我应该在C ++中使用什么XML解析器?

时间:2012-02-22 00:44:51

标签: c++ xml-parsing c++-faq

我有需要解析的XML文档和/或我需要构建XML文档并将它们写入文本(文件或内存)。由于C ++标准库没有此库,我应该使用什么?

注意:这是一个明确的,C ++ - 常见问题解答风格的问题。所以,是的,它与其他人重复。我不是简单地适应其他问题,因为他们倾向于要求更具体的东西。这个问题更通用。

6 个答案:

答案 0 :(得分:623)

就像使用标准库容器一样,您应该使用哪个库取决于您的需求。这是一个方便的流程图:

enter image description here

所以第一个问题是:你需要什么?

我需要完全符合XML

好的,所以你需要处理XML。不是玩具XML,真正的 XML。您需要能够读取和编写XML规范的所有,而不仅仅是低位,易于解析的位。您需要命名空间,DocTypes,实体替换,工作。 W3C XML规范的全部内容。

接下来的问题是:您的API是否需要符合DOM或SAX?

我需要精确的DOM和/或SAX一致性

好的,所以你真的需要API是DOM和/或SAX。它不仅可以是SAX风格的推送解析器,也可以是DOM风格的保留解析器。它必须是实际的DOM或实际的SAX,达到C ++允许的程度。

您选择了:

<强> Xerces

这是您的选择。它几乎是唯一一个完全(或接近C ++允许)DOM和SAX一致性的C ++ XML解析器/编写器。它还具有XInclude支持,XML Schema支持以及许多其他功能。

它没有真正的依赖关系。它使用Apache许可证。

我不关心DOM和/或SAX一致性

您选择了:

<强> LibXML2

LibXML2提供了一个C风格的界面(如果真的困扰你,请使用Xerces),尽管界面至少有点基于对象并且很容易包装。它提供了很多功能,比如XInclude支持(带回调以便你可以告诉它从哪里获取文件),XPath 1.0识别器,RelaxNG和Schematron支持(尽管错误消息留下批次需要),等等。

它确实依赖于iconv,但可以在没有该依赖关系的情况下进行配置。虽然这确实意味着您可以解析更有限的一组可能的文本编码。

它使用MIT许可证。

我不需要完全符合XML

好的,所以完整的XML合规性对您来说并不重要。您的XML文档完全在您的控制之下,或者保证使用&#34;基本子集&#34; XML:没有命名空间,实体等。

那对你有什么影响?接下来的问题是:您的XML工作中最重要的是什么?

最大XML分析性能

您的应用程序需要采用XML并将其转换为C ++数据结构,因为这种转换可能会发生。

您选择了:

<强> RapidXML

这个XML解析器正如它所说的那样:快速XML。它甚至不会将文件拉入内存;怎么回事取决于你。它处理的是将其解析为一系列可以访问的C ++数据结构。它的执行速度与逐字节扫描文件的速度一样快。

当然,没有免费午餐这样的事情。像大多数不关心XML规范的XML解析器一样,Rapid XML不会触及命名空间,DocTypes,实体(字符实体和6个基本XML实例除外),等等。所以基本上是节点,元素,属性等。

此外,它是一个DOM风格的解析器。因此,它确实需要您阅读所有文本。但是,它没有做的是复制任何文本(通常)。 RapidXML获得大部分速度的方式是通过引用字符串就地。这需要您进行更多的内存管理(当RapidXML正在查看时,您必须保持该字符串处于活动状态)。

RapidXML的DOM很简陋。您可以获取事物的字符串值。您可以按名称搜索属性。这是关于它的。没有便利功能可以将属性转换为其他值(数字,日期等)。你只是得到了字符串。

RapidXML的另一个缺点是编写 XML很痛苦。它要求您为字符串名称进行大量显式内存分配以构建其DOM。它确实提供了一种字符串缓冲区,但是仍需要大量明确的工作。它确实很有用,但使用起来很痛苦。

它使用MIT许可证。它是一个只有头文件的库,没有依赖项。

我关心性能但不是很多

是的,性能对您很重要。但也许你需要一些不那么简单的东西。也许某些东西可以处理更多的Unicode,或者不需要这么多用户控制的内存管理。性能仍然很重要,但你想要的东西不那么直接。

您选择了:

<强> PugiXML

从历史上看,这是RapidXML的灵感来源。但这两个项目有所不同,Pugi提供了更多功能,而RapidXML完全专注于速度。

PugiXML提供Unicode转换支持,因此如果您有一些UTF-16文档,并希望将它们读作UTF-8,Pugi将提供。如果你需要那种东西,它甚至还有XPath 1.0实现。

但Pugi仍然很快。与RapidXML一样,它没有依赖关系,并且在MIT许可下分发。

阅读巨大的文件

您需要阅读以千兆字节大小测量的文档。也许你从stdin那里得到它们,被其他一些过程所吸引。或者你从大量文件中读取它们。管他呢。关键是,您需要的是 not 必须一次性将整个文件读入内存才能进行处理。

您选择了:

<强>的libxml2

Xerces的SAX风格API将以此身份运行,但LibXML2在这里是因为它更容易使用。 SAX风格的API是一个push-API:它开始解析一个流,然后触发你必须捕获的事件。您被迫管理上下文,状态等。读取SAX风格API的代码比人们希望的更为分散。

LibXML2的xmlReader对象是一个pull-API。您要求转到下一个XML节点或元素;你没有被告知。这允许您根据需要存储上下文,以便以比一堆回调更易读的方式处理不同的实体。

替代

<强> Expat

Expat是一个众所周知的C ++解析器,它使用了拉解析器API。它是由詹姆斯克拉克写的。

它的当前状态是有效的。最新版本是2.2.5,上个月发布(2017-10-31)。

<强> LlamaXML

它是StAX风格的API的实现。它是一个拉解析器,类似于LibXML2的xmlReader解析器。

但它自2005年以来一直没有更新。再次,Caveat Emptor。

XPath支持

XPath是一个用于查询XML树中元素的系统。使用标准化语法,通过公共属性有效地命名元素或元素集合是一种方便的方法。许多XML库都提供XPath支持。

这里有三种选择:

  • LibXML2 :它提供完整的XPath 1.0支持。同样,它是一个C API,所以如果这困扰你,还有其他选择。
  • PugiXML :它还支持XPath 1.0。如上所述,它比LibXML2更像是一个C ++ API,所以你可能会更熟悉它。
  • TinyXML :它没有XPath支持,但有 TinyXPath 库提供它。 TinyXML正在进行2.0版本的转换,这会显着改变API,因此TinyXPath可能无法使用新的API。与TinyXML本身一样,TinyXPath是在zLib许可下发布的。

完成工作

因此,您并不关心XML的正确性。性能对您来说不是问题。流媒体无关紧要。你想要的只是某些东西,它将XML带入内存并允许你再次将它重新粘贴到磁盘上。 关心的是API。

您希望XML解析器体积小,易于安装,使用起来微不足道,并且小到足以与最终可执行文件的大小无关。

您选择了:

<强> TinyXML

我把TinyXML放在这个插槽中,因为它就像XML解析器一样简单易用。是的,它很慢,但它很简单明了。它具有许多用于转换属性等的便利功能。

在TinyXML中编写XML没有问题。您只需new了一些对象,将它们连接在一起,将文档发送到std::ostream,每个人都很开心。

还有一些围绕TinyXML构建的生态系统,具有更加迭代器友好的API,甚至还有一个基于XPath 1.0的实现。

TinyXML使用zLib许可证,该许可证或多或少是具有不同名称的MIT许可证。

答案 1 :(得分:17)

您可能需要考虑另一种处理XML的方法,称为XML 数据绑定。特别是如果您已经有XML词汇表的正式规范,例如,在XML Schema中。

XML数据绑定允许您在不实际进行任何XML解析或序列化的情况下使用XML。数据绑定编译器自动生成所有低级代码,并将解析后的数据显示为与应用程序域对应的C ++类。然后,您可以通过调用函数,使用C ++类型(int,double等)来处理这些数据,而不是比较字符串和解析文本(这是您使用低级XML访问API(如DOM或SAX)执行的操作)。 / p>

例如,请参阅我编写的开源XML数据绑定实现, CodeSynthesis XSD和 轻量级,无依赖版本,CodeSynthesis XSD/e

答案 2 :(得分:0)

答案 3 :(得分:0)

Secured Globe,Inc。中,我们使用rapidxml。我们尝试了所有其他功能,但rapidxml似乎是我们的最佳选择。

以下是一个例子:

 rapidxml::xml_document<char> doc;
    doc.parse<0>(xmlData);
    rapidxml::xml_node<char>* root = doc.first_node();

    rapidxml::xml_node<char>* node_account = 0;
    if (GetNodeByElementName(root, "Account", &node_account) == true)
    {
        rapidxml::xml_node<char>* node_default = 0;
        if (GetNodeByElementName(node_account, "default", &node_default) == true)
        {
            swprintf(result, 100, L"%hs", node_default->value());
            free(xmlData);
            return true;
        }
    }
    free(xmlData);

答案 4 :(得分:0)

关于Expat的另一个注意事项:值得关注嵌入式系统的工作。但是,您可能在网络上找到的文档是古老而错误的。源代码实际上具有相当彻底的功能级别注释,但是需要对它们进行一些有意义的理解。

答案 5 :(得分:0)

好的。我已经创建了新的,因为没有一个列表不能满足我的需求。

优点:

  1. 在低级别(Java StAX like
  2. 上拉取解析器流式传输API
  3. 支持的例外和RTTI模式
  4. 限制内存使用,支持大文件(使用100 mib XMark file测试,速度取决于硬件)
  5. UNICODE支持,以及输入源编码的自动检测
  6. 用于阅读structures/POCO
  7. 的高级API
  8. 用于从structures/POCO编写和生成XSD的元编程API 支持xml结构(属性和嵌套标签)(XSD生成需要RTTI,但只能在调试时才能使用一次)
  9. C ++ 11 - GCC和VC ++ 15 +
  10. 缺点:

    1. 尚未提供DTD和XSD验证
    2. 正在进行的HTTP / HTTPS获取XML / XSD,尚未完成
    3. 新图书馆
    4. Project home