在比较过程中返回节点信息



我在制作这段代码时得到了一些帮助。目前,代码所做的是打印出文件中差异的 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>

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

您可以将xml_node对象放入地图中 - 而不是std::set<std::string>使用 std::map<std::string, pugi::xml_node> .

不过,使用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<std::string, pugi::xml_node>进行简化 - 它可能更慢,但更短。

相关内容

  • 没有找到相关文章

最新更新