简述

在一个项目中需要用到XML的解析和生成,知乎上有人推荐rapidxmlpugixml等库。RapidXML一看库还比较大,就先研究一下pugixml了。

因为对解析XML的需求不大(都是一些很小的XML文本),但是对生成XML有较大的需求,且这些XML文本都很大,所以先写了一个根据XML文件生成对应的C++代码的项目。

对XML的规范并不熟悉,所以这里只做了读取节点属性节点值生成对应代码的操作,对于其它的部分,我也不知道还有哪里需要做的。

这里没有考虑非UTF-8编码和宽字符的情况,我这里暂时用不上,需要的可以根据自己的情况改。

不知道是不是pugixml的bug,对于一个没有子节点的节点,也能获取其一个无名子节点

示例

假设有如下内容的XML文件

<?xml version="1.0" encoding="utf-8" ?>
<EnvelopeN xsi:type='typens:EnvelopeN' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:typens='http://www.esri.com/schemas/ArcGIS/10.1'>
<XMin>-180</XMin>
<YMin>-90</YMin>
<XMax>180</XMax>
<YMax>90</YMax>
<SpatialReference xsi:type='typens:GeographicCoordinateSystem'>
<WKT>GEOGCS[&quot;GCS_WGS_1984&quot;,DATUM[&quot;D_WGS_1984&quot;,SPHEROID[&quot;WGS_1984&quot;,6378137.0,298.257223563]],PRIMEM[&quot;Greenwich&quot;,0.0],UNIT[&quot;Degree&quot;,0.0174532925199433],AUTHORITY[&quot;EPSG&quot;,4326]]</WKT>
<XOrigin>-400</XOrigin>
<YOrigin>-400</YOrigin>
<XYScale>11258999068426.238</XYScale>
<ZOrigin>-100000</ZOrigin>
<ZScale>10000</ZScale>
<MOrigin>-100000</MOrigin>
<MScale>10000</MScale>
<XYTolerance>8.983152841195215e-009</XYTolerance>
<ZTolerance>0.001</ZTolerance>
<MTolerance>0.001</MTolerance>
<HighPrecision>true</HighPrecision>
<LeftLongitude>-180</LeftLongitude>
<WKID>4326</WKID>
<LatestWKID>4326</LatestWKID>
</SpatialReference>
</EnvelopeN>

那么生成的代码如下

pugi::xml_document xmldoc;
{
pugi::xml_node decl = xmldoc.append_child(pugi::node_declaration);
decl.append_attribute("version") = "1.0";
decl.append_attribute("encoding") = "utf-8";
}
{
{/*add EnvelopeN*/
pugi::xml_node EnvelopeN = xmldoc.append_child("EnvelopeN");
EnvelopeN.append_attribute("xsi:type")="typens:EnvelopeN";
EnvelopeN.append_attribute("xmlns:xsi")="http://www.w3.org/2001/XMLSchema-instance";
EnvelopeN.append_attribute("xmlns:xs")="http://www.w3.org/2001/XMLSchema";
EnvelopeN.append_attribute("xmlns:typens")="http://www.esri.com/schemas/ArcGIS/10.1";
{/*add XMin*/
pugi::xml_node XMin = EnvelopeN.append_child("XMin");
XMin.text().set("-180");
}/*end XMin*/ {/*add YMin*/
pugi::xml_node YMin = EnvelopeN.append_child("YMin");
YMin.text().set("-90");
}/*end YMin*/ {/*add XMax*/
pugi::xml_node XMax = EnvelopeN.append_child("XMax");
XMax.text().set("180");
}/*end XMax*/ {/*add YMax*/
pugi::xml_node YMax = EnvelopeN.append_child("YMax");
YMax.text().set("90");
}/*end YMax*/ {/*add SpatialReference*/
pugi::xml_node SpatialReference = EnvelopeN.append_child("SpatialReference");
SpatialReference.append_attribute("xsi:type")="typens:GeographicCoordinateSystem";
{/*add WKT*/
pugi::xml_node WKT = SpatialReference.append_child("WKT");
WKT.text().set("GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433],AUTHORITY[\"EPSG\",4326]]");
}/*end WKT*/ {/*add XOrigin*/
pugi::xml_node XOrigin = SpatialReference.append_child("XOrigin");
XOrigin.text().set("-400");
}/*end XOrigin*/ {/*add YOrigin*/
pugi::xml_node YOrigin = SpatialReference.append_child("YOrigin");
YOrigin.text().set("-400");
}/*end YOrigin*/ {/*add XYScale*/
pugi::xml_node XYScale = SpatialReference.append_child("XYScale");
XYScale.text().set("11258999068426.238");
}/*end XYScale*/ {/*add ZOrigin*/
pugi::xml_node ZOrigin = SpatialReference.append_child("ZOrigin");
ZOrigin.text().set("-100000");
}/*end ZOrigin*/ {/*add ZScale*/
pugi::xml_node ZScale = SpatialReference.append_child("ZScale");
ZScale.text().set("10000");
}/*end ZScale*/ {/*add MOrigin*/
pugi::xml_node MOrigin = SpatialReference.append_child("MOrigin");
MOrigin.text().set("-100000");
}/*end MOrigin*/ {/*add MScale*/
pugi::xml_node MScale = SpatialReference.append_child("MScale");
MScale.text().set("10000");
}/*end MScale*/ {/*add XYTolerance*/
pugi::xml_node XYTolerance = SpatialReference.append_child("XYTolerance");
XYTolerance.text().set("8.983152841195215e-009");
}/*end XYTolerance*/ {/*add ZTolerance*/
pugi::xml_node ZTolerance = SpatialReference.append_child("ZTolerance");
ZTolerance.text().set("0.001");
}/*end ZTolerance*/ {/*add MTolerance*/
pugi::xml_node MTolerance = SpatialReference.append_child("MTolerance");
MTolerance.text().set("0.001");
}/*end MTolerance*/ {/*add HighPrecision*/
pugi::xml_node HighPrecision = SpatialReference.append_child("HighPrecision");
HighPrecision.text().set("true");
}/*end HighPrecision*/ {/*add LeftLongitude*/
pugi::xml_node LeftLongitude = SpatialReference.append_child("LeftLongitude");
LeftLongitude.text().set("-180");
}/*end LeftLongitude*/ {/*add WKID*/
pugi::xml_node WKID = SpatialReference.append_child("WKID");
WKID.text().set("4326");
}/*end WKID*/ {/*add LatestWKID*/
pugi::xml_node LatestWKID = SpatialReference.append_child("LatestWKID");
LatestWKID.text().set("4326");
}/*end LatestWKID*/ }/*end SpatialReference*/ }/*end EnvelopeN*/ }

关键代码

这里贴出关键部分代码

// 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(pugi::xml_node& node,int level = 0)
{
if(!node){return true;}
std::string s(level*4,32); if(node.root() == node){
puts("pugi::xml_document xmldoc;\n"
"{\n"
" pugi::xml_node decl = xmldoc.append_child(pugi::node_declaration);\n"
" decl.append_attribute(\"version\") = \"1.0\";\n"
" decl.append_attribute(\"encoding\") = \"utf-8\";\n"
"}");
}
if(node == node.root()){
puts("{");
}
// 获取节点名称
std::string nodeName = node.name();
// pugixml这里有点问题,不知道是不是bug(我对XML规范和pugixml都不是很熟)
// 一个节点A没有子节点的时候,它也能获取到它的一个子节点,这个子节点的name是
// 空的,value与节点A相同,其它的属性信息也是没有的。
// 所以在这里一些地方写的会比较别扭 if(!nodeName.empty()){
printf("%s{/*add %s*/\n",s.c_str(),nodeName.c_str()); // 获取父节点名称
std::string parentName = node.parent() == node.root()?
"xmldoc":node.parent().name();
// 输出添加子节点代码
printf("%s pugi::xml_node %s = %s.append_child(\"%s\");\n",
s.c_str(),normalVarName(nodeName).c_str(),
normalVarName(parentName).c_str(),nodeName.c_str()); // 逐个输出属性信息添加代码
for(pugi::xml_node::attribute_iterator iter = node.attributes_begin();
iter != node.attributes_end(); ++iter){
// 输出属性信息添加代码
printf("%s %s.append_attribute(\"%s\")=\"%s\";\n",
s.c_str(),normalVarName(nodeName).c_str(),
iter->name(),iter->value());
}
// 如果节点的值为空,则不输出节点的值了(例如有子节点的情况下,节点的值为空)
if(!node.text().empty()){
// 输出设置节点值代码
printf("%s %s.text().set(\"%s\");\n",
s.c_str(),normalVarName(nodeName).c_str(),
toEscape(node.text().as_string()).c_str());
}
}
// 遍历子节点
for(pugi::xml_node subnode = node.first_child();
subnode;subnode = subnode.next_sibling()){
TraversalXml(subnode,level+1);
}
// 与前面匹配
if(!nodeName.empty()){
printf("%s}/*end %s*/\n\n",s.c_str(),nodeName.c_str());
}
// 与前面匹配
if(node == node.root()){
puts("}");
}
return true;
}

完整代码可在这里下载

https://files.cnblogs.com/files/oloroso/XmlGenCppCode.zip

XML文件生成C++代码(基于pugixml)的更多相关文章

  1. XML文件生成C++代码(基于rapidxml)

    简述 与XML文件生成C++代码(基于pugixml)中的功能一致,只是这里改用的rapidxml来实现.就不多说了,直接放代码. 代码 #include "rapidxml-1.13/ra ...

  2. 使用XML文件和Java代码控制UI界面

    Android推荐使用XML文件设置UI界面,然后用Java代码控制逻辑部分,这体现了MVC思想. MVC全名是Model View Controller,是模型(model)-视图(view)-控制 ...

  3. Android color(颜色) 在XML文件和java代码中

    Android color(颜色) 在XML文件和java代码中,有需要的朋友可以参考下. 1.使用Color类的常量,如: int color = Color.BLUE;//创建一个蓝色 是使用An ...

  4. 根据xml文件生成javaBean

    原 根据xml文件生成javaBean 2017年08月15日 18:32:26 吃完喝完嚼益达 阅读数 1727 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出 ...

  5. eclips运行generatorConfig.xml文件生成代码

    描述: 如何通过eclips工具来运行 generatorConfig.xml 文件来自动生成代码并获取数据(类似于mybaits逆向生成)? mybatis-generator:generate 2 ...

  6. WebAPI使用多个xml文件生成帮助文档

    一.前言 上篇有提到在WebAPI项目内,通过在Nuget里安装(Microsoft.AspNet.WebApi.HelpPage)可以根据注释生成帮助文档,查看代码实现会发现是基于解析项目生成的xm ...

  7. WebAPI使用多个xml文件生成帮助文档(转)

    http://www.cnblogs.com/idoudou/p/xmldocumentation-for-web-api-include-documentation-from-beyond-the- ...

  8. Android(java)学习笔记185:xml文件生成

    1.xml文件: 用元素描述数据,跨平台. 2.利用传统的方式创建xml文件,下面是一个案例: 设计思路:建立一个学生管理系统,创建xml文件保存学生信息: (1)首先是布局文件activity_ma ...

  9. 【转】WebAPI使用多个xml文件生成帮助文档

    来自:http://www.it165.net/pro/html/201505/42504.html 一.前言 上篇有提到在WebAPI项目内,通过在Nuget里安装(Microsoft.AspNet ...

随机推荐

  1. 安装chrome

    安装chrome 在suse12中安装chrome时,提示 lsb >= 4.0 is needed by google-chrome-stable 到http://rpm.pbone.net当 ...

  2. CentOS下httpd下php 连接mysql 本机可以,外网报错Could not connect: Can't connect to MySQL server on '127.0.0.1' (13)2003 原因解析

    php代码很简单: $server="127.0.0.1"; println("Begin"); $link = mysql_connect($server,& ...

  3. android自定义风格的toast

    先上图看一下我的自定义toast的样式 源码下载地址: CustomToastActivity.java源码 package com.jinhoward.ui_customtoast; /** * A ...

  4. 使用MDS Switch基本命令的一个例子

    笔者有幸摆弄一套vBlock的环境, 刚刚接手, 对其上的很多配置都不了解. 下面我们就例举一下我们通过运行哪些命令来搞清楚我们的UCS是如何连接到VNX storage array上的. 首先, 通 ...

  5. Android -- java代码设置margin

    我们平常可以直接在xml里设置margin,如: <ImageView android:layout_margin="5dip" android:src="@dra ...

  6. 3d打印机的软件系统组成部分

    主要由计算机.应用软件.底层控制软件和接口驱动单元组成1)计算机一般采用上位机和下位机两级控制.其中上位主控机一般采用配置高.运行速度快的PC机:下位机采用嵌入式系统DSP,驱动执行机构.上位机和下位 ...

  7. 【矩阵乘】【DP】【codevs 1305】Freda的道路

    1305 Freda的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级: 大师 Master 题目描写叙述 Description Freda要到Rainbow的城堡去玩了. 我们能 ...

  8. 【python】安装bcoding

    C:\Users\horn1>pip install bcodingCollecting bcoding Downloading https://files.pythonhosted.org/p ...

  9. 《python源代码剖析》笔记 python中的List对象

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.PyListObject对象 --> 变长可变对象,可看作vector<Py ...

  10. android中Snackbar(Design Support)的使用

    Snackbar是Android Design Support Library中的一个组件,想使用Snackbar,必须先引入Design Support,我这里引入的是当前的最新版本: implem ...