Xml(Extensible Markup Language)即可扩展标记语言,Xml是互联网数据传输的重要工具,它可以跨越互联网任何的平台,不受编程语言和操作系统的限制,可以说它是一个拥有互联网最高级别通行证的数据携带者。
Xml用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。Xml是标准通用标记语言(SGML)的子集,非常适合Web传输。Xml提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
在很多工具或服务中需要解析Xml,此文档供相关开发人员使用C++解析Xml做参考。
Xml特点:
在XML产生之前,要想定义一个置标语言并推广利用它非常困难。一方面,如果制定了一个新的语言而期望它能生效,需要把这个标准提交给相关的组织(如W3C),等待它接受并正式公布这个标准,经过几轮的评定和修改,到这个置标语言终于成为一个正式推荐标准时,可能已经过了几年的时间。另一方面,为了让这套标记得到广泛应用,制订者必须为它配备浏览工具。这样,就不得不去游说各个浏览器厂商接受并支持新制定的标记,或者索性自己开发一个新的浏览器去与现有的浏览器竞争,无论哪个办法,都需要耗费大量的时间和工作。现在借助XML的帮助,制定新的置标语言要简单易行得多了,这也正是XML的优势所在。
各个不同的行业可能会有一些独特的要求,比如说,化学家需要化学公式中的一些特殊符号,建筑家需要设计图纸中的某些特殊的标记,音乐家需要音符,这些都需要单独的标记。但是,其他网页设计者一般不会用这些记号,也不需要这些标记。XML的优点就在于它允许各个组织、个人建立适合他们自己需要的标记库,并且这个标记库可以迅速地投入使用。
XML不仅允许自定义一套标记,而且这些标记不必仅限于对显示格式的描述。在XML中,显示样式从数据文档中分离出来,放在样式单文件中。这样,如果要改动信息的表现方式,无须改动信息本身,只要改动样式单文件就够了。如果这时候把列表的数据改用表格显示,无须再去修改大量数据信息文档,因为它们和同一个样式文件相关联,只要改动这个样式单文件就可以了。
在XML中数据搜索可以简单高效地进行。 若在HTML文件中搜索某个字符串,脚本会逐字寻找对应的字符串,即使找到了,若存在多个相同目标字符串,也不能确定是否为自己想要找到的那个。在XML中搜索不必要再去遍历整个文档,只需要找一下相关标记下的内容。此外,信息之间的某些复杂关系,比如树状结构、继承关系等,在XML中也都得到了绝好的体现,这样就大大方便了XML的应用处理程序的开发。
一个正规的Xml文档的结构需要有声明,文档元素描述信息(有且仅有一个根元素),元素属性。也可能包含实体,注释等信息。
在编写XML文档时,需要先使用文档声明来声明XML文档。且必须出现在文档的第一行。最简单的声明语法:
<?xml version="xxx"?>
Version后引号内的字符串表示文档的版本。
当我们写好的一个xml文件写入内存的时候会转换为二进制保存,这个时候会查码表,记事本保存的时候是gbk,而保存的时候默认查码表时用的是utf-8,这个时候我们就可以用encoding属性:默认是UTF-8
<?xml version="xxx” encoding="GBK"?>
这样就可以解决乱码等问题。
Xml声明还可能包含standlone属性:该xml文件是否独立存在。
根元素是Xml文档里面唯一的,它的开始是放在最前面,结束是放在最后面。
对于有属性的元素,语法结构为:
<元素名 属性名=“属性值”></元素名>
Note:
在xml中,一些字符拥有特殊的意义。如果把字符“<”放在xml元素中,会发生错误,这是因为解析器会把它当作新元素的开始,这样会产生xml错误。
为了避免这个错误,在元素中需要引用这些字符时,用实体引用来代替字符。Xml中5个预定义实体:
实体 | 符号 |
---|---|
&It; | < |
> | > |
& | & |
" | * |
' | . |
注释语法:
Note:
在C++中读写Xml会用到一个C++库tinyXml2类库。这个库中包含了我们读取Xml所需的接口。
TinyXML2是一个开源、简单、小巧、高效的C++ XML解析器,可以轻松集成到其它程序中。目前存在两个著名的开源XML文件解析库:tinyXml1,tinyXml2。相对tinyXml1而言,tinyXml2更为简洁,它只有一个tinyXml2.h文件和一个tinyXml2.cpp文件组成,而tinyXml1包含了6个文件。
TinyXml2具有以下几个优点:
使用方法:将 tinyxml2.cpp 和 tinyxml2.h 拷贝至项目目录,使用时包含头文件和引入名字空间。
作用:用于加载Xml文件
传参:LoadFile(FilePath)
一般使用格式:
if(Xml.LoadFile(FilePath)!=XML_SUCCESS)// 通过Xml文件路径读取文件,若读取失败则返回
return;
作用:用于读取Xml的根节点
传参:RootElement()
一般使用格式:
tinyxml2::XMLElement* rootElement = NULL;
rootElement=Xml.RootElement();//rootElement指向当前Xml的根节点
if(rootElement==NULL)//若读取失败则返回
return;
作用:用于读取xml节点的下一层节点
传参:(1)FirstChildElement()//读取下一层节点的第一个节点
(2)FirstChildElement(“XXX”)//读取下一层节点第一个元素名为“XXX”的节点
一般使用格式:
const XMLNode* Element1 = NULL;
Element1 = rootElement-> FirstChildElement(“XXX”);//Element1指向rootElement的下一层第一个元素名为”XXX”的节点
if(Element1 ==NULL)//若读取失败则返回
return;
作用:用于读取Xml节点同层节点的下一个节点
传参:NextSiblingElement()
一般使用格式:
const XMLNode* Element2 = NULL;
Element2 = Element1 -> NextSiblingElement ();//Element2指向Element1的同层节点的下一个节点
if(Element2 ==NULL)//若读取失败则返回
return;
作用:用于读取Xml节点的元素名
传参:Value()
一般使用格式:
String str1= Element2->Value();//将Element2的元素名赋值给str1
作用:用于读取Xml节点的属性值
传参:Attribute()
一般使用格式:
String str2 = Element2->ToElement()->Attribute(“XXX”);//将Element2的属性名为”XXX”的属性值赋值给str2
作用:用于读取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
}
通常在Xml中搜索数据会有很多限制条件,需要通过层层搜索找到想要的数据。
如图中,若希望通过限制条件WwanDeviceConfigID-ID,FCC_MAP_INDEX_TYPE- Value,Standard- Vaule,Item- 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节点的属性值对应的MapType
MapTypeElement = 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节点下,找到属性值与传参PSensors,DeviceMode,AntMode,AntMode1一一对应的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: