使用Boost读写XML文件


71

使用Boost来读写XML文件有什么好的方法(也是一种简单的方法)?

我似乎找不到任何简单的示例来使用Boost读取XML文件。您能指出一个使用Boost读写XML文件的简单示例吗?

如果没有Boost,是否有任何您可以推荐的良好简单的库来读写XML文件?(必须是C ++库)


4
尝试Boost.PropertyTree。您可以在此处找到有关使用它读写XML文件的简短介绍。
Andrzej 2014年

Answers:


64

您应该尝试pugixml C ++的轻量,简单和快速的XML解析器

pugixml最好的东西是TinyXML和RapidXML缺少的XPath支持。

引用RapidXML的作者“我要感谢Arseny Kapoulkine在pugixml上所做的工作,这是该项目的灵感”,并且“比我知道的最快的XML解析器pugixml快5%-30%”,他已针对0.3版进行了测试的pugixml版本,最近已经达到0.42版。

以下是pugixml文档的摘录:

主要特点是:

  • 低内存消耗和碎片化(pugxml的获胜率约为1.3倍,TinyXML约为2.5倍,Xerces(DOM)约为4.3倍1)。确切数字可以在“与现有解析器比较”部分中看到。
  • 极高的解析速度(胜过pugxml的约6倍,TinyXML的约10倍,Xerces-DOM的约17.6倍1
  • 极高的解析速度(嗯,我重复一遍,但是速度如此之快,以至于在测试XML上它的表现比Expat快2.8倍)2
  • 或多或少符合标准(除DTD相关问题外,它将正确解析任何符合标准的文件)
  • 几乎是无知的错误(它不会像expat那样使您和我一样窒息;它将以错误的编码解析具有数据的文件;依此类推)
  • 干净的接口(一个严重重构的pugxml的接口)
  • 或多或少地支持Unicode(实际上,它假定输入数据为UTF-8编码,尽管它可以很容易地与ANSI一起使用-暂时没有UTF-16(请参阅将来的工作),并带有辅助转换功能(UTF-8 <- > UTF-16 / 32(无论std :: wstring和wchar_t的默认值是什么)
  • 完全符合标准的C ++代码(由Comeau严格模式批准);该库是多平台的(请参阅平台列表的参考)
  • 高灵活性。您可以通过解析选项控制文件解析和DOM树构建的许多方面。

好吧,你可能会问-有什么收获?一切都很可爱-它是用于解析XML的小型,快速,健壮,简洁的解决方案。什么东西少了?好的,我们是公平的开发人员-这是功能不全的清单:

  • 内存消耗。它击败了我所知道的每个基于DOM的解析器-但是当SAX解析器出现时,就没有机会了。您无法处理内存少于4 Gb的2 Gb XML文件-并且要快速完成。尽管pugixml的表现要好于其他所有基于DOM的解析器,所以如果您对DOM有所了解,这不是问题。
  • 内存消耗。好,我再说一遍。再次。当其他解析器允许您在恒定存储中(甚至作为内存映射区域)提供XML文件时,pugixml不会。因此,您必须将整个数据复制到非恒定存储中。此外,它应该在解析器的生存期内保持不变(有关生存期的原因以及更多有关生存期的信息,请参见下文)。同样,如果您对DOM没问题,那应该不成问题,因为总体内存消耗较少(虽然,您需要连续的内存块,但这可能是个问题)。
  • 缺乏验证,DTD处理,XML名称空间,正确的编码处理。如果您需要这些-请使用MSXML或XercesC或类似的东西。

pugixml现在具有UTF-8,UTF-16,UTF-32解析。
布伦特阿里亚斯

@CristianAdam我不知道它是否支持SAX解析还是不...。我认为是可以的,因为您说它无法处理内存少于4GiB的2GiB XML文件。
基里尔'04

TinyXpath确实向TinyXML添加了xpath支持
Aman Aggarwal

@fizzbuzz是的,但是根据TinyXPath文档,“在Linux下,还没有库”。只有命令行工具。
Scott Deerwester

pugixml很好,但这不能回答有关Boost的问题吗?
阿德里安·梅尔



13

Boost页面如何填充属性树中的XML解析器一章所述使用RapidXML

不幸的是,在撰写本文时,Boost中还没有XML解析器。因此,该库包含快速而纤巧的RapidXML解析器(当前版本为1.13),以提供XML解析支持。RapidXML不完全支持XML标准。它无法解析DTD,因此无法进行完整的实体替换。

另请参阅XML boost教程

由于OP需要一种“使用boost读取和写入xml文件的简单方法”,因此我在下面提供了一个非常基本的示例:

<main>
    <owner>Matt</owner>
    <cats>
        <cat>Scarface Max</cat>
        <cat>Moose</cat>
        <cat>Snowball</cat>
        <cat>Powerball</cat>
        <cat>Miss Pudge</cat>
        <cat>Needlenose</cat>
        <cat>Sweety Pie</cat>
        <cat>Peacey</cat>
        <cat>Funnyface</cat>
    </cats>
</main>

(猫名来自Matt Mahoney的主页

C ++中的相应结构:

struct Catowner
{
    std::string           owner;
    std::set<std::string> cats;
};

read_xml() 用法:

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

Catowner load(const std::string &file)
{
    boost::property_tree::ptree pt;
    read_xml(file, pt);

    Catowner co;

    co.owner = pt.get<std::string>("main.owner");

    BOOST_FOREACH(
       boost::property_tree::ptree::value_type &v,
       pt.get_child("main.cats"))
       co.cats.insert(v.second.data());

    return co;
}

write_xml() 用法:

void save(const Catowner &co, const std::string &file)
{
   boost::property_tree::ptree pt;

   pt.put("main.owner", co.owner);

   BOOST_FOREACH(
      const std::string &name, co.cats)
      pt.add("main.cats.cat", name);

   write_xml(file, pt);
}


4

好吧,boost中没有用于XML解析的特定库,但是有很多替代方法,这里有几个: libxmlXercesExpat

当然,您可以使用boost中的其他一些库来帮助您创建自己的库,但这可能是一项艰巨的任务。

这里是整个文章由IBM的主题。


4

Boost不提供XML解析器atm。

Poco XML(Poco C ++库的一部分)既好又简单。


我无法评论Poco C ++库的质量,但是从风格上讲,它与Boost完全不同。对于想要与其他Boost组件和STL良好互操作的人来说,这可能不是一个很好的选择。我不是在指代命名约定(尽管它们可能会让人讨厌)。而是大量使用继承,虚函数以及缺少字符类型的模板。这些设计决策可能会更好,也可能不会更好。但它们肯定与Boost和STL完全不同。
理查德·史密斯


3

如果仅在寻找DOM功能,那么此线程中已经有一些建议。我个人可能不会对缺少XPath支持的库感到困扰,并且在C ++中将使用Qt。还有TinyXPath,Arabica声称具有XPath支持,但是我对此一无所知。


2

从我潜伏在Boost邮件列表中的经验来看,似乎每当XML成为主题时,它就会被转移到有关Unicode的讨论中。但是,由于目前可能会出现Unicode库,因此我认为XML库在那里出现不会花费太长时间。

同时,我也一直在使用TinyXML。

关于RapidXML的有趣链接。我来看一下。



2

一个警告。我喜欢RapidXML,但是在解析UTF16时有一个非常讨厌的错误。一些有效值导致它崩溃。

我想推荐pugixml-但它缺少名称空间支持,我知道这会给我带来麻烦。


1
嗨,我已经尝试过pugixml,并且该库中的最大问题(当然对我来说)是缺少一些将模式转换为C ++的工具,因此我回到“繁琐的xerces :)并与此一起使用有趣的是codeynthesis.com/projects/xsd
Nuno


1
<?xml version="1.0"?>
<Settings>
  <GroupA>
      <One>4</One>
      <Two>7</Two>
      <Three>9</Three> 
  </GroupA>
  <GroupA>
      <One>454</One>
      <Two>47</Two>
      <Three>29</Three> 
  </GroupA>
  <GroupB>
      <A>String A</A>
      <B>String B</B>  
  </GroupB>  
</Settings>

有一种使用BOOST读取XML的简单方法。这个例子是与std :: wstring:

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

bool CMyClass::ReadXML(std::wstring &full_path)
{
    using boost::property_tree::wptree;

    // Populate tree structure pt:
    wptree pt;
    std::wstringstream ss; ss << load_text_file(full_path); // See below for ref.
    read_xml(ss, pt);

    // Traverse pt:
    BOOST_FOREACH(wptree::value_type const& v, pt.get_child(L"Settings"))
    {
        if (v.first == L"GroupA")
        {
            unsigned int n1 = v.second.get<unsigned int>(L"One");
            unsigned int n2 = v.second.get<unsigned int>(L"Two");
            unsigned int n3= v.second.get<unsigned int>(L"Three");
        }
        else if (v.first == L"GroupB")
        {
            std::wstring wstrA = v.second.get<std::wstring>(L"A");
            std::wstring wstrB = v.second.get<std::wstring>(L"B");
        }
    };
}

读取属性稍微复杂一点。

--

仅供参考:

std::wstring load_text_file(std::wstring &full_path)
{
    std::wifstream wif(full_path);

    wif.seekg(0, std::ios::end);
    buffer.resize(wif.tellg());
    wif.seekg(0);
    wif.read(buffer.data(), buffer.size());

    return buffer;
}

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.