c++ - 比较时返回节点信息

标签 c++ xml xml-parsing pugixml

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

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

我可以从 Google 找到的最佳猜测是使用(不知道如何实现):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 对象放入 map 中 - 而不是 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 让您降低 diff 的复杂性 - 现在是 O(N+M),而不是 O(NlogN + MlogM)
  • C 字符串的自定义哈希器避免分配不必要的内存

当然你可以使用std::unordered_map<std::string, pugi::xml_node>来简化- 它可能会更慢,但更短。

关于c++ - 比较时返回节点信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29633937/

相关文章:

c++ - 热衷于不依赖 GNU Make 的依赖项的原子创建?

xml - 去哪里申请语言设计审查?

java - 使用 Java XPath 查询解析 XML,错误 :

java - urlrewritefilter 不重定向

c++ - 使用 std::map 时出现此错误。为什么?

c++ - DirectShow 手动图形内存泄漏

c++ - 任务管理器显示的线程比我创建的多

android - 删除所有语言的字符串 Android

java - Android:实现错误屏幕

ios - 停止/中止 NSURLConnection