【问题标题】:Should I use XPath or just DOM?我应该使用 XPath 还是只使用 DOM?
【发布时间】:2011-07-08 20:28:08
【问题描述】:

我有一堆分层数据存储在一个 XML 文件中。我正在使用 TinyXML 将其封装在手工制作的类后面。给定一个将源签名描述为一组(频率、级别)对的 XML 片段,有点像这样:

<source>
  <sig><freq>1000</freq><level>100</level><sig>
  <sig><freq>1200</freq><level>110</level><sig>
</source>

我正在用这个提取对:

std::vector< std::pair<double, double> > signature() const
{
    std::vector< std::pair<double, double> > sig;
    for (const TiXmlElement* sig_el = node()->FirstChildElement ("sig");
        sig_el;
        sig_el = sig_el->NextSiblingElement("sig"))
    {
        const double level = boost::lexical_cast<double> (sig_el->FirstChildElement("level")->GetText());
        const double freq =  boost::lexical_cast<double> (sig_el->FirstChildElement("freq")->GetText());
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

其中 node() 指向 &lt;source&gt; 节点。

问题:我是否会使用 XPath 库获得更整洁、更优雅、更易于维护或以任何其他方式更好的代码?

更新:我使用 TinyXPath 两种方式进行了尝试。它们都没有真正起作用,这显然对它们不利。我在做一些根本错误的事情吗?如果这就是 XPath 的样子,我认为它不会让我得到任何东西。

std::vector< std::pair<double, double> > signature2() const
{
    std::vector< std::pair<double, double> > sig;
    TinyXPath::xpath_processor source_proc (node(), "sig");
    const unsigned n_nodes = source_proc.u_compute_xpath_node_set();
    for (unsigned i = 0; i != n_nodes; ++i)
    {
        TiXmlNode* s = source_proc.XNp_get_xpath_node (i);
        const double level = TinyXPath::xpath_processor(s, "level/text()").d_compute_xpath();
        const double freq =  TinyXPath::xpath_processor(s, "freq/text()").d_compute_xpath();
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

std::vector< std::pair<double, double> > signature3() const
{
    std::vector< std::pair<double, double> > sig;
    int i = 1;
    while (TiXmlNode* s = TinyXPath::xpath_processor (node(), 
        ("sig[" + boost::lexical_cast<std::string>(i++) + "]/*").c_str()).
        XNp_get_xpath_node(0))
    {
        const double level = TinyXPath::xpath_processor(s, "level/text()").d_compute_xpath();
        const double freq =  TinyXPath::xpath_processor(s, "freq/text()").d_compute_xpath();
        sig.push_back (std::make_pair (freq, level));
    }
    return sig;
}

作为次要问题,如果是这样,我应该使用哪个 XPath 库?

【问题讨论】:

    标签: c++ xml xpath tinyxml


    【解决方案1】:

    XPath 就是为此而生的,所以如果你使用它,你的代码当然会“更好”。

    我不能推荐一个特定的 c++ XPath 库,但是即使在大多数情况下使用一个是正确的决定,在添加一个之前做一个成本/收益分析。也许YAGNI

    【讨论】:

      【解决方案2】:

      这个 XPath 表达式

      /*/sig[$pN]/*
      

      选择 XML 文档顶部元素的第 $pN 个 sig 子元素的所有子元素(仅一对 freqlevel)。

      字符串$pN应替换为特定的正整数,例如:

      /*/sig[2]/*
      

      选择这两个元素

      <freq>1200</freq><level>110</level>
      

      使用 XPath 表达式,因为这显然比提供的 C++ 代码更短且易于理解

      另一个优点是可以在 C# 或 Java 或 ... 程序中使用相同的 XPath 表达式,而无需以任何方式对其进行修改——因此遵守 XPath 的结果非常高便携程度。

      【讨论】:

      • 我可以看到 XPATH 表示法如何使描述节点变得简洁,但是当它被封装到 C++ API 中时,好处就变得不那么明显了。
      • @Pete:你为什么告诉我你不打算将所有 C++ 代码包装到一个函数中?所以你只有someObj.SelectNode('Expression')——好的软件工程原则是独立于语言的。
      • @Dimitre Novatchev:我不确定你在说什么。我试图将它包装到原始问题中给出的函数中,使用 XPath 会比没有使用更整洁吗?由于我缺乏 XPath 经验,在您的 SomeType something = someObj.SelectNode ("Expression") 中,我看不出 SomeType、someObj 或 Extpression 会有什么帮助。
      • @Pete:您为什么不阅读有关 SelectNodes() 和 SelectSingleNode() 方法的文档?这会给你一个好主意。另外,如果这两种方法已经实现了,为什么还要重新实现它们呢?
      • @Dimitre:我想我看到了困惑:TinyXPath 没有 SelectNodes 方法。我应该在哪里寻找有关这些方法的文档?我发现一些似乎适用于 JScript API 无论如何,如果我得到节点,我不是回到使用 DOM 方法从它们中获取内容吗?
      【解决方案3】:

      一般来说,我更喜欢基于 XPath 的解决方案,因为它们简洁且多功能,但老实说,在您的情况下,我认为使用 XPath 不会给您的signature 带来很多好处。

      原因如下:

      代码优雅
      您的代码既美观又紧凑,使用 XPath 表达式不会变得更好。

      内存占用
      除非您的输入 XML 配置文件很大(一种矛盾修饰法)并且 DOM 解析会占用大量内存,对此没有证据表明使用 XPath 会是一种决定性的治疗方法,否则我会坚持使用 DOM。

      执行速度
      在这样一个简单的 XML 树上,执行速度应该是相当的。 如果有区别,那可能是 TinyXml 的优势,因为freqlevel 标签在给定节点下的搭配。

      图书馆和外部参考这是决定性的一点。
      C++ 世界中领先的 XPath 引擎是 XQilla。 它支持 XQuery(因此同时支持 XPath 1.0 和 2.0)并得到 Oracle 的支持,因为它是由负责 Berkeley DB 产品(包括 Berkeley DB XML——使用 XQilla)的团队开发的。
      对于希望使用 XQilla 的 C++ 开发人员来说,问题在于他们有多种选择

      1. 使用 Xerces 2 和 XQilla 2.1 让您的代码使用强制转换。
      2. 使用 XQilla 2.2+ 并使用 Xerces 3(此处无需强制转换)
      3. 使用 TinyXPath 与 TinyXml 很好地集成,但 然而,它有许多限制(例如不支持命名空间)
      4. 混合 Xerces 和 tinyXml

      总而言之,在您的情况下,只是为了它而切换到 XPath,如果有的话,也不会带来什么好处。

      然而,XPath 是当今开发人员工具箱中非常强大的工具,没有人可以忽视它。 如果您只想练习一个简单的示例,那么您的示例与任何示例一样好。然后,我会牢记以上几点,并且可能仍然使用 TinyXPath

      【讨论】:

        【解决方案4】:

        如果您需要灵活地对提取的值进行运行时更改,则需要 XPath。

        但是,如果您不太可能需要这种灵活性,或者重新编译以扩展您正在提取的内容不是问题,并且事情不会经常更改,或者如果用户永远不需要更新表达式。或者,如果您拥有的东西对您来说很好,您就不需要 XPath,而且有很多应用程序不使用它。

        至于它是否更具可读性,是的,它确实可以。但是,如果您只是提取一些值,我会质疑是否需要引入另一个库。

        我当然会更好地记录您目前拥有的内容,因为那些不熟悉 tinyxml 或 xml 库的人可能不确定它在做什么,但它并不难理解。

        我不确定 XPath 会增加什么样的开销,但我怀疑它可能会增加一些。对于大多数人来说,我猜他们根本不会注意到任何差异,这可能不是您或大多数人关心的问题,但请注意这一点,以防您担心。

        如果您确实想使用 xpath 库,那么我只能说我使用的是 Xerces-C++ 附带的库,而且学习起来并不难。我以前使用过 TinyXML,这里有人提到过 TinyXPath。我没有这方面的经验,但它是可用的。

        我还发现这个链接在第一次学习 XPath 表达式时很有用。 http://www.w3schools.com/xpath/default.asp

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-17
          • 2011-05-07
          • 1970-01-01
          • 1970-01-01
          • 2018-09-05
          相关资源
          最近更新 更多