簡述
與XML文件生成C++代碼(基於pugixml)中的功能一致,只是這里改用的rapidxml來實現。就不多說了,直接放代碼。
代碼
#include "rapidxml-1.13/rapidxml.hpp"
#include "rapidxml-1.13/rapidxml_utils.hpp"
#include "rapidxml-1.13/rapidxml_iterators.hpp"
#include "rapidxml-1.13/rapidxml_print.hpp"
#include <algorithm>
#include <cstdio>
// XML節點名稱中可以包含C++變量名不支持的字符
// 需要將其規范化,使之能夠正常作為C++變量名
std::string normalVarName(std::string s)
{
// XML 元素必須遵循以下命名規則:
// 名稱可以含字母、數字以及其他的字符
// 名稱不能以數字或者標點符號開始
// 名稱不能以字符 “xml”(或者 XML、Xml)開始
// 名稱不能包含空格
// 可使用任何名稱,沒有保留的字詞。
// 如果只需要C++編譯通過,完全可以將s轉換為base16表示的字符串即可
// 這里我只對 : . , ; 做一下處理,其它的就先不管了
for(std::size_t pos = s.find_first_of(":.,;");
pos != std::string::npos; pos = s.find_first_of(":.,;",pos+1)){
s[pos] = '_';
}
return s;
}
// 對於節點的值,它有可能包含需要轉義的字符,需要進行轉義(未考慮C++原始字面常量)
std::string toEscape(const std::string& s)
{
std::string s2;
s2.reserve(s.size());
for(std::size_t i=0;i<s.size();++i){
switch (s[i]) {
case '"':
case '\\':
s2.push_back('\\');
break;
default:
break;
}
s2.push_back(s[i]);
}
return s2;
}
bool TraversalXml(rapidxml::xml_node<char>& node,int level = 0)
{
std::string s(level*4,32);
if(level == 0){ /*表明是root節點*/
puts("rapidxml::xml_document<char> xmldocObject;\n"
"rapidxml::xml_document<char>* xmldoc = &xmldocObject;\n"
"{\n"
" rapidxml::xml_node<char>* decl = \n"
" xmldoc->allocate_node(rapidxml::node_pi,\n"
" xmldoc->allocate_string(\"xml version='1.0' encoding='utf-8'\"));\n"
" xmldoc->append_node(decl);\n"
"}");
puts("{");
}
// 獲取節點名稱
std::string nodeName(node.name(),node.name_size());
std::string nodeValue(node.value(),node.value_size());
std::string parentName;
if(node.parent() == NULL || node.parent()->name_size() == 0){
parentName = "xmldoc";
} else {
parentName = std::string(node.parent()->name(),node.parent()->name_size());;
}
// pugixml這里有點問題,不知道是不是bug(我對XML規范和pugixml都不是很熟)
// 一個節點A沒有子節點的時候,它也能獲取到它的一個子節點,這個子節點的name是
// 空的,value與節點A相同,其它的屬性信息也是沒有的。
// 所以在這里一些地方寫的會比較別扭
// 這里使用rapidxml的時候也有這個問題,所以我覺得可能是對於沒有子節點的的節點
// 它的值就是它的子節點吧。這只是我的猜想,並未查閱相關規范。
if(!nodeName.empty()){
printf("%s{/*add %s*/\n",s.c_str(),nodeName.c_str());
// 輸出添加子節點代碼
if(nodeValue.empty()){
printf("%s rapidxml::xml_node<char>* %s = xmldoc->allocate_node(\n"
"%s rapidxml::node_element,\"%s\",NULL);\n",
s.c_str(),normalVarName(nodeName).c_str(),
s.c_str(),nodeName.c_str());
}else{
printf("%s rapidxml::xml_node<char>* %s = xmldoc->allocate_node(\n"
"%s rapidxml::node_element,\"%s\",\"%s\");\n",
s.c_str(),normalVarName(nodeName).c_str(),
s.c_str(),nodeName.c_str(),toEscape(nodeValue).c_str());
}
// 輸出添加子節點到父節點代碼
printf("%s %s->append_node(%s);\n",
s.c_str(),normalVarName(parentName).c_str(),
normalVarName(nodeName).c_str());
// 逐個輸出屬性信息添加代碼
for(rapidxml::xml_attribute<char>* attr = node.first_attribute();
attr != NULL; attr = attr->next_attribute()){
// 輸出屬性信息添加代碼
printf("%s %s->append_attribute(\n"
"%s xmldoc->allocate_attribute(\"%s\",\"%s\"));\n",
s.c_str(),normalVarName(nodeName).c_str(),
s.c_str(),attr->name(),attr->value());
}
}
// 遍歷子節點
for(rapidxml::xml_node<char>* subnode = node.first_node();
subnode != NULL;subnode = subnode->next_sibling()){
TraversalXml(*subnode,level+1);
}
// 與前面匹配
if(!nodeName.empty()){
printf("%s}/*end %s*/\n\n",s.c_str(),nodeName.c_str());
}
// 與前面匹配
if(level == 0){
puts("}");
}
return true;
}
int main(int argc,char** argv)
{
if(argc != 2){
puts("Usage:....");
return 0;
}
try{
rapidxml::file<char> xmlfile(argv[1]);
rapidxml::xml_document<char> doc;
doc.parse<0>(xmlfile.data());
TraversalXml(doc);
}
catch(std::exception& e){
puts(e.what());
}
return 0;
}