Ruby / Nokogiri / Xpath浅层搜索

时间:2011-02-25 19:38:58

标签: ruby search xpath nokogiri

应用于下面的(简化的)xml的代码获得了myanim1.swf的节点,正如预期的那样。我实际上想要myanim3.swf节点。我想说“获取带有属性名称= animationUrl的属性标记的第一个节点,但不要比一个孩子更深入”。我目前有一个解决方案,但我正在寻找一个更优雅的解决方案。

这是红宝石,对象是Nokogiri对象。我相信这是XPath搜索,但我有点不清楚它是否是Nokogiri的XPath味道。无论如何,感谢帮助,谢谢。

XML:

<blah>
    <property name="overlays">
        <array>
            <object type="myType">
                <property name="animationUrl" value="myanim1.swf"/>
            </object>
            <object type="myType">
                <property name="animationUrl" value="myanim2.swf"/>
            </object>
        </array>
    </property>
    <property name="animationUrl" value="myanim3"/>
    </property>
</blah>

CODE:

myNode = thisNode.search("property[name=animationUrl]").first.andand["value"]

4 个答案:

答案 0 :(得分:2)

  

获取带有属性标记的第一个节点   使用属性name = animationUrl,但是   不要比一个孩子更深入

相对XPath表达式:

*[property/@name='animationUrl'][1]

这意味着:上下文节点的第一个子元素,其中至少有一个property子元素的@name属性等于'animationUrl'

绝对XPath表达式:

/*[property/@name='animationUrl']

这意味着:根元素至少有一个property子元素,@name属性等于'animationUrl'

/descendant::*[property/@name='animationUrl'][1]

这意味着:文档根目录的第一个后代元素,其中至少有一个property子元素,@name属性等于'animationUrl'

答案 1 :(得分:1)

我认为你需要这样的东西:

t.xpath("/blah/property[@name='animationUrl']")

答案 2 :(得分:1)

您需要使用at_xpath以及对节点的绝对引用,这将指定您只想检索<blah><property>深度的节点:

my_node = xml.at_xpath("/blah/property[@name='animationUrl']")

行动中:

require 'nokogiri'
thisNode = <<XML 
<blah>
    <property name="overlays">
        <array>
            <object type="myType">
                <property name="animationUrl" value="myanim1.swf"/>
            </object>
            <object type="myType">
                <property name="animationUrl" value="myanim2.swf"/>
            </object>
        </array>
    </property>
    <property name="animationUrl" value="myanim3"/>
    </property>
</blah>
XML

xml=Nokogiri::XML(thisNode)
my_node = xml.at_xpath("/blah/property[@name='animationUrl']")
puts my_node   #=> <property name="animationUrl" value="myanim3"/>

答案 3 :(得分:1)

如果你知道你想要的项目的深度,你可以这样做:

p d.at_xpath('//property[@name="animationUrl"][count(ancestor::*) = 1]')

但是,如果你知道深度,那么当然更容易做到:

p d.at_xpath('/*/property[@name="animationUrl"]')

如果你想要一个实际的广度优先搜索,找到任何深度最浅的项目:

虽然XPath允许您确定项目的深度(如上所示),但它不允许您对返回的NodeSet中的项目进行排序(这是您在纯XPath中需要执行的操作)。因此,我们将不得不求助于使用Ruby作为一般情况:

class Nokogiri::XML::Node
  def at_shallowest_xpath( path )
    xpath(path).sort_by{ |n| n.xpath 'count(ancestor::*)' }.first
  end
end

d = Nokogiri::XML xml_source
puts d.at_shallowest_xpath('//property[@name="animationUrl"]')
#=> <property name="animationUrl" value="myanim3"/>

编辑:使用XPath查找深度,虽然很棘手,但是大约两倍(在我的机器上,使用此测试数据)要求Nokogiri找到元素的深度适合你。相反,使用这个:

class Nokogiri::XML::Node
  def at_shallowest_xpath( path )
    xpath(path).sort_by{ |n| n.ancestors.length }.first
  end
end