如何在c++程序中使用TinyXml2解析xml文件

How to get xml file parsed using TinyXml2 in c++ program?

本文关键字:TinyXml2 解析 xml 文件 c++ 程序      更新时间:2023-10-16

我第一次使用TinyXml2获取xml文件,如下所示:

<ORDER>
<ITEM>
<SN>132487A-J</SN>
<NAME>crank casing</NAME>
<Person age="12" passed="Yes">Alive</Person>
<QTY>1</QTY>
</ITEM>
</ORDER>

那么,我如何在visual studio中从TinyXml2生成这种类型的xml呢?我在互联网上搜索过,但他们展示的例子非常冗长和复杂,难以理解。所以,请建议我在c++中使用小xml的简单代码片段,可以实现我的目的。

在喷子回答类别中:

注释我已经在这里添加了一个非喷子答案,因为我发现时间使用TinyXML

  1. Boost属性树

    Live On Coliru

    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/xml_parser.hpp>
    struct Person {
        int age;
        bool passed;
        enum Condition { Alive, Dead } condition;
        friend std::ostream& operator<<(std::ostream& os, Condition c) {
            switch (c) {
                case Alive : return os << "Alive";
                case Dead  : return os << "Dead";
            }
            throw "failure"; //TODO
        }
    };
    struct Order {
        struct Item {
            std::string serialnumber, name;
            Person person;
            int quantity;
        };
        std::vector<Item> items;
    };
    using Tree = boost::property_tree::ptree;
    Tree make_tree(Person const& p) {
        Tree pt;
        pt.put("<xmlattr>.age", p.age);
        pt.put("<xmlattr>.passed", p.passed?"Yes":"No");
        pt.put_value(p.condition);
        return pt;
    }
    Tree make_tree(Order::Item const& p) {
        Tree pt;
        pt.put("SN",     p.serialnumber);
        pt.put("NAME",   p.name);
        pt.put_child("Person", make_tree(p.person));
        pt.put("QTY",    p.quantity);
        return pt;
    }
    Tree make_tree(Order const& p) {
        Tree pt;
        Tree& order = pt.put_child("ORDER", {});
        for (auto& item : p.items)
            order.add_child("ITEM", make_tree(item));
        return pt;
    }
    #include <iostream>
    /*
     *  <ORDER>
     *    <ITEM>
     *      <SN>132487A-J</SN>
     *      <NAME>crank casing</NAME>
     *      <Person age="12" passed="Yes">Alive</Person>
     *      <QTY>1</QTY>
     *    </ITEM>
     *  </ORDER>
     *
     */
    int main() {
        Order const order {
            {
                Order::Item {
                    "132487A-J", "crank casing", 
                    Person { 12, true, Person::Alive },
                    1
                },
            }
        };
        using namespace boost::property_tree;
        auto settings = xml_parser::xml_writer_make_settings<std::string>(' ', 4, "utf-8");
        write_xml(std::cout, make_tree(order), settings);
    }
    

    打印

    <?xml version="1.0" encoding="utf-8"?>
    <ORDER>
        <ITEM>
            <SN>132487A-J</SN>
            <NAME>crank casing</NAME>
            <Person age="12" passed="Yes">Alive</Person>
            <QTY>1</QTY>
        </ITEM>
    </ORDER>
    

这里使用Pugi XML。我真的希望这能更方便用户使用。

注释我已经在这里添加了一个非喷子答案,因为我发现时间使用TinyXML

#include <pugixml.hpp>
#include <vector>
#include <iostream>
#include <sstream>
struct Person {
    int age;
    bool passed;
    enum Condition { Alive, Dead } condition;
    friend std::ostream& operator<<(std::ostream& os, Condition c) {
        switch (c) {
            case Alive : return os << "Alive";
            case Dead  : return os << "Dead";
        }
        throw "failure"; //TODO
    }
};
struct Order {
    struct Item {
        std::string serialnumber, name;
        Person person;
        int quantity;
    };
    std::vector<Item> items;
};
using Tree = pugi::xml_node;
Tree make_tree(Person const& p, pugi::xml_node parent) {
    auto pt = parent.append_child("Person");
    pt.append_attribute("age").set_value(p.age);
    pt.append_attribute("passed").set_value(p.passed?"Yes":"No");
    std::ostringstream oss;
    oss << p.condition;
    pt.append_child(pugi::node_pcdata).set_value(oss.str().c_str());
    return pt;
}
Tree make_tree(Order::Item const& p, pugi::xml_node parent) {
    auto pt = parent.append_child("ITEM");
    pt.append_child("SN").append_child(pugi::node_pcdata).set_value(p.serialnumber.c_str());
    pt.append_child("NAME").append_child(pugi::node_pcdata).set_value(p.name.c_str());
    make_tree(p.person, pt).set_name("Person");
    pt.append_child("QTY").set_value(std::to_string(p.quantity).c_str());
    return pt;
}
Tree make_tree(Order const& p, pugi::xml_node parent) {
    auto pt = parent.append_child("ORDER");
    for (auto& item : p.items)
        make_tree(item, pt);
    return pt;
}
#include <iostream>
/*
 *  <ORDER>
 *    <ITEM>
 *      <SN>132487A-J</SN>
 *      <NAME>crank casing</NAME>
 *      <Person age="12" passed="Yes">Alive</Person>
 *      <QTY>1</QTY>
 *    </ITEM>
 *  </ORDER>
 *
 */
int main() {
    Order const order {
        {
            Order::Item {
                "132487A-J", "crank casing", 
                Person { 12, true, Person::Alive },
                1
            },
        }
    };
    pugi::xml_document doc;
    make_tree(order, doc.append_child("ORDER"))
        .print(std::cout);
}

没有Live Demo,因为Coliru没有PugiXML。它打印:

<ORDER>
    <ITEM>
        <SN>132487A-J</SN>
        <NAME>crank casing</NAME>
        <Person age="12" passed="Yes">Alive</Person>
        <QTY />
    </ITEM>
</ORDER>

好的,因为您非常有耐心,而且因为我想第一次尝试TinyXml2,所以下面是:

#include <tinyxml2.h>
#include <vector>
#include <iostream>
#include <sstream>
struct Person {
    int age;
    bool passed;
    enum Condition { Alive, Dead } condition;
    friend std::ostream& operator<<(std::ostream& os, Condition c) {
        switch (c) {
            case Alive : return os << "Alive";
            case Dead  : return os << "Dead";
        }
        throw "failure"; //TODO
    }
};
struct Order {
    struct Item {
        std::string serialnumber, name;
        Person person;
        int quantity;
    };
    std::vector<Item> items;
};
using Tree = tinyxml2::XMLNode;
using Document = tinyxml2::XMLDocument;
Tree* make_tree(Person const& p, Document& doc) {
    auto pt = doc.NewElement("Person");
    pt->SetAttribute("age", p.age);
    pt->SetAttribute("passed", p.passed?"Yes":"No");
    std::ostringstream oss;
    oss << p.condition;
    pt->SetValue(oss.str().c_str());
    return pt;
}
Tree* make_tree(Order::Item const& p, Document& doc) {
    auto pt = doc.NewElement("ITEM");
    (pt->InsertEndChild(doc.NewElement("SN")))->InsertFirstChild(doc.NewText(p.serialnumber.c_str()));
    (pt->InsertEndChild(doc.NewElement("NAME")))->InsertFirstChild(doc.NewText(p.name.c_str()));
    pt->InsertEndChild(make_tree(p.person, doc));
    (pt->InsertEndChild(doc.NewElement("QTY")))->InsertFirstChild(doc.NewText(std::to_string(p.quantity).c_str()));
    return pt;
}
Tree* make_tree(Order const& p, Document& doc) {
    auto pt = doc.NewElement("ORDER");
    for (auto& item : p.items)
        pt->InsertEndChild(make_tree(item, doc));
    return pt;
}
#include <iostream>
/*
 *  <ORDER>
 *    <ITEM>
 *      <SN>132487A-J</SN>
 *      <NAME>crank casing</NAME>
 *      <Person age="12" passed="Yes">Alive</Person>
 *      <QTY>1</QTY>
 *    </ITEM>
 *  </ORDER>
 *
 */
int main() {
    Order const order {
        {
            Order::Item {
                "132487A-J", "crank casing", 
                Person { 12, true, Person::Alive },
                1
            },
        }
    };
    Document doc;
    doc.InsertFirstChild(make_tree(order, doc));
    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    std::cout << printer.CStr() << "n";
}

打印

<ORDER>
    <ITEM>
        <SN>132487A-J</SN>
        <NAME>crank casing</NAME>
        <Alive age="12" passed="Yes"/>
        <QTY>1</QTY>
    </ITEM>
</ORDER>