一、百度上转的,不错有意思:
方法/步骤
1
1.1.1 协议概述
采用网络上开源的Cmarkup类来解析XML协议,因为Cmarkup使用起来方便、简单。Cmarkup具备了所有对XML的操作,只要调用所提供的方法就可以了。最新版下载网站:http://www.firstobject.com/dn_markup.htm
2
1.1.1 XML描述
XML 文档形成一种树结构XML 文档必须包含根元素。该元素是所有其他元素的父元素。
XML 文档中的元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端。
上图表示下面的 XML 中的一本书:
<bookstore>
<book category="COOKING">
<titlelang="en">Everyday Italian</title>
<author>Giada DeLaurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<titlelang="en">Harry Potter</title>
<author>J K.Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<titlelang="en">Learning XML</title>
<author>Erik T.Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
嵌入式linux开发:[1]XML解析
3
1.1.1 XML语法
推荐学习网站http://www.w3school.com.cn/xml/xml_syntax.asp
一个合格xml的语法要求
1)文档的开始必须是XML声明。
2)含有数据的元素必须有起始标记和结束标记。
即:<tag>xxx</tag>
3)不含数据并且仅使用一个标记的元素必须以/>结束。
即:<tag/>
也可以使用<tag></tag>,但是不推荐.
不可以使用<tag>
4)文档只能包含一个能够包含全部其他元素的元素。
即:合格的XML文档必须有且只有一个根元素
5)元素只能嵌套不能重叠。
eg:不合法的嵌套例子:<b><i>Thistext is bold and italic</b></i>
6)属性值必须加引号。
eg: <tag key="value" />value要用双引号括起来
7)字符<和&只能用于起始标记和实体引用。
8)xml对大小写敏感
4
1.1.1 函数参考
下面是CMarkup的类成员函数列表。这些函数的设计都是基于源EDOM的。
1)初始化
Load 从一个(xml)文件构建CMarkup对象并对其进行解析。
SetDoc 从一个字符串构建CMarkup对象并对其进行解析。 xml.SetDoc("xml version=\"1.0\"encoding=\"UTF-8\"?>\r\n");
2)输出
Save 把xml文档数据写到文件中。
GetDoc 将整个xml文档数据作为一个字符串返回。
3)改变当前位置
FindElem 定位到下一个元素,可以选择匹配标签名或者路径。
FindChildElem 定位到下一个子元素,可以选择匹配标签名或者路径。
FindNode 定位到下一个节点,可选择匹配节点类型。
IntoElem 进入当前位置的下一级位置,而当前位置则变为父位置。
OutOfElem 使当前位置的父位置变为当前位置。
ResetPos 复位当前位置为文档的起始位置,到XML第一行的位置,需要使用FindChildElem函数后才可以使用其他函数,暂时测试如此。
ResetMainPos 复位当前位置为第一个兄弟位置之前。
ResetChilePos 复位当前的子位置为第一个子位置之前。
4)添加元素
AddElem 在当前位置元素或者最后一个兄弟之后新增一个元素。
InsertElem 在当前位置元素或者第一个兄弟之前插入一个元素。
AddChildElem 在当前子位置元素或者最后一个子位置之后增加一个元素。
InsertChildElem 在当前子位置元素或者第一个子位置之前插入一个元素。
InsertNode 在当前节点的前面或者父元素内容的开头新增一个节点。
译注:注意区分元素和节点,元素只是一种特殊的节点而已。
5)删除元素
RemoveElem 删除当前位置元素,包括子元素。
RemoveChildElem 删除当前位置的子元素,包括子元素的子元素。
RemoveNode 删除当前节点。
6)获取数据
GetData 返回当前位置元素或者节点的字符串值。
GetChildData 返回当前子位置元素的字符串值。
GetElemContent 返回当前位置包括子位置的markup字符串内容
GetSubDoc 返回当前位置包括子位置的子文档markup字符串内容
7)设置值,修改数据
SetData 设置当前位置元素或者节点的值
SetChildData 设置当前子位置元素的值
SetElemContent 将当前位置元素用markup(标记)内容来替换
SetAttrib 设置当前位置元素的指定属性的值
SetChildAttrib 设置当前子位置元素的指定属性的值
GetTagName 获得当前位置的标签的名
8)部分函数不解
例1、FindChildElem(“ITEM”)
<ORDER>
<ITEM>
<SN>132487A-J </SN>
<NAME>crank casing </NAME>
<QTY>1 </QTY>
</ITEM>
</ORDER>
xml.FindChildElem("ITEM")
xml.FindChildElem("SN");
CString csSN = xml.GetChildData();
如上并不能获得SN的值,必须增加xml.IntoElem();xml.FindChildElem("SN");所以FindChildElem并没有进入到<SN>依然处于<ITEM>的位置。该函数并不改变当前位置,可以使用GetTagName来获取当前的位置。该函数如果返回空就表示不存在该元素。
9)常用函数
1.CString转char *
windows strslave = xml.GetChildData(); cout << "sssss "<<strslave<<endl; char *p = (LPSTR)(LPCTSTR)strslave;
linux 下转换函数CString. c_str();
二、查找的资料:
最近在arm-linux下做个项目,需要在本地记录一些数据,日志之类的东西.本来准备随便用文本文件记录下完事,突然看到了rss,于是想起了xml.自己还没有用过xml,于是打算用xml来存放这个写数据,算是练个手.
由于以前没有了解过xml编程,所以查阅了点资料.原来目前的xml解析器一般有两种解析的形式.一种是DOM模型的,一种是SAX2模型的.DOM模型是讲xml文件中的结构解析成一棵树,然后再进行各种操作;而SAX2模型是类似与事件处理的方式从头到位解析xml文件.两种方式各有优劣,不过在嵌入式设备上用DOM模型的解析器似乎太耗内存,所以一般都用SAX2的解析器.而我使用的正是linux下的expat,是符合SAX2模型的.
好像linux都有自带expat的库,不过我为了移植到arm板上还是去下了个源码包.先交叉编译通过确认可以使用了才开始学习具体的使用.在源码包中有一个帮助文件已经很详细的介绍了库中每个函数的用途和入门编程.基本上看这个就够用了.
查阅了帮助发现其实只需要3,4个函数就可以搞定大部分的工作.
XML_ParserXML_ParserCreate(const XML_Char *encoding);
建立一个XML的对象.
XML_SetElementHandler(XML_Parserp, XML_StartElementHandler start, XML_EndElementHandler end);
是设置处理元素头尾的函数.
XML_SetCharacterDataHandler(XML_Parserp,XML_CharacterDataHandler charhndl)
设置元素内文本的处理函数.
voidXML_SetUserData(XML_Parser p,void *userData);
设置一个共享的数据结构给各各处理函数使用.
XML_StatusXML_Parse(XML_Parser p,const char *s,int len,int isFinal);
这个是主处理函数.通过给XML_Parse对象指定一个含有xml文本的char型数组s,来解析xml.解析的过程就是在读到某个位置就调用的处理函数来处理.比如读到元素的头部,就调用在XML_SetElementHandler中设定的start函数来处理.
上面描述的有些空洞,看个例子就全明白了:
要解析这样一个XML:
<ifqname="Wang Jingtian" age="22"> a greate guy!</ifq>
显示其中的attr和content,程序如下:
void starthandle(void*userdata, const char *el, const char **attr)
{
//解析时对xml元素头的解析函数
int i;
for(i=0;attr[i];i+=2)
{
printf("%s=%s",attr[i],attr[i+1]);
}
}
void endhandle(void*data, const char *el)
{
//什么也不做.
}
voidchardatahandle(void *data,char *s,int len)
{
//显示content的内容.注意s不是以空作为字符串结尾的标识.要手动用len来控制.
}
int ReadXml(char *xmlbuf,int bufsize)
{
XML_Parser g_Parser=XML_ParserCreate(NULL);
XML_SetElementHandler(g_Parser,starthandle,endhandle);
XML_SetCharacterDataHandler(g_Parse,chardatahandle);
if (! XML_Parse(g_Parser, xmlbuf,bufsize, 1))
{
fprintf(stderr, "Parseerror at line %d:/n%s/n",
XML_GetCurrentLineNumber(g_Parser),
XML_ErrorString(XML_GetErrorCode(g_Parser)));
return -1;
}
XML_ParserFree(g_Parser);
return 0;
} //程序大概就是这样,但是没有调试,不能保证正确:)
上边就是整个处理程序,是要调用readXML,传入xml的buf就可以解析了.基本上所有expat程序的框架都是这个样子,稍作改动就可以用在自己的程序里.