先来看一下在Poco中XML各元素被抽象成什么关系:
可以看到,任何元素都被抽象成Node,同时又分为三种类型的节点。(Attr和Notation看成一种)
第一种类型:CharacterData,这类Node是Name不可变,而Value可以由用户自定义。
第二种类型:AbstractContainerNode,这类Node有个特点,即含有属性,特别的对于Element节点,Name可以由用户自定义,而Value不可变。
第三种类型:右边两个,它们既可以改变Name,也可以改变Value。
下面是sample.xml文本:
hahah
对于上面这一份XML数据,有下面一份代码执行操作:
InputSource src("./sample.xml");//设置源数据
try
{
DOMParser parser;//创建一个分析者
AutoPtr pDoc = parser.parse(&src);//开始分析,并返回指向分析后数据的指针,用AutoPtr是为了自动回收垃圾
NodeIterator it(pDoc, NodeFilter::SHOW_ALL);//创建一个节点迭代器,默认迭代显示全部node
Node* pNode = it.nextNode();//此时指向第一个
while (pNode)
{
NamedNodeMap* map = pNode->attributes();//试图返回这个节点的属性
if(map)//看看是否真有属性
{
for(int i = 0 ; i < map->length() ; i++)//属性肯定至少0个,用循环一个个取出
{
Node* attr = map->item(i);
std::cout << attr->nodeName() << std::endl;
std::cout << attr->nodeValue() << std::endl;
}//属性结束
}
std::cout << pNode->nodeName() << std::endl;//取出当前节点的Name
std::cout<< pNode->nodeValue() << std::endl;//取出当前节点的Value
pNode = it.nextNode();//指向下一个node
}
}
catch (Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
}
可以看出,节点的Name和Value同节点属性的Name和Value取得方法是同样的,都是用nodeName()和nodeValue()。
看一下显示结果:
在把数据拿过来看看:
hahah
可以看出,程序虽是我们写的,可是具体的遍历行为却是Poco自己定义的。首先明确,有#的全都是系统的const string,也就体现了Name不可变。
Poco先发现Document类型,把它的Name打印出:#Document,再打印出它的Value,由于在源码中,其值为空字符串,所以什么也没有。
Poco再发现Comment类型,把它的Name打印出:#Comment,由于Comment的值是可以由用户自定义的,所以存在并显示出“This is a comment”。
Poco再发现Element类型,把它的Name打印出:zhong,由于element的Name是由用户定义的,所以存在,然而,它没有值,只可能有属性。
Poco再发现Text类型,把它的Name打印出:#Text,这个text是element zhong 的,它不可以指定Name,但可以指定Value,这里没有Value,所以没有什么出现。
Poco再发现Attr类型,这说明判断属性的循环进去了,把它的Name打印出:long ,再打印Value 5。由于程序语句执行顺序,这个属性是element guo的
Poco再发现Element类型,把它的Name打印出:guo,没有Value可以打印出。
Poco再发现Text类型,把它的Name打印出:#Text,这个text是element guo的,它不可以指定Name,但可以指定Value,这里Value是“hahah”。
最后,值得注意一下,我发现父子Element元素之间还有一个Text element,比如上面这份数据,在 和 之间就存在这样一个元素,所以在屏幕上最后会打印Name:#Text,而没有值。
可以这样设置:
wo
shi
zhong
guo
ren
这样,解析后的每个Text元素都有Value了。
还没有涉及更加复杂的XML操作,因为我在项目中对XML数据格式的要求不太复杂,主要集中在节点属性这一块,就这足够了。
以上分析建立在本人没有系统的学习过XML知识的前提下。
谢谢观赏!