我应该在C ++中使用哪种XML解析器?[关闭]


344

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

注意:这旨在作为对此的权威性C ++-FAQ式问题。是的,它是其他人的副本。我并没有简单地提出其他问题,因为它们倾向于要求一些更具体的内容。这个问题比较笼统。


我喜欢tiCpp code.google.com/p/ticpp,文档还不错(还好吗?),但是我喜欢这个库,干净利落的代码。

我写了自己的github.com/igagis/mikroxml
igagis

Answers:


678

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

在此处输入图片说明

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

我需要完全符合XML

好的,因此您需要处理XML。不是玩具XML,而是真正的 XML。您需要能够读取和写入所有 XML规范,而不仅仅是底层的,易于解析的位。您需要命名空间,DocType,实体替换,工程。完整的W3C XML规范。

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

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

好的,因此您确实需要API为DOM和/或SAX。它不仅可以是SAX样式的推式解析器,也可以是DOM样式的保留解析器。在C ++允许的范围内,它必须是实际的DOM或实际的SAX。

你已经选择:

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文档完全处于您的控制之下,或者保证使用XML的“基本子集”:没有名称空间,实体等。

那对你有什么关系呢?下一个问题是:在您的XML工作中,最重要的什么?

最高的XML解析性能

您的应用程序需要采用XML并将其尽快转换为C ++数据结构。

你已经选择:

RapidXML

这个XML解析器恰好就是它所说的:快速XML。它甚至不处理将文件拉入内存的过程。如何进行取决于您。它所处理的是将其解析为可以访问的一系列C ++数据结构。它的执行速度与逐字节扫描文件的速度一样快。

当然,没有免费的午餐。像大多数不关心XML规范的XML解析器一样,Rapid XML不会涉及名称空间,DocType,实体(字符实体和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许可证进行分发。

阅读大量文件

您需要阅读以GB为单位的文档。也许您是从stdin那里获取它们的,可能是由其他过程提供的。或者您正在从海量文件中读取它们。管他呢。问题的关键是,你需要的是具备以处理它读取整个文件到内存中的一次。

你已经选择:

LibXML2

Xerces的SAX风格的API将以这种方式工作,但是LibXML2在这里是因为它使用起来更容易。SAX风格的API是推入API:它开始解析流,并仅触发您必须捕获的事件。您被迫管理上下文,状态等。读取SAX样式的API的代码比人们期望的要分散得多。

LibXML2的xmlReader对象是pull-API。您要求转到下一个XML节点或元素。你没有被告知。这样一来,您就可以根据需要存储上下文,从而以比一堆回调更具代码可读性的方式处理不同的实体。

备择方案

外籍人士

Expat是使用Pull-Parser API的著名C ++解析器。它是由詹姆斯·克拉克(James Clark)撰写的。

当前状态为有效。最新版本是2.2.9,已于(2019-09-25)发行。

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许可证,但名称不同。


6
这看起来有点像复制粘贴。您可以链接原始文档吗?
Joel 2012年

28
@Joel:很多时候,当某人回答一个很好的帖子时,这是因为他们遵循Jeff的建议精神-尤其是因为看起来像一个一般问题的问题通常可以在一个好的答案得到解决之前就关闭如果此人正在正确地写答案,则将其张贴。在他问问题之前,花了一些时间准备答复:) Nicol 将来为我们所有人提供了Close-> Duplicate问题的优秀候选人。
sarnold

28
@Joel:恐怕我做不到。这只是我在Notepad ++中复制的一个临时文档。我从未保存过它,所以无法将您链接到它;)
Nicol Bolas 2012年

6
可能值得一提的是TinyXML的更新版本:TinyXML-2使用与TinyXML-1类似的API和相同的丰富测试用例。但是解析器的实现已完全重写,使其更适合在游戏中使用。它使用较少的内存,速度更快,并且使用的内存分配很少。
johnbakers 2013年

6
我喜欢这个问题和答案,但是觉得它偏于Unix。没有提及MSXML和XmlLite?如果您将多平台可移植性排除在外,那么在问答中应明确提及。(否则,有些人最终可能会为例如Windows的项目选择例如Libxml2,这要求可以很容易避免的头痛问题。)
Scrontch 2013年

17

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

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

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


13
我不介意该帖子,但是SO政策指出,如果您建议自己写一些东西,那么为了全面披露,您应该提到您写了它。
Nicol Bolas'3

@Nicol我将其编辑为答案。
JBentley

此列表可能有用,但我无法确定该列表的作者是谁(没有公开披露,我看不到这些描述和等级是否有意义)。也许可以看一下W3C数据绑定工作组,该工作组列出了一些在公共领域中用于测试和报告的数据绑定工具(完整披露:我不隶属于CodeSynthesis,我已经帮助gsoap列出了W3C工具)。
RE博士

1

关于Expat的另一个注意事项:值得一看的嵌入式系统工作。但是,您可能会在网上找到的文档是古老而错误的。源代码实际上具有相当全面的功能级注释,但是要使它们有意义,将需要一些细读。



0

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

优点:

  1. 底层的Pull-parser Streaming API(类似于Java StAX
  2. 支持的异常和RTTI模式
  3. 内存使用限制,支持大文件(使用100 mib XMark文件进行测试,速度取决于硬件)
  4. 支持UNICODE,并自动检测输入源编码
  5. 用于读取结构/ POCO的高级API
  6. 元编程API,用于从结构/ POCO编写和生成XSD, 并支持xml结构(属性和嵌套标签)(XSD生成需要RTTI,但只能在调试时使用一次)
  7. C ++ 11-GCC和VC ++ 15+

缺点:

  1. 尚未提供DTD和XSD验证
  2. 正在通过HTTP / HTTPS获取XML / XSD,尚未完成
  3. 新图书馆

项目首页


1
您可以添加基准吗?
Vadim Peretokin

-1

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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.