Xerces Parser解析CDATA段异常:长CDATA开头出现乱码求助
解析Xerces Parser长CDATA段出现乱码的问题
问题现象
使用Xerces Parser解析XML时,短CDATA段可正常解析,但长CDATA段开头出现奇怪乱码符号。已确认解析前XML字符串完整无异常,排除终端显示问题,仅该长CDATA段出现异常。
XML示例代码
const std::string XML = R"(<?xml version="1.0" encoding="UTF-8"?> <AAA version="5.2.0"> <Status> <CurrentStatus> <Status><![CDATA[<LghjL><AAAA><BBBCCCCCDD><EEEEE>AAAAccf123</EEEEE></BBBCCCCCDD></AAAA></FF><AAAA><BBBCCCCCDD><EEEEE></BBBCCCCCDD>]]></Status> <Test><![CDATA[<TEST>data</TEST>]]></Test> </CurrentStatus> </Status> </AAA>)";
Parser配置代码
#include <iostream> #include <string> #include <list> #include <xercesc/framework/MemBufInputSource.hpp> #include <xercesc/parsers/XercesDOMParser.hpp> #include <xercesc/dom/DOM.hpp> #include <xercesc/sax/HandlerBase.hpp> #include <xercesc/sax/SAXParseException.hpp> #include <xercesc/sax/ErrorHandler.hpp> #include <xercesc/util/XMLString.hpp> #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/XMLUni.hpp> #include <xercesc/util/OutOfMemoryException.hpp> #include <xercesc/validators/common/Grammar.hpp> #include <xercesc/framework/LocalFileInputSource.hpp> #include <xercesc/framework/MemBufFormatTarget.hpp> #include <xercesc/dom/DOMImplementationRegistry.hpp> #include <xercesc/dom/DOMErrorHandler.hpp> #include <xercesc/dom/DOMImplementationLS.hpp> #include <xercesc/dom/DOMConfiguration.hpp> #include <xercesc/dom/DOMCDATASection.hpp> #include <xercesc/util/XMLException.hpp> #include <xercesc/sax/SAXException.hpp> #include <xercesc/dom/DOMDocument.hpp> #include <xercesc/dom/DOMImplementation.hpp> #include <xercesc/dom/DOMLSSerializer.hpp> #include <xercesc/dom/DOMLSOutput.hpp> #include <xercesc/framework/LocalFileFormatTarget.hpp> #include <xercesc/sax2/XMLReaderFactory.hpp> #include <xercesc/sax2/DefaultHandler.hpp> #include <sstream> namespace xmlx { class XMLNode { private: xercesc::DOMElement* _element; bool _first_in_loop; public: XMLNode() : _element(nullptr), _first_in_loop(true) { } XMLNode(xercesc::DOMElement* element) : _element(element), _first_in_loop(true) {} ~XMLNode() { } xercesc::DOMDocument* parseXml(const std::string& XML = "") { xercesc::MemBufInputSource memBuf(reinterpret_cast<const XMLByte*>(XML.c_str()), XML.size(), "xmlBuffer", false); xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser(); parser->setValidationScheme(xercesc::XercesDOMParser::Val_Never); parser->setDoNamespaces(false); parser->setDoSchema(false); parser->setLoadExternalDTD(false); xercesc::DOMDocument* doc; try { parser->parse(memBuf); doc = parser->getDocument(); delete parser; } catch (...) { std::cerr << "Unexpected exception during parsing" << std::endl; } _element = doc->getDocumentElement(); return doc; } XMLNode operator [](const std::string& tagName){ if(_element == nullptr) { std::string error = "------------------- OBS *************** Current element is null element: " +tagName; throw(std::runtime_error(error)); } for (DOMNode* child = _element->getFirstChild(); child != nullptr; child = child->getNextSibling()) { if (child->getNodeType() == xercesc::DOMNode::ELEMENT_NODE) { xercesc::DOMElement* currentElement = dynamic_cast<xercesc::DOMElement*>(child); std::string myStr = xercesc::XMLString::transcode(currentElement->getTagName()); if (myStr == tagName) { return XMLNode(currentElement); } } } std::string error = "No next element found"; throw(std::runtime_error(error)); } std::string getText() { if (_element == nullptr) return ""; for (DOMNode* child = _element->getFirstChild(); child != nullptr; child = child->getNextSibling()) { if (child->getNodeType() == xercesc::DOMNode::TEXT_NODE) { xercesc::DOMText* tempText = dynamic_cast<xercesc::DOMText*>(child); if (tempText == nullptr) { return ""; } char* textContent = xercesc::XMLString::transcode(tempText->getData()); std::string text(textContent); xercesc::XMLString::release(&textContent); return text; } if (child->getNodeType() == xercesc::DOMNode::CDATA_SECTION_NODE) { xercesc::DOMCDATASection* tempCdata1 = dynamic_cast<xercesc::DOMCDATASection*>(child); if (tempCdata1 == nullptr) { return ""; } char* textContent1 = xercesc::XMLString::transcode(tempCdata1->getData()); std::string text1(textContent1); xercesc::XMLString::release(&textContent1); return text1; } } return ""; } }; }
控制台输出
xercesc::XMLPlatformUtils::Initialize(); xmlx::XMLNode myXmlx; myXmlx.parseXml(XML); std::cout << myXmlx["Status"]["CurrentStatus"]["Test"].getText() << "\n"; //输出:<TEST>data</TEST> std::cout << myXmlx["Status"]["CurrentStatus"]["Status"].getText() << "\n"; //输出:????jL><AAAA><BBBCCCCCDD><EEEEE>AAAAccf123</EEEEE></BBBCCCCCDD></AAAA></FF><AAAA><BBBCCCCCDD><EEEEE></BBBCCCCCDD> xercesc::XMLPlatformUtils::Terminate();
原因分析
核心问题出在MemBufInputSource的构造参数上:
- 第四个参数
copyBuf被设置为false,意味着Xerces不会复制传入的内存缓冲区,而是直接引用原字符串的内存地址。当XML字符串较长时,原字符串的内存可能在解析过程中被意外修改、覆盖或释放(比如栈内存回收、其他操作的内存复用),导致Xerces读取到非法内存数据,表现为开头的乱码。 - 此外,虽然这里XML是UTF-8编码,但直接将
std::string的c_str()强制转换为XMLByte*时,若字符串包含多字节字符,可能存在编码转换隐患,但本案例中主要触发点是内存引用问题。
解决方法
1. 让Xerces复制内存缓冲区
将MemBufInputSource构造的第四个参数改为true,确保Xerces内部复制一份独立的内存,避免原内存失效影响解析:
xercesc::MemBufInputSource memBuf( reinterpret_cast<const XMLByte*>(XML.c_str()), XML.size(), "xmlBuffer", true // 修改为true,让Xerces复制内存 );
2. 显式指定编码(可选增强)
为MemBufInputSource显式设置UTF-8编码,确保Xerces正确识别字符串编码,避免潜在的编码转换问题:
const XMLCh* encoding = xercesc::XMLString::transcode("UTF-8"); xercesc::MemBufInputSource memBuf( reinterpret_cast<const XMLByte*>(XML.c_str()), XML.size(), "xmlBuffer", true, encoding ); xercesc::XMLString::release(&encoding);
修改后的parseXml函数示例
xercesc::DOMDocument* parseXml(const std::string& XML = "") { const XMLCh* encoding = xercesc::XMLString::transcode("UTF-8"); xercesc::MemBufInputSource memBuf( reinterpret_cast<const XMLByte*>(XML.c_str()), XML.size(), "xmlBuffer", true, encoding ); xercesc::XMLString::release(&encoding); xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser(); parser->setValidationScheme(xercesc::XercesDOMParser::Val_Never); parser->setDoNamespaces(false); parser->setDoSchema(false); parser->setLoadExternalDTD(false); xercesc::DOMDocument* doc = nullptr; try { parser->parse(memBuf); doc = parser->getDocument(); } catch (const xercesc::XMLException& e) { char* msg = xercesc::XMLString::transcode(e.getMessage()); std::cerr << "XML Exception: " << msg << std::endl; xercesc::XMLString::release(&msg); } catch (const xercesc::SAXException& e) { char* msg = xercesc::XMLString::transcode(e.getMessage()); std::cerr << "SAX Exception: " << msg << std::endl; xercesc::XMLString::release(&msg); } catch (...) { std::cerr << "Unexpected exception during parsing" << std::endl; } delete parser; if (doc != nullptr) { _element = doc->getDocumentElement(); } return doc; }
额外优化提示
- 在异常处理中添加具体的Xerces异常捕获,便于定位问题,避免吞掉所有异常导致调试困难。
- 确保
DOMDocument在异常情况下不会返回空指针后直接访问,增加空指针检查。
内容的提问来源于stack exchange,提问作者Fredrik s
相关产品推荐
相关产品推荐

