【问题标题】:Return node information during comparison比较时返回节点信息
【发布时间】:2015-06-20 10:51:27
【问题描述】:

我在编写这段代码时得到了一些帮助。目前,代码所做的是打印出文件中差异的 id 编号,即新的与旧的相比,添加、删除或保持不变。

但是我想要做的是返回节点中的信息,当它只出现在 new.xml 中时,而不仅仅是 ID(即标题、位置、日期)。

我能从谷歌找到的最好的猜测是使用(不知道如何实现):xpath->getAncestor

我当前的代码

#include <set>
#include <string>
#include <sstream>
#include <iostream>
#include <algorithm>

#include "include/pugixml.hpp"

#define con(m) std::cout << m << '\n'
#define err(m) std::cerr << m << std::endl

using str_set = std::set<std::string>;

int main()
{
    pugi::xml_document doc;

    str_set a;
    doc.load_file("old.xml");

    // fill set a with just the ids from file a
    for(auto&& node: doc.child("site_entries").children("entry"))
        a.emplace(node.child("id").text().as_string());

    str_set b;
    doc.load_file("new.xml");

    // fill set b with just the ids from file b
    for(auto&& node: doc.child("site_entries").children("entry"))
        b.emplace(node.child("id").text().as_string());

    // now use the <algorithms> library

    str_set b_from_a;
    std::set_difference(a.begin(), a.end(), b.begin(), b.end()
        , std::inserter(b_from_a, b_from_a.begin()));

    str_set a_from_b;
    std::set_difference(b.begin(), b.end(), a.begin(), a.end()
        , std::inserter(a_from_b, a_from_b.begin()));

    str_set a_and_b;
    std::set_intersection(a.begin(), a.end(), b.begin(), b.end()
        , std::inserter(a_and_b, a_and_b.begin()));

    for(auto&& v: a)
        con("a       : " << v);

    con("");

    for(auto&& v: b)
        con("b       : " << v);

    con("");

    for(auto&& v: b_from_a)
        con("b_from_a: " << v);

    con("");

    for(auto&& v: a_from_b)
        con("a_from_b: " << v);

    con("");

    for(auto&& v: a_and_b)
        con("a_and_b : " << v);

    con("");
}

这是一个示例 XML:

<?xml version="1.0" encoding="ISO-8859-1" ?> <site_entries> <entry> <id><![CDATA[946757316]]></id> <url><![CDATA[http://www.site.co.uk/cgi-bin/tr.cgi?tid=752276]]></url> <content><![CDATA[Specialized Dolce Sport 27 Speed]]></content> <title><![CDATA[Bike]]></title> <price><![CDATA[£600]]></price> <date><![CDATA[01-AUG-13]]></date> <display_reference><![CDATA[214683-50142933_370647]]></display_reference> <location><![CDATA[City of London]]></location> <category><![CDATA[Bike]]></category> </entry> <entry> <id><![CDATA[90007316]]></id> <url><![CDATA[http://www.site.co.uk/cgi-bin/tr.cgi?tid=70952276]]></url> <content><![CDATA[Giant Sport Offroad Bike]]></content> <title><![CDATA[Bike]]></title> <price><![CDATA[£100]]></price> <date><![CDATA[11-AUG-15]]></date> <display_reference><![CDATA[2146433-50142933_370647]]></display_reference> <location><![CDATA[City of London]]></location> <category><![CDATA[Bike]]></category> </entry> </site_entries>

我将获得数十万个总结果和数万个添加条目,因此我正在寻找实现这一目标的最有效方法。

【问题讨论】:

    标签: c++ xml xml-parsing pugixml


    【解决方案1】:

    您可以只将 xml_node 对象放入地图中 - 而不是 std::set&lt;std::string&gt; 使用 std::map&lt;std::string, pugi::xml_node&gt;。

    不过,对于您的情况,使用 unordered_map 可能/可能会更快。我会这样做:

    #include "pugixml.hpp"
    
    #include <iostream>
    #include <unordered_map>
    
    struct string_hasher
    {
        unsigned int operator()(const char* str) const
        {
            // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
            unsigned int result = 0;
    
            while (*str)
            {
                result += static_cast<unsigned int>(*str++);
                result += result << 10;
                result ^= result >> 6;
            }
    
            result += result << 3;
            result ^= result >> 11;
            result += result << 15;
    
            return result;
        }
    
        bool operator()(const char* lhs, const char* rhs) const
        {
            return strcmp(lhs, rhs) == 0;
        }
    };
    
    typedef std::unordered_map<const char*, pugi::xml_node, string_hasher, string_hasher> xml_node_map;
    
    int main()
    {
        pugi::xml_document doca, docb;
        xml_node_map mapa, mapb;
    
        if (!doca.load_file("a.xml") || !docb.load_file("b.xml"))
            return 1;
    
        for (auto& node: doca.child("site_entries").children("entry"))
            mapa[node.child_value("id")] = node;
    
        for (auto& node: docb.child("site_entries").children("entry"))
            mapb[node.child_value("id")] = node;
    
        for (auto& ea: mapa)
            if (mapb.count(ea.first) == 0)
            {
                std::cout << "Removed:" << std::endl;
                ea.second.print(std::cout);
            }
    
        for (auto& eb: mapb)
            if (mapa.count(eb.first) == 0)
            {
                std::cout << "Added:" << std::endl;
                eb.second.print(std::cout);
            }
    }
    

    与您的方法的显着差异:

    • unordered_map 可让您降低差异的复杂性 - 现在是 O(N+M),而不是 O(NlogN + MlogM)
    • C 字符串的自定义哈希避免分配不必要的内存

    当然,您可以使用std::unordered_map&lt;std::string, pugi::xml_node&gt; 进行简化 - 它可能会更慢,但更短。

    【讨论】:

    • 非常感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 2010-10-29
    相关资源
    最近更新 更多