我应该使用XPath还是只使用DOM?

时间:2011-03-04 13:53:35

标签: c++ xml xpath tinyxml

我有一堆存储在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()指向<source>节点。

问题:我是否会使用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库?

4 个答案:

答案 0 :(得分:5)

总的来说,我倾向于选择基于XPath的解决方案,因为它们的简洁性和多功能性,但老实说,在您的情况下,我认为使用XPath不会给您的signature带来很多。

原因如下:

典雅优雅
你的代码很好而且紧凑,使用XPath表达式也不会有任何好处。

内存占用
除非您的输入XML配置文件很大(一种矛盾)并且DOM解析需要大量的内存占用,因此没有证据表明使用XPath将是一个决定性的解决方案,我会坚持使用DOM。

执行速度
在这样一个简单的XML树上,执行速度应具有可比性。 如果存在差异,那么由于在给定节点下freqlevel标记的搭配,它可能会在TinyXml中占据优势。

图书馆和外部参考这是决定性的一点 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
  5. 总之,在你的情况下,只是为了它而切换到XPath,如果有的话会带来很少的好处。

    然而,XPath是当今开发人员工具箱中非常强大的工具,没有人可以忽略它。 如果你只想练习一个简单的例子,你的就像任何一个一样好。然后,我会记住以上几点,并且可能还是使用 TinyXPath

答案 1 :(得分:3)

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

但是,如果您不太可能需要这种灵活性,或者重新编译以扩展您提取的内容不是问题,并且事情不会经常更改或者用户永远不需要更新表达式。或者,如果您的工作正常,则不需要XPath,并且有许多应用程序不使用它。

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

我肯定会记录你目前的情况,因为那些不熟悉tinyxml或xml库的人可能不确定它在做什么,但它并不难理解。

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

如果您确实想使用xpath库,那么我可以说的是我使用了 Xerces-C ++ 附带的那个,并且它并不太难学。我之前使用过TinyXML,有人提到 TinyXPath 。我没有经验,但可以使用。

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

此XPath表达式

/*/sig[$pN]/*

选择XML文档顶部元素的$ pN-th freq子项的所有子元素(只有levelsig对)。

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

/*/sig[2]/*

选择这两个元素

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

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

另一个优点是可以在C#或Java或...程序中使用相同的XPath表达式,而无需以任何方式修改它 - 因此坚持XPath结果非常高便携性程度。