如何使用 RapidXML 读取 UTF-8 XML 并将其与 C++ 一起使用

How to read UTF-8 XML with RapidXML and use it with C++

我开发了一个 C++ 应用程序并实现了一个翻译器 class,它使用 XML 文件中的数据来翻译字符串。我现在遇到了一些特殊字符的严重问题,例如德国变音符号 ÖÄÜ...

在 Visual Studio 我在调试视图中看到以下内容,它读取以下示例字符串 "Dateiäüö":

由于这个问题,我在 Whosebug 上发现了这个 post: How to read Unicode XML values with rapidxml 并更改了我的 RapidXML class 以使用 wchar_t:

std::string RapidXMLParser::getValueUTF8(const std::string path)
{
    std::vector<std::string> tags = splitPath(path);
    rapidxml::file<wchar_t> xmlFile(filename.data());
    docUTF8.parse<0>(xmlFile.data());
    rapidxml::xml_node<wchar_t>* element = findElementUTF8(path);
    if (element)
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::wstring temp = element->value();
        std::string result = converter.to_bytes(temp);
        return result;
    }
    else
        return "";
}

但这并没有解决我的问题:

源 XML 文件已通过 UTF-8 验证程序检查,没有问题。如果我将编码更改为 ANSI,一切都适用于 Windows(但这不是解决方案!)。如果我在 Linux 上编译相同的代码,我得到带有变音符号的 ANSI 编码 XML 的空字符串和 UTF-8 编码的 XML...

的崩溃

该程序使用 wxwidgets 作为其界面,该菜单项呈现与调试器显示的字符相同的字符。在 Linux 上,空字符串会导致缺少菜单项或空行。

我希望有人对如何解决这个问题有很好的建议,或者对使用 XML 文件等可编辑数据源进行 UTF-8 翻译的替代方法提出建议。

编辑: 我的 XML 解析器可以在 RapidXML 和 TinyXML 之间切换。我也用 TinyXML 测试过这个,我遇到了同样的问题:

经过几个小时的努力解决这个问题,解决方案非常简单。 永远不要相信你的调试器!!!问题是由 wxwidgets 引起的...它显示的字符与我在调试器中看到的字符相同,但是如果我在呈现菜单之前将 utf8 转换为 utf16项目,它显示的字符串正确!

解决方案是不要在我的 XMLParser 中使用显示的 codecvt 代码,而是在输出之前的我的 wxwidgets 代码中使用。在 Linux 我现在遇到了问题,codecvt 不是 g++ 标准的一部分...但这是另一回事了。

天哪...我希望这对遇到类似问题的人有用。

我认为你的 findElementUTF8() 应该 return 一个 rapidxml::xml_node<char>*

rapidxml::xml_node<char>* element = findElementUTF8(path);

因为UTF8通常用char*表示。以下代码适用于 windows API 和 codecvt

  // äüö UTF8 encoded
  byte b8[] = { 0xc3, 0xa4, 0xc3, 0xbc, 0xc3, 0xb6, 0x00 };

  std::string sb8 = (char*)b8;

  wchar_t win_conv[16]{ 0 };
  MultiByteToWideChar(CP_UTF8, 0, (char*)b8, -1, win_conv, ARRAYSIZE(win_conv));

  std::wstring utf16_conv = std::wstring_convert<
    std::codecvt_utf8_utf16<wchar_t>>{}.from_bytes(sb8);

  assert(utf16_conv == win_conv);