分类: C/C++
2008-04-02 15:01:57
Apache的Xerces C++ 和IBM的XML4C是广大C/C++编程人员非常喜欢使用的XML解析器,我比较偏好XML4C,最主要的原因是它能正确处理XML文档中的中文字符,具体可参见我以前在IBM developerWorkers China上发表的文章《如何利用Xerces-C++解析包含中文字符的XML文档》。
Xerces C++提供DOMParser和SAXParser解析XML文档,主要用途可有以下三种:
第2和第3种应用的实现比较简单,可参照Xerces C++提供的DOMPrint和SAXPrint的例子,并略做改进即可解决。而对于应用非常普遍的第一种情况,常有人会因为XML文档中的whitespace而出现程序处理问题,不能正确操纵DOM_Document表示的XML tree,从而影响了Xerces C++或XML4C上的应用开发。
下面以Xerces C++的DOMParser为例,描述当解析含whitespace的XML文档时存在的问题,图1是部分程序代码,图2是要解析的XML文档。
图1中的代码在创建DOMParser之后,调用了DOMParser类的setIncludeIgnorableWhitespace()方法,目的是告诉解析器不要在DOM_Document中包含whitespace,因而,根据图2所示,图1代码运行结果应为:
List size = 1
但是,程序实际运行的结果为:
List size = 3
对DOM_NodeList遍历时发现,DOMParser解析test.xml时将文档中的whitespace认为了DOM_Text节点。DOMParser没有理会setIncludeIgnorableWhitespace()方法的调用,这样,DOM_Document中会存在多个代表whitespace的DOM_Text节点,这不仅占用了多余内存,而且,极大影响了程序员对DOM_Document的操作,甚至会使子节点是否等于某值的判断始终为false。因而,Xerces C++的程序员需要在DOM_Document中过滤掉所有的whitespace,如果将test.xml中多余的whitespace去掉(见图3所示)后,重新运行图1的代码,结果与预想的相同。
|
|
|
显然,利用额外的程序编程解决此问题是不明智的。Xerces C++应提供了相应的机制来解决它。我用google搜索了这方面的信息,发现还是有许多人遇到了此类问题,尽管IBM论坛上有人提出了解决思路,但是,还不够完整,我在研究Xerces C++的相关资料和代码解决此问题后认为,如何利用Xerces C++正确处理xml文档中的whitespace问题需要有较详细的解释和解决方法,权当是抛砖引玉吧,希望能为Xerces C++或XML4C的普及应用有所帮助。
根据void DOMParser::setIncludeIgnorableWhitespace (const bool include ) 的文档说明,Parser是否包含whitespace的设置仅在Parser对XML文档进行有效性验证处理时有效。因而,图2中的test.xml只能是格式良好的XML文档,由于它没有相应的schema定义,所以,DOMParser无法对此文档进行有效性验证,缺省认为whitespace是DOM_Document的子节点,类型是DOM_Text。
那么,为test.xml提供schema之后,图1的运行结果是否正确呢?答案是不正确的,DOMParser还需要调用下列的API来设置其它选项。
方法名 | 方法说明 |
Void SetDoSchema(const bool newState ) | 设置Parser是否处理xml文档中的schema,如果为true,则Parser还要处理xml中的schema,否则,parser不处理xml文档的schema。 |
Void setDoValidation ( const bool newState ) | 此方法同setValidationScheme,不推荐使用。 |
Void setDoNamespaces ( const bool newState ) | 设置Parser是否处理xml文档中的名域,如果为true,则Parser增强名域定义的约束和规则。 |
Void setValidationScheme (const ValSchemes newScheme ) | 设置Parser利用定义的schema对xml文档进行有效性验证解析。NewScheme的值有Val_Never,Val_Auto,Val_Always,分别表示对xml文档不进行shema有效验证、自动选择是否验证、总是进行有效验证。 |
因而,通过设置DOMParser的几个选项并提供test.xml的schema就应该能解决whitespace的问题。
基于上面的分析,我们首先需要为test.xml提供schema定义,这是解决此问题的第一步,也是必须的,如果不提供schema定义而想完成xml文档的紧缩处理,则需要程序员额外增加实现代码;或者使用SAXParser,在实现ContentHandler::ignorableWhitespace(const XMLCh* const chars, const unsigned int length)的纯虚方法中特殊处理,不为whitespace生成DOM_Text节点。但我这里不推荐此种处理方法,XML文档的有效性验证在许多应用系统中是必须的。
Test.xml的schema文件定义见Xerces C++包中的文件:
在上述步骤完成后,修改图1的程序代码,设置Parser支持XML文档的有效性验证,具体见图6。
|
|
需要说明以下几点:
目前,许多企业已经或者正在采用Xerces C++开发XML的应用系统,相信在应用的过程中会遇到各种问题,欢迎有兴趣的朋友与我联系,共同交流。
chinaunix网友2008-04-28 15:20:30
请教个问题:我现在用XQILLA实现了节点定位,而后想修改节点的内容,却报出异常document has changed。是否意味着xqilla不能修改DOM树,那应该如何实现这个功能呢?谢谢