Xerces C++ 学习笔记
1. 初始化平台:
XMLPlatformUtils::Initialze()
2. 销毁平台:
XMLPlatformUtils::Terminate();
3. 加载分析报文
XercesDOMParser *parser = new XercesDOMParser();
Parser->parse( 参数 ); 这个参数可以直接是文件名,也可以是内存的数据,具体的查看 API
4. 数据格式转换
XMLString.transcode() 这个方法有多个重载,既可以把 XMLCh * 格式的数据转换成 char * 的数据,也可以把 char * 的数据转换成 XMLCh *, 我们也可以利用这个函数来初始化 XMLCh 格式类型的数组,比如 XMLCh temp[100];
XMLString.transcode(“LS”,temp,99);// 用“ LS ”初始化 temp 这个数组的内容。
5. 分析报文后,如何得到文档的树型结构
DOMDocument *xmlDoc = parser->getDocument();
6. 得到树型结构后,如何得到第一个根节点
DOMElement *root = xmlDoc->getDocumentElement();
7. 如何遍历文档的结构
遍历一个树型的文档结构有三种方法。
1 .使用 DOMNodeIterator 类
DOMNodeIterator *iterator = xmlDoc->createNodeIterator(root, DOMNodeFilter::SHOW_TEXT, NULL, true);
for ( DOMNode * current = (DOMNode *)iterator->nextNode(); current != 0; current = (DOMNode *)iterator->nextNode() )
{
string strValue = XMLString::transcode(current->getNodeValue());
std::cout <
}// 以上就可以把 xml 文档中的属性为 NODETEXT 节点的内容给打印出来。
2 .使用 DOMTreeWalker 类
D OMTreeWalker *walker = xmlDoc->createTreeWalker(root, DOMNodeFilter::SHOW_TEXT, NULL, true);
f or (DOMNode *current = walker->nextNode(); current != 0; current = walker->nextNode() )
{
char *strValue = XMLString::transcode( current->getNodeValue() ); std::cout <
}
3 .使用子节点直接遍历树型结构
DOMNode *n = (DOMNode*)xmlDoc->getDocumentElement();
// 下面开始遍历这个树的结构
if(n)
{
if (n->getNodeType() == DOMNode::ELEMENT_NODE)
{
DOMNodeList* nodeList = n->getChildNodes();
unsigned int nListLen = nodeList->getLength();
for (unsigned int i=0; i
{
DOMNode* nodeTemp = nodeList->item(i);
if (nodeTemp->getNodeType() == DOMNode::ELEMENT_NODE)
{
for (DOMNode* node1=nodeTemp->getFirstChild(); node1!=0; node1=node1->getNextSibling())
{
char* name = XMLString::transcode(node1->getNodeName());
string strTemp = name;
if (strTemp == "name") // 这个就是跟 xml 文档中 name 节点匹配
{
char* myname=XMLString::transcode(node1->getFirstChild()->getNodeValue());
cout<
}
}
}
continue;
}
}
}
8. 如何添加子节点。
//Add new (empty) Element to the root element
DOM_Element parentNode = …;// parent is known
DOM_Element prodElem = doc->createElement (tagName);
parentNode->appendChild (prodElem);
9. 在加载 xml 文件分析前,有两种加载方式:一种直接通过文件加载,一种是通过内存加载
1. String xmlfile = “a.xml”;
Parser->parse(xmlfile.c_str());
2.MemBufInputSource 这个类处理内存的数据,然后利用 parser->parse(*men)//men 是 MemBufInputSource 的实例指针对象。
|
10. 在加载分析报文前,可以设置 XercesDOMParser 的一些属性。
P arser->setValidationScheme( XercesDOMParser::Val_Auto );
Parser->setDoNamespaces( false );
Parser->setDoSchema( false );
Parser->setLoadExternalDTD( false );
// 这个部分的代码可以参照类库自带的例子。
11. 我们也可以设置错误的处理代码。
这部分可以查看类库下的 DOMPrint 例子。 DOMError ,DOMErrorHandler
12. 也可以设置分析过滤的属性
DOMNodeFilter 这个类能起到这个效果
13. 要美化文档的格式化输出,我们可以使用
XMLFormatter XMLFormatTarget , 用的时候可以查看。
14 我们也可以通过 DOMImplementationLs , DOMImplementation 前者是后者的基类。通过这个类我们可以创建 DOMBuilder ( parser )或 DOMWriter (序列,既可以写到屏幕,也可以写到文件)
如何利用Xerces C++正确处理XML文档中的中文
作者: 张志强
下载本文示例代码
1. 背景介绍
Apache的Xerces C++是广大c/c++程序员非常喜欢使用的XML解析器之一。主要原因是其本身是一个开放源代码的项目而且提供不同平台下的库和源代码,故深受广大c/c++程序员的欢迎。
Xerces C++可以到以下网站下载:
1) http://xml.apache.org/
2) http://www.vckbase.com/tools
2. 问题描述
根据软件开发的要求,作者开发了一个文件特征识别软件,该软件可根据文件特有的特征识别出文件的类型。要求将文件特征保存在XML文件中。根据要求作者选择了Xerces C++作为XML解析器。但发现出了一个严重的问题:被解析的XML文件中不能包含中文,否则中文将不能正确的解析。作者研究了Xerces C++提供的例子程序,发现这些例子程序解析的结果也是错误的。只有DOMPrint程序例外。这肯定了Xerces C++本身是支持中文的。
XML编码:
SAXPrint程序解析结果:
为此,作者曾经在IBM的中文网站发现一篇文章《如何利用Xerces-C++解析包含中文字符的XML文档》并将其所描述的办法应用到程序中。但后来由于机器发生故障,硬盘上的数据全部丢失。不得不把以前做过的事重做一遍。因一时在IBM的网站上未找到上面提到的贴子,而且由于当时捡现成的没有用心研究其实现方法,故不得不仔细分析Xerces C++提供的源代码,自己动手解决中文问题。为了今后广大C++程序员碰到类似问题时不会像我一样痛苦。我也决定将自己的研究结果公布出来供大家分享。如果谁有更好的解决办法不要忘记告诉我。
3. 原因分析
上面的例子里,程序将“文档”两个中文字符解析成了乱码。但DOMPrint程序确能够正确解析。这表明Xerces C++对国际编码肯定是支持的。作者通过对DOMPrint和SAXPrint两个程序的比较跟踪发现问题的根本就是XMLFormatter设置的问题。由于SAX是基于事件的,大多数使用者只是简单的解析XML文档,XMLFormatter的使用比较麻烦。而DOMPrint也是通过标准的输出程序输出的屏幕上的,我们不能直接使用输出结果。
由于XML解析器解析的字符串都是XMLCh格式的,一个字符占用一个字节,而汉字字符确要占用两个字节。故若不做适当的转换,汉字的输出结果就变成乱码了。
4. 解决办法
找到原因就有解决问题的方法了,明显的需要一个把解析出来的XMLCh转换成普通的字符串。这是解析,如果我们需要自己写入XML文档也有一个把普通字符串转换为XMLCh的过程。我把这两个转换过程封装在了一个名为“XMLStringTranslate”的类中。使用如下:
void SAXMagicHandlers::startElement(const XMLCh* const name,AttributeList& attributes) { XMLStringTranslate stringTranslate("gb2312"); string strName=stringTranslate.translate(name);//得到可包含汉字字符的普通字符串 string strValue="pdf文档"; XMLCh * value= stringTranslate.translate(strValue.c_str());//将普通字符串转换成XMLCh串 }
采用XMLStringTranslate后的实际运行结果:
特别说明:
由于为了防止内存释放问题,将普通字符串转换成XMLCh *的translate函数返回的是类的一个成员变量,故下面的代码是不允许的:
XMLCh * value1= stringTranslate.translate("测试1"); XMLCh * value2= stringTranslate.translate("测试2");
这样使用的结果是value1和value2的值将是一样的(因为其内存地址根本就是一样的)。正确的使用方法是通过内存拷贝或则其他方法,将value1的值保存起来或则及时使用,否则value2将影响value1的值。
5. 结束语
目前,许多企业已经或者正在采用Xerces C++开发XML的应用系统,相信在应用的过程中会遇到各种问题,欢迎有兴趣的朋友与我联系,共同交流。