在C++中生成XML的最简单方法是什么?

17

我使用了boost序列化,但似乎无法生成符合特定模式的XML -- 它的目的似乎仅仅是持久化一个类的状态。

平台:Linux

你们用什么来生成而不是解析XML?

到目前为止,我走了Foredecker的路线,自己生成它 -- 这不是一个很大的文档,但我真的不应该在找到正确的库来生成它方面遇到这么多麻烦。

至于Boost,我想要能够设置节点名称,设置节点属性,并摆脱所有无关的东西,因为我其实并不关心将我的文档放回那个类中。


我使用了libxml++来生成XML,但我不能保证这是最简单的方法! :-) - activout.se
6个回答

51

我最近审查了一堆用于生成XML代码的XML库。

总结一下:我选择了TinyXML++

TinyXML++具有良好的C++语法,基于成熟的TinyXML C库构建,是免费且开源(MIT许可证),而且很小。简而言之,它可以快速完成工作。以下是一个快速示例:

Document doc;
Node* root(doc.InsertEndChild(Element("RootNode")));
Element measurements("measurements");
Element tbr("TotalBytesReceived",  12);
measurements.InsertEndChild(tbr);
root->InsertEndChild(measurements);

生成如下:

<RootNode>
    <measurements>
        <TotalBytesReceived>12</TotalBytesReceived>
    </measurements>
</RootNode>

我一直对它非常满意。

我审核了很多其他库,以下是一些更好的选择:

Xerces:最强大的库。它可以 做任何事情(尤其是与Xalan组合使用时),但是它很庞大,需要用户自行管理内存。

RapidXML:用于解析的速度 非常快,但是由于添加节点到DOM需要进行内存管理,因此不适用于生成。

Boost.XML(提议):看起来非常 - 强大、优秀的C++语法。但它尚未经过审查过程,没有官方支持,可能会改变接口。我差点就用了这个库,期待它被纳入Boost。

Libxml++):非常好;功能强大,语法不错。但如果你只是在生成XML,它会有点大,而且它与glibmm库(用于ustring)捆绑在一起。如果我们只使用Linux(像你一样?),我会认真考虑这个库。

XiMOL:独特的基于流的库。对于我们的需求来说,这个库有点过于简单了,但是对于基本的XML生成,你可能会发现它非常有用。其流语法非常简洁。

希望这些内容对你有所帮助!


看了一下TinyXML++的问题页面,似乎它存在一些内存泄漏问题。你有遇到过吗? - metal
@mlimber 我经常使用它,但我只用它处理相对较小的文档,目前还没有出现问题。 - Jim Jeffries
5
看着最内层的元素,我怀疑输出和代码不匹配。 :-) - Christoph Wurm
只是一个小提示:在使用TinyXML之后,我发现了pugiXML。对于我来说,内存非常重要,因为我正在解析巨大的XML树。我快速比较了一下800MB的XML文件。TinyXML需要9.5GB(!)的内存来解析它,而pugiXML只需要大约3.5GB。 - Szak1

13

有些人可能会认为我是XML异端,但一种有效的方法是使用您喜欢的字符串输出工具(print、输出流等)来生成它 - 这可以写入缓冲区或文件。

保存后,您应该在提交或发送之前使用模式进行验证。

对于我们的一个项目,我们有一组非常简单的模板来管理开始/结束标记和属性。每个模板都有一个流输出运算符。这使得生成源XML和调试非常容易。这使得XML生成代码的结构看起来非常像XML本身。

其中一个优点是,如果流式传输到文件,则可以高效地生成大量XML。您稍后将支付验证成本(可能是昂贵操作的更好时间)。

这种技术的缺点是它基本上只能输出。它不适用于动态创建然后消耗XML。


1
非常感谢!我在过去的2-3个小时里搜遍了互联网、新闻组、IRC等,但在过去的20分钟内,我使用这种方法构建了一个生成器,它正是我需要做的事情——虽然不完美,需要进一步改进,但它确实可行。谢谢! - eyberg
5
是的,异端者! ;) 但是认真地说,我建议不要选择这条路 - 有很多库可以帮助你,在XML中避免犯错误。 - MattyT
嗯,我已经多年自己生成XML而没有问题。像Foredecker一样,我们的XML相对简单,但可能比他所说的更复杂。 - Rob
3
我本能地同意这个答案,但你可能最终需要转义一些内容。“and”和“&”对于大多数情况已经足够了,但如果你的数据足够复杂,你最终可能会编写半个通用XML输出生成器... - Edmund

10

Boost.PropertyTree 是一种很好的且直接的生成XML的方式,特别是当你已经在使用Boost时。

以下是一个完整的示例程序:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

using boost::property_tree::ptree;
using boost::property_tree::write_xml;
using boost::property_tree::xml_writer_settings;

int wmain(int argc, wchar_t* argv[]) {
    char* titles[] = {"And Then There Were None", "Android Games", "The Lord of the Rings"};

    ptree tree;
    tree.add("library.<xmlattr>.version", "1.0");
    for (int i = 0; i < 3; i++) {
        ptree& book = tree.add("library.books.book", "");
        book.add("title", titles[i]);
        book.add("<xmlattr>.id", i);
        book.add("pageCount", (i+1) * 234);
    }

    // Note that starting with Boost 1.56, the template argument must be std::string
    // instead of char
    write_xml("C:\\Users\\Daniel\\Desktop\\test.xml", tree,
        std::locale(),
        xml_writer_settings<char>(' ', 4));

    return 0;
}

生成的XML如下:

<?xml version="1.0" encoding="utf-8"?>
<library version="1.0">
    <books>
        <book id="0">
            <title>And Then There Were None</title>
            <pageCount>234</pageCount>
        </book>
        <book id="1">
            <title>Android Games</title>
            <pageCount>468</pageCount>
        </book>
        <book id="2">
            <title>The Lord of the Rings</title>
            <pageCount>702</pageCount>
        </book>
    </books>
</library>

特别好的一点是使用点分隔路径可以隐式地创建所有节点。文档相对较少,但结合 ptree.hpp 应该可以让你了解它是如何工作的。documentation


0

使用哪个平台? 在Windows上,MSXML是一个选项。 CMarkup是另一个不错的选择。 如果可以使用.NET,它具有出色的XML支持。


CMarkup也可以在没有.Net的情况下工作。您可以构建它以使用std :: string或MFC CString。如果这是一个问题,它确实会在内存中构建整个文档。 - Martin Beckett

0

我实际上还没有尝试使用boost序列化来做这件事,但据我了解,如果你非常小心地选择选项,你可以在模式中设置许多不同的选项(例如防止指针飞行权并为某些类型设置元素名称)


0

我使用tinyXml++,它使得像上面发布的那样创建xml非常容易。它还可以通过一个命令将其保存到文件中,但我找不到如何将其保存到缓冲区。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接