我有需要解析的XML文档和/或需要构建XML文档并将其写入文本(文件或内存)。由于C ++标准库没有为此提供的库,我应该使用什么?
注意:这旨在作为对此的权威性C ++-FAQ式问题。是的,它是其他人的副本。我并没有简单地提出其他问题,因为它们倾向于要求一些更具体的内容。这个问题比较笼统。
我有需要解析的XML文档和/或需要构建XML文档并将其写入文本(文件或内存)。由于C ++标准库没有为此提供的库,我应该使用什么?
注意:这旨在作为对此的权威性C ++-FAQ式问题。是的,它是其他人的副本。我并没有简单地提出其他问题,因为它们倾向于要求一些更具体的内容。这个问题比较笼统。
Answers:
就像标准库容器一样,应使用哪种库取决于您的需求。这是一个方便的流程图:
所以第一个问题是:您需要什么?
好的,因此您需要处理XML。不是玩具XML,而是真正的 XML。您需要能够读取和写入所有 XML规范,而不仅仅是底层的,易于解析的位。您需要命名空间,DocType,实体替换,工程。完整的W3C XML规范。
下一个问题是:您的API是否需要符合DOM或SAX?
好的,因此您确实需要API为DOM和/或SAX。它不仅可以是SAX样式的推式解析器,也可以是DOM样式的保留解析器。在C ++允许的范围内,它必须是实际的DOM或实际的SAX。
你已经选择:
那是你的选择。它几乎是唯一具有完全(或尽可能接近C ++允许)DOM和SAX一致性的C ++ XML解析器/编写器。它还具有XInclude支持,XML Schema支持以及许多其他功能。
它没有真正的依赖性。它使用Apache许可证。
你已经选择:
LibXML2提供了一个C样式的接口(如果确实让您感到困扰,请使用Xerces),尽管该接口至少在某种程度上是基于对象的并且易于包装。它提供了许多功能,例如XInclude支持(带有回调,以便您可以告诉它从何处获取文件),XPath 1.0识别器,RelaxNG和Schematron支持(尽管错误消息还有很多不足之处),以及等等。
它确实对iconv有依赖性,但是可以在没有该依赖性的情况下进行配置。虽然这确实意味着您可以解析的文本编码可能会更加有限。
它使用MIT许可证。
好的,因此完全符合XML对您而言无关紧要。您的XML文档完全处于您的控制之下,或者保证使用XML的“基本子集”:没有名称空间,实体等。
那对你有什么关系呢?下一个问题是:在您的XML工作中,最重要的是什么?
您的应用程序需要采用XML并将其尽快转换为C ++数据结构。
你已经选择:
这个XML解析器恰好就是它所说的:快速XML。它甚至不处理将文件拉入内存的过程。如何进行取决于您。它所处理的是将其解析为可以访问的一系列C ++数据结构。它的执行速度与逐字节扫描文件的速度一样快。
当然,没有免费的午餐。像大多数不关心XML规范的XML解析器一样,Rapid XML不会涉及名称空间,DocType,实体(字符实体和6个基本XML实体除外)等等。所以基本上是节点,元素,属性等等。
另外,它是DOM样式的解析器。因此,它确实要求您阅读所有文本。但是,它不执行任何操作(通常是复制任何文本)。RapidXML获得大部分速度的方法是指的字符串原地。这需要您进行更多的内存管理(在RapidXML查看字符串时,必须保持该字符串处于活动状态)。
RapidXML的DOM是准系统。您可以获取事物的字符串值。您可以按名称搜索属性。就是这样 没有方便的功能可以将属性转换为其他值(数字,日期等)。您只是得到字符串。
RapidXML的另一个缺点是编写 XML 很麻烦。它要求您对字符串名称进行大量的显式内存分配,以构建其DOM。它确实提供了一种字符串缓冲区,但这仍然需要大量的显式工作。它当然是功能性的,但是使用起来很麻烦。
它使用MIT许可证。它是没有依赖项的仅标头库。
是的,性能对您很重要。但是也许您需要的东西少一些。也许可以处理更多Unicode的东西,或者不需要太多用户控制的内存管理。性能仍然很重要,但是您需要一些不太直接的东西。
你已经选择:
从历史上看,这是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)发行。
它是StAX风格的API的实现。它是一个拉式解析器,类似于LibXML2的xmlReader
解析器。
但是自2005年以来就没有进行过更新。同样,Caveat Emptor也是如此。
XPath是用于查询XML树中元素的系统。这是一种使用标准化语法通过通用属性有效命名元素或元素集合的便捷方法。许多XML库都提供XPath支持。
实际上,这里有三个选择:
因此,您不必担心XML的正确性。性能对您来说不是问题。流无关紧要。所有你想要的是什么是得到XML到内存中,并允许你再坚持它放回盘。什么,你关心的是API。
您想要一个XML解析器,它要小,易于安装,使用琐碎并且小到与最终可执行文件的大小无关。
你已经选择:
我将TinyXML放在此插槽中是因为它就像XML解析器一样容易使用。是的,它很慢,但是很简单明显。它具有许多用于转换属性等的便利功能。
在TinyXML中编写XML没问题。您只需new
将一些对象放在一起,将它们附加在一起,然后将文档发送到即可std::ostream
,每个人都很高兴。
还有一个围绕TinyXML构建的生态系统,它具有对迭代器更友好的API,甚至在其之上都分层了XPath 1.0实现。
TinyXML使用zLib许可证,该许可证或多或少是MIT许可证,但名称不同。
您可能要考虑另一种处理XML的方法,称为XML数据绑定。特别是如果您已经有了XML词汇表的正式规范,例如在XML Schema中。
XML数据绑定使您可以使用XML,而无需实际进行任何XML解析或序列化。数据绑定编译器自动生成所有低级代码,并将解析后的数据显示为与您的应用程序域相对应的C ++类。然后,您可以通过调用函数并使用C ++类型(int,double等)来处理这些数据,而不是比较字符串和解析文本(这是使用低级XML访问API(例如DOM或SAX)进行的操作)。
例如,请参阅我编写的开源XML数据绑定实现 CodeSynthesis XSD,以及重量更轻,无依赖的版本CodeSynthesis XSD / e。
放我的。
http://www.codeproject.com/Articles/998388/XMLplusplus-version-The-Cplusplus-update-of-my-XML
没有XML验证功能,但速度很快。
好吧。我创建了一个新的列表,因为没有一个列表不能满足我的需求。
优点:
缺点:
在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);