XML文件生成C++代码(基于pugixml)
简述
在一个项目中需要用到XML的解析和生成,知乎上有人推荐rapidxml和pugixml等库。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["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]]</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)的更多相关文章
- XML文件生成C++代码(基于rapidxml)
		
简述 与XML文件生成C++代码(基于pugixml)中的功能一致,只是这里改用的rapidxml来实现.就不多说了,直接放代码. 代码 #include "rapidxml-1.13/ra ...
 - 使用XML文件和Java代码控制UI界面
		
Android推荐使用XML文件设置UI界面,然后用Java代码控制逻辑部分,这体现了MVC思想. MVC全名是Model View Controller,是模型(model)-视图(view)-控制 ...
 - Android color(颜色) 在XML文件和java代码中
		
Android color(颜色) 在XML文件和java代码中,有需要的朋友可以参考下. 1.使用Color类的常量,如: int color = Color.BLUE;//创建一个蓝色 是使用An ...
 - 根据xml文件生成javaBean
		
原 根据xml文件生成javaBean 2017年08月15日 18:32:26 吃完喝完嚼益达 阅读数 1727 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出 ...
 - eclips运行generatorConfig.xml文件生成代码
		
描述: 如何通过eclips工具来运行 generatorConfig.xml 文件来自动生成代码并获取数据(类似于mybaits逆向生成)? mybatis-generator:generate 2 ...
 - WebAPI使用多个xml文件生成帮助文档
		
一.前言 上篇有提到在WebAPI项目内,通过在Nuget里安装(Microsoft.AspNet.WebApi.HelpPage)可以根据注释生成帮助文档,查看代码实现会发现是基于解析项目生成的xm ...
 - WebAPI使用多个xml文件生成帮助文档(转)
		
http://www.cnblogs.com/idoudou/p/xmldocumentation-for-web-api-include-documentation-from-beyond-the- ...
 - Android(java)学习笔记185:xml文件生成
		
1.xml文件: 用元素描述数据,跨平台. 2.利用传统的方式创建xml文件,下面是一个案例: 设计思路:建立一个学生管理系统,创建xml文件保存学生信息: (1)首先是布局文件activity_ma ...
 - 【转】WebAPI使用多个xml文件生成帮助文档
		
来自:http://www.it165.net/pro/html/201505/42504.html 一.前言 上篇有提到在WebAPI项目内,通过在Nuget里安装(Microsoft.AspNet ...
 
随机推荐
- python读取yaml配置文件
			
支持多种语言:python.js.golang.java.c.c++ YAML 语言(发音 /ˈjæməl/ )的设计目标,就是方便人类读写.它实质上是一种通用的数据串行化格式. 它的基本语法规则如下 ...
 - org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.xugao.bean.MemberLevel.memberpointrate
			
由于数据不合法的原因,好几次遇到: org.hibernate.PropertyAccessException: Null value was assigned to a property of pr ...
 - 日历控件My97DatePicker  WdatePicker屏蔽 onchange的解决方法
			
http://www.cnblogs.com/wan-feng/archive/2013/12/13/3473439.html 受下面文章的启发,使用DatePicker自带的年月日相关的change ...
 - Java hashCode() 和 equals()的若干问题解答<转载自skywang12345>
			
第1部分 equals() 的作用equals()的作用是用来判断两个对象是否相等.equals()定义在JDK的Object类中.通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否 ...
 - .Net-using-Class:MemoryCache 类
			
ylbtech-.Net-using-Class:MemoryCache 类 初始化 System.Runtime.Caching.MemoryCache 类的新实例. 1. 程序集 System.R ...
 - ProDinner
			
ylbtech-dbs:ProDinner A, 数据库关系图 返回顶部 4, 点餐关系图 3, 留言图 1, 用户角色关系图 0, B,SQL脚本返回顶部 2, use master go --ki ...
 - AS 阿里巴巴Java开发规约 CheckStyle-IDEA
			
Alibaba Java Coding Guidelines 简介 github地址:https://github.com/alibaba/p3c 官方文档 阿里巴巴Java开发手册(纪念版) ...
 - JQuery实现密码有短暂的显示过程和实现 input hint效果
			
目录: 一.实现目的 二.问题思考 三.解决办法 1.输入用户名 2.输入密码短暂显示 一.实现目的 这几天做项目的时候,客户要求在文本框输入密码的时候,要求密码有短暂的显示过程,如下图: 二.问题思 ...
 - C++类中的访问权限问题
			
纠结的东西: private,public,protected方法的访问范围.(public继承下)private: 只能由该类中的函数.其友元函数访问,不能被任何其他访问,该类的对象也不能访问. p ...
 - 【ElasticSearch】ES5新特性-keyword-text类型-查询区别
			
ES5新特性-keyword-text类型-查询区别 elasticsearch-head Elasticsearch-sql client junneyang (JunneYang) es keyw ...