整理代码
This commit is contained in:
commit
c7b4e178ec
364 changed files with 59691 additions and 0 deletions
371
util/xpack/xml_encoder.h
Executable file
371
util/xpack/xml_encoder.h
Executable file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_XML_ENCODER_H
|
||||
#define __X_PACK_XML_ENCODER_H
|
||||
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include "xencoder.h"
|
||||
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class XmlWriter {
|
||||
struct Attr {
|
||||
const char* key;
|
||||
std::string val;
|
||||
Attr(const char*_key, const std::string&_val):key(_key), val(_val){}
|
||||
};
|
||||
struct Node {
|
||||
Node(const char*_key=NULL, const Extend *ext=NULL) {
|
||||
(void)ext;
|
||||
if (_key != NULL) {
|
||||
key = _key;
|
||||
}
|
||||
}
|
||||
~Node() {
|
||||
std::list<Node*>::iterator it;
|
||||
for (it = childs.begin(); it!=childs.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
std::string key; // key for this node
|
||||
std::string val; // value for this node, only for leaf node
|
||||
std::list<Attr> attrs; // attribute
|
||||
std::list<Node*> childs;// child nodes
|
||||
|
||||
std::string vec_key; // key for vector
|
||||
};
|
||||
|
||||
friend class XEncoder<XmlWriter>;
|
||||
friend class XmlEncoder;
|
||||
const static bool support_null = false;
|
||||
public:
|
||||
XmlWriter(int indentCount = -1, char indentChar = ' ', int decimalPlaces = 324):_indentCount(indentCount),_indentChar(indentChar),_decimalPlaces(decimalPlaces) {
|
||||
if (_indentCount > 0) {
|
||||
if (_indentChar!=' ' && _indentChar!='\t') {
|
||||
throw std::runtime_error("indentChar must be space or tab");
|
||||
}
|
||||
}
|
||||
_cur = &_root;
|
||||
}
|
||||
private:
|
||||
std::string String() {
|
||||
merge();
|
||||
return _output;
|
||||
}
|
||||
inline static const char *Name() {
|
||||
return "xml";
|
||||
}
|
||||
inline const char *IndexKey(size_t index) {
|
||||
(void)index;
|
||||
return _cur->vec_key.c_str();
|
||||
}
|
||||
void ArrayBegin(const char *key, const Extend *ext) {
|
||||
Node *n = new Node(key, ext);
|
||||
|
||||
if (NULL!=_cur && !_cur->vec_key.empty()) { // vector<vector<...>>
|
||||
n->vec_key = n->key;
|
||||
} else if (NULL != ext && NULL != ext->alias) {
|
||||
if (!ext->alias->Flag("xml", "vl", &n->vec_key)) { // forward compatible, support vector label
|
||||
if (ext->alias->Flag("xml", "sbs")) { // no top label, vector item will side by side
|
||||
n->vec_key.swap(n->key); // n->vec_key=key and n->key="";
|
||||
} else {
|
||||
n->vec_key = n->key; // has top level
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n->vec_key = n->key;
|
||||
}
|
||||
|
||||
_cur->childs.push_back(n);
|
||||
|
||||
_stack.push_back(_cur);
|
||||
_cur = n;
|
||||
}
|
||||
void ArrayEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
_cur = _stack.back();
|
||||
_stack.pop_back();
|
||||
}
|
||||
void ObjectBegin(const char *key, const Extend *ext) {
|
||||
Node *n = new Node(key, ext);
|
||||
_cur->childs.push_back(n);
|
||||
|
||||
_stack.push_back(_cur);
|
||||
_cur = n;
|
||||
}
|
||||
void ObjectEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
_cur = _stack.back();
|
||||
_stack.pop_back();
|
||||
}
|
||||
bool WriteNull(const char*key, const Extend *ext) {
|
||||
static std::string empty;
|
||||
return this->encode_string(key, empty, ext);
|
||||
}
|
||||
// string
|
||||
bool encode_string(const char*key, const std::string &val, const Extend *ext) {
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, string_quote(val)));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = val;
|
||||
} else if (!Extend::AliasFlag(ext, "xml", "cdata")) {
|
||||
Node *n = new Node(key);
|
||||
n->val = string_quote(val);
|
||||
_cur->childs.push_back(n);
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = "<![CDATA[" + val + "]]>";
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// bool
|
||||
bool encode_bool(const char*key, const bool &val, const Extend *ext) {
|
||||
std::string bval;
|
||||
if (val) {
|
||||
bval = "true";
|
||||
} else {
|
||||
bval = "false";
|
||||
}
|
||||
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, bval));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = bval;
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = bval;
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// integer
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type encode_number(const char*key, const T& val, const Extend *ext) {
|
||||
if (val==0 && Extend::OmitEmpty(ext)) {
|
||||
return false;
|
||||
} else if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, Util::itoa(val)));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = Util::itoa(val);
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = Util::itoa(val);
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// float
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type encode_number(const char*key, const T &val, const Extend *ext) {
|
||||
if (val==0 && Extend::OmitEmpty(ext)) {
|
||||
return false;
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
os.precision(_decimalPlaces+1);
|
||||
os<<val;
|
||||
std::string fval = os.str();
|
||||
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, fval));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = fval;
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = fval;
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// escape string
|
||||
static std::string string_quote(const std::string &val) {
|
||||
std::string ret;
|
||||
ret.reserve(val.length()*2);
|
||||
|
||||
for (size_t i=0; i<val.length(); ++i) {
|
||||
int c = (int)(val[i]) & 0xFF;
|
||||
switch (c) {
|
||||
case '<':
|
||||
ret += "<";
|
||||
break;
|
||||
case '>':
|
||||
ret += ">";
|
||||
break;
|
||||
case '&':
|
||||
ret += "&";
|
||||
break;
|
||||
case '\'':
|
||||
ret += "'";
|
||||
break;
|
||||
case '\"':
|
||||
ret += """;
|
||||
break;
|
||||
default:
|
||||
if(c >= ' ') {
|
||||
ret.push_back(val[i]);
|
||||
} else {
|
||||
ret += "\\x";
|
||||
unsigned char uch = (unsigned char)val[i];
|
||||
unsigned char h = (uch>>4)&0xf;
|
||||
unsigned char l = uch&0xf;
|
||||
if (h < 10) {
|
||||
ret.push_back(h+'0');
|
||||
} else {
|
||||
ret.push_back(h-10+'A');
|
||||
}
|
||||
if (l < 10) {
|
||||
ret.push_back(l+'0');
|
||||
} else {
|
||||
ret.push_back(l-10+'A');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void appendNode(const Node *nd, int depth) {
|
||||
bool indentEnd = true;
|
||||
|
||||
if (!nd->key.empty()) { // for array that without label
|
||||
indent(depth);
|
||||
_output.push_back('<');
|
||||
_output += nd->key;
|
||||
} else if (depth > 0) {
|
||||
depth--;
|
||||
}
|
||||
|
||||
// output attribute
|
||||
std::list<Attr>::const_iterator it;
|
||||
for (it=nd->attrs.begin(); it!=nd->attrs.end(); ++it) {
|
||||
_output.push_back(' ');
|
||||
_output += it->key;
|
||||
_output += "=\"";
|
||||
_output += it->val;
|
||||
_output.push_back('"');
|
||||
}
|
||||
|
||||
// no content, end object
|
||||
if (nd->val.empty() && nd->childs.size()==0) {
|
||||
if (!nd->key.empty()) {
|
||||
_output += "/>";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// key finished
|
||||
if (!nd->key.empty()) {
|
||||
_output.push_back('>');
|
||||
}
|
||||
if (!nd->val.empty()) {
|
||||
_output += nd->val;
|
||||
indentEnd = false;
|
||||
} else {
|
||||
std::list<Node*>::const_iterator it;
|
||||
for (it=nd->childs.begin(); it!=nd->childs.end(); ++it) {
|
||||
appendNode(*it, depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nd->key.empty()) {
|
||||
if (indentEnd) {
|
||||
indent(depth);
|
||||
}
|
||||
_output += "</";
|
||||
_output += nd->key;
|
||||
_output.push_back('>');
|
||||
}
|
||||
}
|
||||
void merge() {
|
||||
if (_output.length() > 0 || _root.childs.size()==0) {
|
||||
return;
|
||||
}
|
||||
|
||||
appendNode(_root.childs.front(), 0);
|
||||
}
|
||||
|
||||
void indent(int depth) {
|
||||
if (_indentCount < 0) {
|
||||
return;
|
||||
}
|
||||
_output.push_back('\n');
|
||||
if (_indentCount == 0) {
|
||||
return;
|
||||
}
|
||||
for (int i=0; i<depth*_indentCount; ++i) {
|
||||
_output.push_back(_indentChar);
|
||||
}
|
||||
}
|
||||
|
||||
Node _root;
|
||||
Node *_cur;
|
||||
std::list<Node*> _stack;
|
||||
|
||||
std::string _output;
|
||||
|
||||
int _indentCount;
|
||||
char _indentChar;
|
||||
|
||||
int _decimalPlaces;
|
||||
};
|
||||
|
||||
|
||||
class XmlEncoder {
|
||||
public:
|
||||
XmlEncoder() {
|
||||
indentCount = -1;
|
||||
indentChar = ' ';
|
||||
maxDecimalPlaces = 324;
|
||||
}
|
||||
XmlEncoder(int _indentCount, char _indentChar, int _maxDecimalPlaces = 324) { // compat
|
||||
indentCount = _indentCount;
|
||||
indentChar = _indentChar;
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
void SetMaxDecimalPlaces(int _maxDecimalPlaces) {
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode(const T&val, const std::string&root) {
|
||||
XmlWriter wr(indentCount, indentChar, maxDecimalPlaces);
|
||||
XEncoder<XmlWriter> en(wr);
|
||||
en.encode(root.c_str(), val, NULL);
|
||||
return wr.String();
|
||||
}
|
||||
|
||||
private:
|
||||
int indentCount;
|
||||
char indentChar;
|
||||
int maxDecimalPlaces;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue