简述

在一个项目中需要用到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. Chapter 7 -- Functional

    Caveats 说明 As of Java 7, functional programming in Java can only be approximated through awkward and ...

  2. HotSpot Generations

    本文主要介绍HotSpot JVM的 Generations 机制, 原文来自 Oracle 文档  Java SE 6 HotSpot[tm] Virtual Machine Garbage Col ...

  3. go语言之进阶篇方法的重写

    1.方法的重写 示例: //Person类型,实现了一个方法 func (tmp *Person) PrintInfo() { fmt.Printf("name=%s, sex=%c, ag ...

  4. 如何远程运行PowerShell命令?

    首先, 被remote运行PowerShell的windows必须已经join了domain. 其次, 该Windows的PowerShell必须开启对remote command的接受, 运行下面的 ...

  5. Rotate Image leetcode java

    题目: You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwis ...

  6. 【google面试题】求1到n的正数中1出现的次数的两种思路及其复杂度分析

    问题描写叙述: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.比如输入12,从1到12这些整数中包括1 的数字有1.10.11和12.1一共出现了5次. 这是一道广为流传的googl ...

  7. mono touch登录设计

    需要对MonoTouch.Dialog-1进行引用: using System; using System.Collections.Generic; using System.Linq; using ...

  8. Tensorflow动态seq2seq使用总结(r1.3)

    https://www.jianshu.com/p/c0c5f1bdbb88 动机 其实差不多半年之前就想吐槽Tensorflow的seq2seq了(后面博主去干了些别的事情),官方的代码已经抛弃原来 ...

  9. VMware中让虚拟机支持虚拟化

    一.问题 由于需要玩一下OpenNebula,但是现在自己只有一台笔记本,如何玩?当然是VMVare了,于是装了几台Ubuntu的虚拟机,但是在看安装OpenNebula的前提要求是 安装的主机cpu ...

  10. ASP入门(十八)-访问Access中的数据库

    Northwind 数据库 这是一个微软为软件的使用者提供的一个练习用的数据库,它模拟了一个商贸公司日常业务流程所需要的一些数据. 并且网络上大部分的 SQL 语句的讲解都是以这个数据库为例子讲解的. ...