最近项目需求研究XSD,在这里记录下。
首先,完全按照使用手册可以生成xsd对应的hxx和cxx两个文件。按照使用手册上的解析方法就显得很复杂,可将xml文件映射成对应的C++类,然后通过访问函数的方式逐层访问,这势必不方便(有可能才接触,不会其优点)。
后来在网上看到大神在linux下的成功案例。所以依葫芦画瓢在windows下试验了一下,成功。
XMLPlatformUtils::Initialize();
XercesDOMParser* domXmlParser = new XercesDOMParser;
//配置DOMParser
domXmlParser->setValidationScheme(XercesDOMParser::Val_Auto);
domXmlParser->setDoNamespaces(false);
domXmlParser->setDoSchema(false);
domXmlParser->setLoadExternalDTD(false);
try
{
//调用Xerces C++类库提供的解析接口
domXmlParser->parse(path.c_str());
//获得DOM树
DOMDocument* xmlDoc = domXmlParser->getDocument();
DOMElement* pRoot = xmlDoc->getDocumentElement();
if (!pRoot)
{
throw(std::runtime_error("empty XML document "));
}
if (0)
{
DOMTreeWalker* walker =
xmlDoc->createTreeWalker(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true);
for (DOMNode *current = walker->nextNode(); current != 0; current = walker->nextNode())
{
char *strValue = XMLString::transcode(current->getNodeValue());
ui.plainTextEdit->appendPlainText(QString(strValue));
XMLString::release(&strValue);
}
}
else
{
DOMNodeIterator* iterator = xmlDoc->createNodeIterator(pRoot, DOMNodeFilter::SHOW_ELEMENT, NULL, true);
for (DOMNode* current = iterator->nextNode(); current != 0; current = iterator->nextNode())
{
const XMLCh* value = current->getNodeValue();
const XMLCh* name = current->getNodeName();
char* strName = XMLString::transcode(current->getNodeName());
DOMNamedNodeMap* mapAttr = current->getAttributes();
if (mapAttr)
{
for (XMLSize_t index = 0; index < mapAttr->getLength(); index++)
{
DOMNode* node = mapAttr->item(index);
if (node)
{
char* strValue1 = XMLString::transcode(node->getNodeValue());
char* strName1 = XMLString::transcode(node->getNodeName());
ui.plainTextEdit->appendPlainText(QString::fromLocal8Bit(strName) + ":" + QString::fromLocal8Bit(strName1) + "=" + QString::fromLocal8Bit(strValue1));
XMLString::release(&strValue1);
XMLString::release(&strName1);
}
}
}
XMLString::release(&strName);
}
}
}
catch (xercesc::XMLException& excp)
{
char* msg = xercesc::XMLString::transcode(excp.getMessage());
ostringstream errBuf;
errBuf << "Error parsing file: " << msg << flush;
XMLString::release(&msg);
}
XMLPlatformUtils::Terminate()。
代码解析:要想利用Xerces C++类库来解析XML文档,必须要对类库进行初始化,所以在类XML的构造函数中,我们对类库进行了初始化:XMLPlatformUtils::Initialize();
接下来,我们定义的解析对象,并在构造函数中对其进行了初始化操作,然后,在xmlParser函数中我们调用类库的解析函数接口,传人xml文件名(m_DOMXmlParser->parse(xmlFile.c_str()) ;)。因为在这里我们选用的是DOM方法,所以接下来我们需要创建DOM树:DOMDocument* xmlDoc = m_DOMXmlParser-> getDocument();,并获取DOM树的根节点 DOMElement *pRoot = xmlDoc->getDocumentElement()。
再接下来是什么呢?根据上面所说的,我们需要遍历这棵DOM树,因此我们需要一种遍历方法,在程序中我给出了两种遍历的方法,一种是创建遍历树 DOMTreeWalker *walker = xmlDoc->createTreeWalker(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true),还有一种是通过迭代器来遍历整棵DOM树 DOMNodeIterator* iterator = xmlDoc-> createNodeIterator(pRoot, DOMNodeFilter::SHOW_TEXT, NULL, true)。两种方法都可以达到同样的效果。程序中注释掉的代码是创建遍历树方法。
遍历完,并打印出节点值以后,我们需要终止对类库的调用,所以在析构函数中:XMLPlatformUtils::Terminate()。
解析简单xml文档的基本步骤就是如此简单,至于复杂的XML文档,解析的步骤,尤其是创建DOM树的方法有点不同,在这里便不作介绍。接下来,来讲一下困扰我多天的中文解析问题。我们知道,Xerces C++默认只支持节点名中文,至于节点值,属性值则不支持,即使解析出来的也是乱码,所以需要自己解决。在这里,我们选用UTF-8编码格式的XML文档。