山西建设工程协会网站,企业网站推广在哪里办,阿里云域名查询,帝国做企业网站C解析xml示例 1. Xml文档介绍1.1 特点及作用1.2 Xml优点1.2.1 良好的可拓展性1.2.2 内容与形式分离 1.3 Xml组成1.3.1 Xml声明1.3.2 根元素1.3.3 元素1.3.4 属性1.3.5 实体1.3.6 注释 2 C解析Xml2.1 tinyXml2类库2.2 关键接口2.2.1 LoadFile2.2.2 RootElement2.2.3 FirstChildE… C解析xml示例 1. Xml文档介绍1.1 特点及作用1.2 Xml优点1.2.1 良好的可拓展性1.2.2 内容与形式分离 1.3 Xml组成1.3.1 Xml声明1.3.2 根元素1.3.3 元素1.3.4 属性1.3.5 实体1.3.6 注释 2 C解析Xml2.1 tinyXml2类库2.2 关键接口2.2.1 LoadFile2.2.2 RootElement2.2.3 FirstChildElement2.2.4 NextSiblingElement2.2.5 Value2.2.6 Attribute2.2.7 ToDeclaration 3 搜索Xml中数据案例 1. Xml文档介绍
XmlExtensible Markup Language即可扩展标记语言Xml是互联网数据传输的重要工具它可以跨越互联网任何的平台不受编程语言和操作系统的限制可以说它是一个拥有互联网最高级别通行证的数据携带者。
Xml用于标记电子文件使其具有结构性的标记语言可以用来标记数据、定义数据类型是一种允许用户对自己的标记语言进行定义的源语言。Xml是标准通用标记语言SGML的子集非常适合Web传输。Xml提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
在很多工具或服务中需要解析Xml此文档供相关开发人员使用C解析Xml做参考。
1.1 特点及作用
Xml特点
xml与操作系统、编程语言的开发平台都无关实现不同系统之间的数据交互 Xml作用配置应用程序和网站在配置文件里几乎所有的配置文件都是以Xml的格式来编写的数据交互即服务器以XML的形式传输数据储存数据
1.2 Xml优点
1.2.1 良好的可拓展性
在XML产生之前要想定义一个置标语言并推广利用它非常困难。一方面如果制定了一个新的语言而期望它能生效需要把这个标准提交给相关的组织如W3C等待它接受并正式公布这个标准经过几轮的评定和修改到这个置标语言终于成为一个正式推荐标准时可能已经过了几年的时间。另一方面为了让这套标记得到广泛应用制订者必须为它配备浏览工具。这样就不得不去游说各个浏览器厂商接受并支持新制定的标记或者索性自己开发一个新的浏览器去与现有的浏览器竞争无论哪个办法都需要耗费大量的时间和工作。现在借助XML的帮助制定新的置标语言要简单易行得多了这也正是XML的优势所在。
各个不同的行业可能会有一些独特的要求比如说化学家需要化学公式中的一些特殊符号建筑家需要设计图纸中的某些特殊的标记音乐家需要音符这些都需要单独的标记。但是其他网页设计者一般不会用这些记号也不需要这些标记。XML的优点就在于它允许各个组织、个人建立适合他们自己需要的标记库并且这个标记库可以迅速地投入使用。
1.2.2 内容与形式分离
XML不仅允许自定义一套标记而且这些标记不必仅限于对显示格式的描述。在XML中显示样式从数据文档中分离出来放在样式单文件中。这样如果要改动信息的表现方式无须改动信息本身只要改动样式单文件就够了。如果这时候把列表的数据改用表格显示无须再去修改大量数据信息文档因为它们和同一个样式文件相关联只要改动这个样式单文件就可以了。
在XML中数据搜索可以简单高效地进行。 若在HTML文件中搜索某个字符串脚本会逐字寻找对应的字符串即使找到了若存在多个相同目标字符串也不能确定是否为自己想要找到的那个。在XML中搜索不必要再去遍历整个文档只需要找一下相关标记下的内容。此外信息之间的某些复杂关系比如树状结构、继承关系等在XML中也都得到了绝好的体现这样就大大方便了XML的应用处理程序的开发。
1.3 Xml组成
一个正规的Xml文档的结构需要有声明文档元素描述信息有且仅有一个根元素元素属性。也可能包含实体注释等信息。
1.3.1 Xml声明
在编写XML文档时需要先使用文档声明来声明XML文档。且必须出现在文档的第一行。最简单的声明语法
?xml versionxxx?Version后引号内的字符串表示文档的版本。
当我们写好的一个xml文件写入内存的时候会转换为二进制保存这个时候会查码表记事本保存的时候是gbk而保存的时候默认查码表时用的是utf-8这个时候我们就可以用encoding属性默认是UTF-8
?xml versionxxx” encodingGBK?这样就可以解决乱码等问题。
Xml声明还可能包含standlone属性该xml文件是否独立存在。
1.3.2 根元素
根元素是Xml文档里面唯一的它的开始是放在最前面结束是放在最后面。
1.3.3 元素
根元素下的所有元素格式与根元素相同其格式为 Note
所有元素都必须有开始标签和结束标签开始标签和结束标签的名称必须相同区分大小写元素title名称可以包含字母数字或者其他字符但是不能以数字或者符号开头名称中不能包含空格名称字符之间不能使用冒号(有特殊用途)
1.3.4 属性
对于有属性的元素语法结构为
元素名 属性名“属性值”/元素名Note
属性值用双引号包括一个元素可以有多个属性属性值中不能直接包含符号
1.3.5 实体
在xml中一些字符拥有特殊的意义。如果把字符“”放在xml元素中会发生错误这是因为解析器会把它当作新元素的开始这样会产生xml错误。为了避免这个错误在元素中需要引用这些字符时用实体引用来代替字符。Xml中5个预定义实体
实体符号It;*.
1.3.6 注释
注释语法 !—注释内容– Note
注释内容中不要出现“–”注释不能嵌套XML声明之前不能有注释不允许第一行写注释
2 C解析Xml
2.1 tinyXml2类库
在C中读写Xml会用到一个C库tinyXml2类库。这个库中包含了我们读取Xml所需的接口。
TinyXML2是一个开源、简单、小巧、高效的C XML解析器可以轻松集成到其它程序中。目前存在两个著名的开源XML文件解析库tinyXml1tinyXml2。相对tinyXml1而言tinyXml2更为简洁它只有一个tinyXml2.h文件和一个tinyXml2.cpp文件组成而tinyXml1包含了6个文件。
TinyXml2具有以下几个优点
对大部分的C/C项目具有普适性并且拥有丰富的测试案例使用较少的内存约 TinyXML1 的 40%速度变得更快没有C的STL要求更接近现代 C 的特性如使用了适当的命名空间适当有效的处理了的空白字符空格Tab 和回车
使用方法将 tinyxml2.cpp 和 tinyxml2.h 拷贝至项目目录使用时包含头文件和引入名字空间。
2.2 关键接口
2.2.1 LoadFile
作用用于加载Xml文件 传参LoadFileFilePath
一般使用格式
if(Xml.LoadFile(FilePath)!XML_SUCCESS)// 通过Xml文件路径读取文件若读取失败则返回return;2.2.2 RootElement
作用用于读取Xml的根节点 传参RootElement()
一般使用格式
tinyxml2::XMLElement* rootElement NULL;
rootElementXml.RootElement();//rootElement指向当前Xml的根节点
if(rootElementNULL)//若读取失败则返回
return;2.2.3 FirstChildElement
作用用于读取xml节点的下一层节点 传参1FirstChildElement()//读取下一层节点的第一个节点 2FirstChildElement(“XXX”)//读取下一层节点第一个元素名为“XXX”的节点
一般使用格式
const XMLNode* Element1 NULL;
Element1 rootElement- FirstChildElement(“XXX”);//Element1指向rootElement的下一层第一个元素名为”XXX”的节点
if(Element1 NULL)//若读取失败则返回
return;2.2.4 NextSiblingElement
作用用于读取Xml节点同层节点的下一个节点 传参NextSiblingElement()
一般使用格式
const XMLNode* Element2 NULL;
Element2 Element1 - NextSiblingElement ();//Element2指向Element1的同层节点的下一个节点
if(Element2 NULL)//若读取失败则返回
return;2.2.5 Value
作用用于读取Xml节点的元素名 传参Value()
一般使用格式
String str1 Element2-Value();//将Element2的元素名赋值给str12.2.6 Attribute
作用用于读取Xml节点的属性值 传参Attribute()
一般使用格式
String str2 Element2-ToElement()-Attribute(“XXX”);//将Element2的属性名为”XXX”的属性值赋值给str22.2.7 ToDeclaration
作用用于读取Xml文件的声明 传参ToDeclaration()
一般使用格式
tinyxml2::XMLDocument xmlParse;
if (xmlParse.LoadFile(str_xmlPath.c_str()) ! tinyxml2::XML_SUCCESS)return -1;
XMLNode *decl xmlParse.FirstChild();
if(NULL! decl){XMLDeclaration* declaration decl-ToDeclaration();
string strDecl declaration-Value();//最终将声明字符串赋值给strDecl
}3 搜索Xml中数据案例
通常在Xml中搜索数据会有很多限制条件需要通过层层搜索找到想要的数据。 如图中若希望通过限制条件WwanDeviceConfigID-IDFCC_MAP_INDEX_TYPE- ValueStandard- VauleItem- PSensors/ DeviceMode/ AntMode/ AntMode1找到对应的Item –SarIndex代码案例如下是一个对应的从Xml中搜索数据的接口代码部分仅供参考
int CStateWork::GetSarIndexFromXml(string str_xmlPath, string WwanDeviceConfigID, string regmcc, string PSensors, string DeviceMode, string AntMode, string AntMode1)string SarIndex;
do{
1.初始化tinyxml2::XMLDocument xmlParse;tinyxml2::XMLElement* rootElement NULL;const XMLNode* WwanDeviceConfigIDElement NULL;const XMLNode* WwanDeviceConfigIDList NULL;const XMLNode* FCC_MAP_INDEX_TYPE_Element NULL;const XMLNode* MapTypeElement NULL;const XMLNode* StandardElement NULL;const XMLNode* ItemElement NULL;string FCC_MAP_INDEX_TYPE;
int i_ret -1;
2.加载Xml文件并获取根节点if (xmlParse.LoadFile(str_xmlPath.c_str()) ! tinyxml2::XML_SUCCESS){return i_ret;}rootElement xmlParse.RootElement();if (NULL rootElement){return i_ret;}
3.通过传参WwanDeviceConfigID找到对应的WwanDeviceConfigID节点WwanDeviceConfigIDList rootElement-FirstChildElement(WwanDeviceConfigIDList);if (NULL WwanDeviceConfigIDList){return i_ret;}WwanDeviceConfigIDElement WwanDeviceConfigIDList-FirstChildElement(WwanDeviceConfigID);for (WwanDeviceConfigIDElement; WwanDeviceConfigIDElement; WwanDeviceConfigIDElement WwanDeviceConfigIDElement-NextSiblingElement()){if (WwanDeviceConfigIDElement-ToElement()-Attribute(ID) WwanDeviceConfigID)break;}4.在WwanDeviceConfigID节点下找到FCC_MAP_INDEX_TYPE节点的属性值FCC_MAP_INDEX_TYPE_Element WwanDeviceConfigIDElement-FirstChildElement(FCC_MAP_INDEX_TYPE);if (NULL FCC_MAP_INDEX_TYPE_Element){return i_ret;}FCC_MAP_INDEX_TYPE FCC_MAP_INDEX_TYPE_Element-ToElement()-Attribute(Value);5.在WwanDeviceConfigID节点下找到与FCC_MAP_INDEX_TYPE节点的属性值对应的MapTypeMapTypeElement WwanDeviceConfigIDElement-FirstChildElement(FCC_MAP_INDEX_TYPE.c_str());if (NULL MapTypeElement){return i_ret;}6.在MapType节点下找到属性值与传参regmcc对应的Standard节点StandardElement MapTypeElement-FirstChildElement(Standard);if (NULL StandardElement){return i_ret;}for (StandardElement; StandardElement; StandardElement StandardElement-NextSiblingElement()){if (StandardElement-ToElement()-Attribute(Vaule) regmcc)break;}7.在Standard节点下找到属性值与传参PSensorsDeviceModeAntModeAntMode1一一对应的Item节点不同的MapType属性个数不同需要先判断在哪个MapType下搜索ItemElement StandardElement-FirstChildElement(Item);if (NULL ItemElement){return i_ret;}if (FCC_MAP_INDEX_TYPE.find(MapType_1) ! std::string::npos){ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}}else if (FCC_MAP_INDEX_TYPE.find(MapType_2) ! std::string::npos){if (PSensors ){return i_ret;}ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}while (ItemElement-ToElement()-Attribute(PSensors) ! PSensors){ItemElement ItemElement-NextSiblingElement();if (NULL ItemElement){return i_ret;}}}else if (FCC_MAP_INDEX_TYPE.find(MapType_3) ! std::string::npos){if (DeviceMode ){return i_ret;}ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}while (ItemElement-ToElement()-Attribute(DeviceMode) ! DeviceMode){ItemElement ItemElement-NextSiblingElement();if (NULL ItemElement){return i_ret;}}}else if (FCC_MAP_INDEX_TYPE.find(MapType_4) ! std::string::npos){if (PSensors ){return i_ret;}if (DeviceMode ){return i_ret;}ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}while (ItemElement-ToElement()-Attribute(PSensors) ! PSensors|| ItemElement-ToElement()-Attribute(DeviceMode) ! DeviceMode){ItemElement ItemElement-NextSiblingElement();if (NULL ItemElement){return i_ret;}}}else if (FCC_MAP_INDEX_TYPE.find(MapType_5) ! std::string::npos){if (PSensors ){return i_ret;}if (AntMode ){ return i_ret;}if (AntMode1 ){return i_ret;}ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}while (ItemElement-ToElement()-Attribute(PSensors) ! PSensors|| ItemElement-ToElement()-Attribute(AntMode) ! AntMode|| ItemElement-ToElement()-Attribute(AntMode1) ! AntMode1){ItemElement ItemElement-NextSiblingElement();if (NULL ItemElement){return i_ret;}}}else if (FCC_MAP_INDEX_TYPE.find(MapType_6) ! std::string::npos){if (PSensors ){return i_ret;}if (AntMode ){return i_ret;}if (AntMode1 ){return i_ret;}if (DeviceMode ){return i_ret;}ItemElement StandardElement-FirstChildElement();if (NULL ItemElement){return i_ret;}while (ItemElement-ToElement()-Attribute(PSensors) ! PSensors|| ItemElement-ToElement()-Attribute(AntMode) ! AntMode|| ItemElement-ToElement()-Attribute(AntMode1) ! AntMode1|| ItemElement-ToElement()-Attribute(DeviceMode) ! DeviceMode){ItemElement ItemElement-NextSiblingElement();if (NULL ItemElement){return i_ret;}}}8.在Item节点下读出SarIndex属性值并作为最终接口的输出SarIndex ItemElement-ToElement()-Attribute(SarIndex);} while (FALSE);return atoi(SarIndex.c_str());
}Note
在LoadFile Xml文件时应该判断是否成功打开若失败则返回在获取任何新的节点以及节点指向的位置变动后应该判断当前节点是否为空若为空则应该返回或做其他异常处理当前节点往下向子节点搜寻一般直接用FirstChild函数直接实现当前节点往下向同级节点搜寻一般用NextSiblingElement函数遍历实现在同一个元素中可能会有多组属性和属性值在这种情况下搜索相应的数据一般需要用循环对于每一次循环都是获取一次新的节点因此在循环前和每一次循环后都应该判断当前节点是否为空以免出现crash