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

如何配置Poco SAX解析器以保留XML原始字符?

如何让Poco SAX解析器保留XML原始编码字符

当然可以实现这个需求,但得先明确一点:标准SAX解析器的核心职责之一就是解析XML中的实体引用(比如&lt;)并将其转换为对应的原始字符(<),这是符合XML规范的默认行为。所以要保留原始的编码字符,我们需要绕开默认的实体解析逻辑,或者使用更底层的XML处理工具。

下面是两种可行的方案:

方案一:使用Poco XMLTokenizer(推荐)

Poco提供了XMLTokenizer这个底层工具,它会把XML分解成一个个token(比如起始标签、字符数据、实体引用等),并且不会自动解码实体引用。这样你可以直接捕获到原始的&lt;字符串,同时还能处理XML的结构。

举个简单的代码示例:

#include "Poco/XML/XMLTokenizer.h"
#include "Poco/XML/InputSource.h"
#include <iostream>

using namespace Poco::XML;

int main() {
    // 示例XML内容
    std::string xmlContent = "<root>Example text with &lt; encoded character</root>";
    InputSource input(xmlContent);
    XMLTokenizer tokenizer(input);

    Token currentToken;
    while ((currentToken = tokenizer.nextToken()).type() != Token::TOKEN_EOF) {
        switch (currentToken.type()) {
            case Token::TOKEN_START_TAG:
                std::cout << "Found start tag: " << currentToken.asString() << "\n";
                break;
            case Token::TOKEN_CHARACTERS:
                std::cout << "Found text: " << currentToken.asString() << "\n";
                break;
            case Token::TOKEN_ENTITY_REFERENCE:
                // 这里直接拿到原始的实体引用字符串
                std::cout << "Found entity reference: " << currentToken.asString() << "\n";
                break;
            case Token::TOKEN_END_TAG:
                std::cout << "Found end tag: " << currentToken.asString() << "\n";
                break;
            // 可以根据需求处理其他token类型(比如注释、DOCTYPE等)
        }
    }
    return 0;
}

运行这段代码后,你会看到输出里直接保留了&lt;,而不是被解码成<。

方案二:自定义EntityResolver(仅适用于自定义实体,预定义实体有限制)

如果你坚持要用标准SAX的ContentHandler,那可以尝试自定义EntityResolver,但要注意:预定义实体(&lt;、&gt;等)是XML规范内置的,Poco的SAX解析器会自动处理它们,不会调用EntityResolver。所以这个方案只适用于你自己定义的实体,对预定义实体无效。

示例代码(仅作参考,不解决预定义实体问题):

#include "Poco/XML/SAXParser.h"
#include "Poco/XML/ContentHandler.h"
#include "Poco/XML/EntityResolver.h"
#include "Poco/XML/InputSource.h"
#include <iostream>

using namespace Poco::XML;

class CustomEntityResolver : public EntityResolver {
public:
    InputSource* resolveEntity(const XMLString* publicId, const XMLString& systemId) override {
        // 自定义实体处理逻辑,比如返回原始的实体字符串
        if (systemId == "my-custom-entity") {
            return new InputSource("&my-custom-entity;");
        }
        return nullptr; // 让解析器使用默认处理
    }
};

class CustomContentHandler : public ContentHandler {
    // 实现必要的ContentHandler方法...
    void characters(const XMLChar ch[], int start, int length) override {
        std::string text(ch + start, length);
        std::cout << "Characters: " << text << "\n";
    }
    // 其他方法(startDocument、endDocument等)可以留空或简单实现
    void startDocument() override {}
    void endDocument() override {}
    void startElement(const XMLString& uri, const XMLString& localName, const XMLString& qName, const Attributes& attrs) override {}
    void endElement(const XMLString& uri, const XMLString& localName, const XMLString& qName) override {}
};

int main() {
    SAXParser parser;
    CustomContentHandler handler;
    CustomEntityResolver resolver;
    parser.setContentHandler(&handler);
    parser.setEntityResolver(&resolver);
    
    std::string xml = "<root>&my-custom-entity;</root>";
    InputSource input(xml);
    try {
        parser.parse(input);
    } catch (SAXException& e) {
        std::cerr << "Error: " << e.what() << "\n";
    }
    return 0;
}

总结

如果你需要保留预定义实体的原始编码形式,方案一的XMLTokenizer是最可靠的选择,因为它直接在底层捕获token,不会自动解码实体引用。标准SAX解析器的ContentHandler回调拿到的都是解码后的字符,这是规范要求的,无法通过简单配置改变。

内容的提问来源于stack exchange,提问作者Takoua

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:22:09