Xerces-C++
http://xerces.apache.org/xerces-c/
如果是自己组XML, 对于带特殊字符的文本要下面的标记包起来. 如果是用Xerces-C++不会出现这种问题。
<![CDATA[
]]>
资料: 针对XERCES2.x的xml数据分析
MFC Controls using XML-Files as DataSource (XERCES-Parser)
http://www.codeproject.com/KB/combobox/XMLControls.aspx
我在这篇资料的基础上, 改了一版. 可以分析提取自定义的xml数据.
原始Demo针对XERCES3.x, 是编译不过的. 我调整了头定义,替换了已经废除的DomBuilder. 在XERCES2每个函数和类前面加上了名字空间, 这回编译通过. 剩下的事情就是遍历节点. 我们做的是xml分析, 都是已知格式的xml. 找到了节点, 如果节点名称和位置是我们要的, 取出对应的值.
xml 编码选为GBK. GB2312在XERCES中不被支持. 如果是GB2312, 分析后的DOMDocument * 是空的.
xerces-c3.x 编译采用vc7.1~vc10, 不在支持vc6. 调用的时候, 可以用vc6.
在.h 中 使用 XERCES_CPP_NAMESPACE_USE,等同于using namespace XERCES_CPP_NAMESPACE;
就不用在指定具体的XERCES_CPP_NAMESPACE::xx, 方便很多.
唯一要显式指定命名空间的是XERCES_CPP_NAMESPACE::DOMDocument, 可能和MS的定义重复了.
XERCES为了使不同版本之间的应用端代码免维护, 定义了下面的宏,这比直接写上命名空间好
#define XERCES_CPP_NAMESPACE_QUALIFIER XERCES_CPP_NAMESPACE::
<2010_1219>
读取自定义xml的最底层节点文本成功, 满足应用了. 还有很多实验需要做.INT CMainDlg::XmlParse(PCHAR pcXmlFileName) { /** <?xml version="1.0" encoding="GBK" ?> <!-- @file test.xml @brief 构造多节点的xml, 用于验证xml解析的正确性 @author LostSpeed @date 2010/12/18 @warning xml解析是硬编码, 直接读预期的已知节点 --> <progname><!-- 程序名称 --> <cmdline_parametr><!-- 命令行参数 --> <openfile_pathname>c:/tmp/test.txt</openfile_pathname><!-- 要打开的文档全路径 --> <cmd_node_1><!-- 命令行参数节点1 --> <SaveAsPathName>c:/tmp/test.dat</SaveAsPathName><!-- 保存路径 --> <bufferSizeMax>4096</bufferSizeMax><!-- 在cmd_node_1节点下模拟一些子节点数据 --> <option1>1024</option1><!-- 在cmd_node_1节点下模拟一些子节点数据 --> <option2>2048</option2><!-- 在cmd_node_1节点下模拟一些子节点数据 --> <option3>4096</option3><!-- 在cmd_node_1节点下模拟一些子节点数据 --> <option4>8192</option4><!-- 在cmd_node_1节点下模拟一些子节点数据 --> </cmd_node_1> </cmdline_parametr> </progname> */ CLsXmlParser myXml; INT nRc = S_FALSE; CString csMsg; CString csTmp; CString csFileNameBeOpen; CString csSaveAsPathName; CString csbufferSizeMax; CString csoption1; CString csoption2; CString csoption3; CString csoption4; myXml.XmlParseBegin(pcXmlFileName); try { nRc = myXml.GetNodeTextContent(csFileNameBeOpen, "%s %s %s %s", "progname", "cmdline_parametr", "openfile_pathname", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csSaveAsPathName, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "SaveAsPathName", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csbufferSizeMax, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "bufferSizeMax", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csoption1, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "option1", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csoption2, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "option2", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csoption3, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "option3", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } nRc = myXml.GetNodeTextContent(csoption4, "%s %s %s %s %s", "progname", "cmdline_parametr", "cmd_node_1", "option4", NULL); if(nRc != S_OK) { throw((DWORD)S_FALSE); } } catch(DWORD dwE) { UNREFERENCED_PARAMETER(dwE); AfxMessageBox("XML分析错误, 请检查XML内容和您要搜索的节点序列"); } myXml.XmlParseEnd(); this->SetWindowText(pcXmlFileName); if(S_OK == nRc) { csMsg.Format(" %s = %s/r/n %s = %s/r/n %s = %s/r/n %s = %s/r/n %s = %s/r/n %s = %s/r/n %s = %s/r/n ", "FileNameBeOpen", csFileNameBeOpen, "SaveAsPathName", csSaveAsPathName, "bufferSizeMax", csbufferSizeMax, "option1", csoption1, "option2", csoption2, "option3", csoption3, "option4", csoption4); } ((CEdit *)GetDlgItem(IDC_EDIT_XML_RESULT))->SetWindowText(csMsg); /** @note 运行结果 * FileNameBeOpen = c:/tmp/test.txt * SaveAsPathName = c:/tmp/test.dat * bufferSizeMax = 4096 * option1 = 1024 * option2 = 2048 * option3 = 4096 * option4 = 8192 */ return S_OK; }
<2010_1220>
fix: 发现节点文本值如果为空, 例如<op1></op1>, 此节点返回的下一级的第一个节点为空。
需要看一下有文本值的节点的名称。
INT CLsXmlParser::GetNodeTextContent(CString & csNodeTextContent, TCHAR * szNodeFormat, ...) { int n = 0; int nSizeParameter = 0; PCHAR lpcszID = NULL; CString m_strID; PCHAR pcBuf = NULL; //DOMNode *row; int count = 0; if (!m_pXmlDoc) return S_FALSE; if(m_pXmlDoc->getNodeType() != DOMNode::DOCUMENT_NODE) return S_FALSE; //从传进来的参数列表中, 得到首节点到目标节点的名称 //CStringArray m_strArrNode; m_strArrNode.RemoveAll(); { va_list args; va_start(args, szNodeFormat);// PCHAR pBuf = NULL; do { pBuf = va_arg(args, TCHAR *); if(pBuf) { m_strArrNode.Add(pBuf); } }while(pBuf); va_end(args); } if(m_strArrNode.GetSize() <= 0) return S_FALSE; DOMNode *pNodeRoot = m_pXmlDoc->getFirstChild(); DOMNode *pNodeSub = pNodeRoot; nSizeParameter = m_strArrNode.GetSize(); BOOL bNeedGetTextContent = FALSE; BOOL bFind = FALSE; for(n = 0; n < nSizeParameter; n++) { bNeedGetTextContent = ((n + 1) == nSizeParameter) ? TRUE : FALSE; pNodeSub = FindSubNodeByNodeName (pNodeSub, (LPSTR)(LPCSTR)m_strArrNode.GetAt(n), csNodeTextContent, bNeedGetTextContent, bFind); /** @note * 防止节点文本为空的情况, 找到节点文本后,返回真 */ //if((!pNodeSub) && bNeedGetTextContent) if(!bFind) return S_FALSE; if(bNeedGetTextContent) break; } return S_OK; }
<2010_1225>
找到一篇基于Xerces-C2.x读写XML的好资料, 使用Xerces静态库连接的.
An XML parser and editor with shades of a Design Pattern
http://www.codeproject.com/KB/XML/xmlparser.aspx
Xerces-3.x 不兼容 2.x的代码, 要参照Xerces-3.x自带的文档做修改.
自己用的写Xml的部件还没完成,先修改了一个demo, 适应于Xerces-3.x.
http://blog.csdn.net/LostSpeed/archive/2010/12/27/6101612.aspx
<<实验: xerces-c2.x 和 xerces-c3.x 的编程区别>>
修改后的demo下载点:
http://download.csdn.net/source/2943125
XMLEditor修改版_V2010_1228_0117
<2010_1113>
今天找到了分析用xerces-c分析XmlBuffer的资料, 把这个实验做了.
再升级程序取属性值这样的操作, 原来封装的函数用来取连续嵌套的节点值,还是很方便。但是对于取嵌套带属性的节点,就不好用了。