Xerces 3.2中XMLString::transcode处理特殊字符失效问题排查
Xerces 3.2.3 XMLCh转char*输出全0问题分析与替代方案
问题原因分析
- 转码器初始化异常:配置Iconv作为转码器后,若未在
XMLPlatformUtils::Initialize()阶段正确指定Iconv转码器,或未设置XERCES_TRANSCODER=Iconv环境变量,Xerces会 fallback 到默认转码逻辑,可能导致转码失败输出全0。 - XMLCh*本身无效:从XML节点获取属性时如果出错(比如节点不存在、属性名拼写错误),拿到的XMLCh*是空指针或未初始化内存,转码后自然无有效内容。
- 内存管理错误:
XMLString::transcode返回的是动态分配的char*,如果转码后未检查返回值就直接操作,或者提前释放了内存,会导致输出全0。 - 编码匹配问题:Iconv转码器需要明确源编码(Xerces的XMLCh是UTF-16BE),如果配置时源编码错误,也会导致转码失败。
替代实现方案(无需XMLString::transcode)
方案1:直接用Xerces原生API输出XML
如果需求是输出XML内容,完全不需要转成char*,用Xerces的DOMLSSerializer可直接处理编码和特殊字符:
#include <xercesc/dom/DOMImplementationLS.hpp> #include <xercesc/dom/DOMLSSerializer.hpp> #include <fstream> // 初始化Xerces(已执行过可跳过) XMLPlatformUtils::Initialize(); // 获取DOM实现与序列化器 DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(XMLString::transcode("LS")); DOMLSSerializer* serializer = ((DOMImplementationLS*)impl)->createLSSerializer(); DOMLSOutput* output = ((DOMImplementationLS*)impl)->createLSOutput(); // 设置输出编码为UTF-8 XMLCh* utf8Enc = XMLString::transcode("UTF-8"); output->setEncoding(utf8Enc); XMLString::release(&utf8Enc); // 输出到文件 std::ofstream outFile("result.xml"); output->setByteStream(new xercesc::StdOutFormatTarget(outFile.rdbuf())); serializer->write(yourDOMDocument, output); // 释放资源 serializer->release(); output->release(); XMLPlatformUtils::Terminate();
方案2:手动封装Iconv转码逻辑
自己实现XMLCh到UTF-8的转码,完全不依赖Xerces的transcode:
#include <iconv.h> #include <string> #include <xercesc/util/XMLString.hpp> std::string xmlch_to_utf8(const XMLCh* xmlchStr) { if (!xmlchStr) return ""; size_t inLen = xercesc::XMLString::stringLen(xmlchStr) * sizeof(XMLCh); size_t outBufSize = inLen * 4; // 预留足够的UTF-8转换空间 char* outBuf = new char[outBufSize]; char* outPtr = outBuf; const char* inPtr = reinterpret_cast<const char*>(xmlchStr); // 打开Iconv转码器:源编码UTF-16BE(Xerces默认XMLCh编码),目标编码UTF-8 iconv_t cd = iconv_open("UTF-8", "UTF-16BE"); if (cd == (iconv_t)-1) { delete[] outBuf; return ""; } // 执行转码 iconv(cd, const_cast<char**>(&inPtr), &inLen, &outPtr, &outBufSize); iconv_close(cd); std::string result(outBuf, outPtr - outBuf); delete[] outBuf; return result; }
方案3:利用C++标准库的宽字符转换
如果项目支持C++11及以上,可以用<codecvt>实现转换:
#include <string> #include <codecvt> #include <xercesc/util/XMLString.hpp> std::string xmlch_to_utf8(const XMLCh* xmlchStr) { if (!xmlchStr) return ""; // XMLCh是unsigned short,直接转成wstring std::wstring wideStr(reinterpret_cast<const wchar_t*>(xmlchStr)); // 宽字符串转UTF-8 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.to_bytes(wideStr); }
注意:部分旧编译器可能不支持<codecvt>,需要确认编译环境兼容性。
内容的提问来源于stack exchange,提问作者Samikaze
相关产品推荐
相关产品推荐

