C ++解析xml的子节点

时间:2016-08-21 18:05:32

标签: c++ xml parsing

那么我在这个开源游戏中再次工作,无论如何我为xml文件创建了这个解析器但是我不确定如何解析职业的子节点,这里是代码和函数的xml ,我希望能够遍历它的子节点,我假设我需要创建另一个for循环,但是我不太确定我应该如何引用vocation的子节点,我不关心它们的属性atm。

bool Game::loadCreatureAdditionalAttributes()
{
    pugi::xml_document data;
    pugi::xml_parse_result result = data.load_file("data/XML/attributes.xml");
    if (!result) {
        printXMLError("Error - Game::loadCreatureAdditionalAttributes", "data/XML/attributes.xml", result);
        return false;
    }
    bool attributesEnabled = false;
    for (auto attributeNode : data.child("attributes").children()) {
        if (strcasecmp(attributeNode.name(), "additionalAttributes") == 0) {
            if (attributeNode.attribute("enabled").as_bool()) {
                if (strcasecmp(attributeNode.name(), "vocation") == 0) {
                    pugi::xml_attribute vocation = attributeNode.attribute("id");
                    uint32_t aNode;
                    pugi::xml_attribute attr = attributeNode.attribute(attributeNode.name());
                    if (attr) {
                        aNode = pugi::cast<uint32_t>(attr.value());
                    }
                    else {
                        aNode = 0;
                    }
                    CreatureAttributes[pugi::cast<uint32_t>(vocation.value())][attributeNode.name()] = aNode;
                }
            }
        }
    }
    return true;
}

现在是xml

<?xml version="1.0" encoding="UTF-8"?>
<attributes>
    <additionalAttributes enabled = "0" />
    <vocation id = "1">
        <attribute stamina = "1" />
        <attribute strength = "1" />
        <attribute intelligence = "1" />
        <attribute dexterity = "1" />
        <attribute wisdom = "1" />
        <attribute luck = "1" />
        <attribute critical = "1" />
        <attribute block = "1" />
        <attribute experienceGain = "1" />
        <attribute power = "1" />
        <attribute precision = "1" />
    </vocation>
    <vocation id = "2">
        <attribute stamina = "1" />
        <attribute strength = "1" />
        <attribute intelligence = "1" />
        <attribute dexterity = "1" />
        <attribute wisdom = "1" />
        <attribute luck = "1" />
        <attribute critical = "1" />
        <attribute block = "1" />
        <attribute experienceGain = "1" />
        <attribute power = "1" />
        <attribute precision = "1" />
    </vocation>
</attributes>

编辑1:

Haven尚未对此进行测试,但我认为我会根据给出的答案显示更新。

bool Game::loadCreatureAdditionalAttributes()
{
    pugi::xml_document data;
    pugi::xml_parse_result result = data.load_file("data/XML/attributes.xml");
    if (!result) {
        printXMLError("Error - Game::loadCreatureAdditionalAttributes", "data/XML/attributes.xml", result);
        return false;
    }

    auto attr = data.child("attributes").child("additionalAttributes");
    bool attributesEnabled = attr.attribute("enabled").as_bool();

    if (attributesEnabled) {
        for (auto vocation : data.child("attributes").children("vocation")) {
            uint32_t id = pugi::cast<uint32_t>(vocation.attribute("id").value());
            for (auto attribute : vocation.children("attribute")) {
                for (auto& a : attribute.attributes()) {
                    CreatureAttributes[id][a.name()] = pugi::cast<uint32_t>(a.value());
                }
            }
        }
    }
    return true;
}

不完全确定孩子对孩子是否合法......但只是将它丢弃在那里lol

编辑2:

尚未对它进行测试,只是在它没有按预期工作的情况下更新它。

bool Game::loadCreatureAdditionalAttributes()
{
    pugi::xml_document data;
    pugi::xml_parse_result result = data.load_file("data/XML/attributes.xml");
    if (!result) {
        printXMLError("Error - Game::loadCreatureAdditionalAttributes", "data/XML/attributes.xml", result);
        return false;
    }

    auto attr = data.child("attributes").child("additionalAttributes");
    if (attr) {

        bool attributesEnabled = attr.attribute("enabled").as_bool();

        if (attributesEnabled) {
            for (auto vocation : data.child("attributes").children("vocation")) {
                uint32_t id = pugi::cast<uint32_t>(vocation.attribute("id").value());
                for (auto attribute : vocation.children("attribute")) {
                    for (auto& a : attribute.attributes()) {
                        CreatureAttributes[id][a.name()] = pugi::cast<uint32_t>(a.value());
                    }
                }
            }
            return true;
        }
    }
    return false;
}

只是想为那些有类似问题的人提供更新,代码效果很好!

vocation id = 1 attributes = stamina value = 1
vocation id = 1 attributes = strength value = 45
vocation id = 1 attributes = intelligence value = 1
vocation id = 1 attributes = dexterity value = 1
vocation id = 1 attributes = wisdom value = 63
vocation id = 1 attributes = luck value = 1
vocation id = 1 attributes = critical value = 1
vocation id = 1 attributes = block value = 1
vocation id = 1 attributes = experienceGain value = 1
vocation id = 1 attributes = power value = 81
vocation id = 1 attributes = precision value = 1
vocation id = 2 attributes = stamina value = 100
vocation id = 2 attributes = strength value = 1
vocation id = 2 attributes = intelligence value = 20
vocation id = 2 attributes = farfenugen value = 1
vocation id = 2 attributes = stackoverflow value = 1000

当然我更改了代码以使其与我正在处理的其他代码一起使用,但Edit 2中的示例代码可以在结构上类似的xml文件中正常工作。

1 个答案:

答案 0 :(得分:1)

我非常喜欢pugixml,这使解析变得非常简单。不过,您的XML格式有点棘手,我会考虑以不同方式存储您的<attributes>

目前,您可以像这样遍历 vocations 属性

#include <iostream>

#define PUGIXML_HEADER_ONLY
#include "pugixml.hpp"

auto xml = R"(
<?xml version="1.0" encoding="UTF-8"?>
<attributes>
    <additionalAttributes enabled = "0" />
    <vocation id = "1">
        <attribute stamina = "1" />
        <attribute strength = "1" />
        <attribute intelligence = "1" />
    </vocation>
    <vocation id = "2">
        <attribute stamina = "1" />
        <attribute strength = "1" />
        <attribute intelligence = "1" />
    </vocation>
</attributes>
)";

int main()
{
    pugi::xml_document doc;

    doc.load(xml);

    for(auto vocation: doc.child("attributes").children("vocation"))
    {
        std::cout << "vocation id:" << vocation.attribute("id").as_string() << '\n';

        for(auto attribute: vocation.children("attribute"))
        {
            for(auto& a: attribute.attributes())
            {
                std::cout << "    attribute: " << a.name() << '\n';
                std::cout << "             : " << a.value() << '\n';
            }
        }
    }
}

我可能会更像XML这样组织:

#include <iostream>

#define PUGIXML_HEADER_ONLY
#include "pugixml.hpp"

auto xml = R"(
<?xml version="1.0" encoding="UTF-8"?>
<attributes>
    <additionalAttributes enabled = "0" />
    <vocation id = "1">
        <stamina>1</stamina>
        <strength>1</strength>
        <intelligence>1</intelligence>
    </vocation>
    <vocation id = "2">
        <stamina>1</stamina>
        <strength>1</strength>
        <intelligence>1</intelligence>
    </vocation>
</attributes>
)";

int main()
{
    pugi::xml_document doc;

    doc.load(xml);

    for(auto vocation: doc.child("attributes").children("vocation"))
    {
        std::cout << "vocation id:" << vocation.attribute("id").as_string() << '\n';
        std::cout << "           : stamina = " << vocation.child("stamina").text().as_string() << '\n';
        std::cout << "           : strength = " << vocation.child("strength").text().as_string() << '\n';
        std::cout << "           : intelligence = " << vocation.child("intelligence").text().as_string() << '\n';
        std::cout << '\n';

    }
}