You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:27:02