2011-02-25 91 views
1

應用於(簡化)xml下面的代碼使myanim1.swf,如預期的節點。我其實希望節點myanim3.swf。我想說的是「獲得屬性名爲animationUrl的屬性標記的第一個節點,但不要超過一個孩子」。我目前有一個解決方法,但我正在尋找一個更優雅的解決方案。紅寶石/ Nokogiri/Xpath淺搜索

這是紅寶石,對象是一個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"] 
+1

Nokogiri的XPath風味? Nokogiri使用libxml2,這是一個標準的XML解析器。 – 2011-03-01 03:21:58

回答

1

我想你需要的東西,如:

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

+1這就是我要用的。 – 2011-03-01 03:25:55

+0

我想你的意思是'at_xpath'? – Phrogz 2011-03-02 15:49:30

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"/> 
+0

你不*有*使用'at_xpath'。你可以使用'at'。 Nokogiri會做正確的事情。 – 2011-03-01 03:24:50

+0

使用at將在指定級別返回具有animationUrl的對象的所有出現次數。 at_xpath只會返回操作查找的第一個事件。 – 2013-04-22 09:49:45

1

如果你知道你想要的項目的深度,你可以這樣做:

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

但是,如果你知道的深度,然後當然這很容易做到:

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

如果你想要一個實際的廣度優先搜索發現最淺的項目在任何深度:

雖然XPath可以讓你決定一個項目的深度(如上圖所示),它不會讓你排序中的項目返回的NodeSet(這是你需要在純XPath中完成的)。因此,我們將不得不訴諸使用紅寶石一般情況下:

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 
+0

我想你誤解了OP的意圖。他只想提取一個根節點級別的節點。他不需要計算深度。 – 2011-02-26 01:05:04

+0

@MarkThomas阿克,你是對的。我完全錯過了「但不要超過一個孩子」的話。我誤解了「淺搜索」是指「廣度優先,先找到最淺的一個」。哦,那麼答案的最上面部分仍然有效,至少:) – Phrogz 2011-02-26 01:44:24

2

得到與屬性名稱= animationUrl屬性標籤 的第一個節點,但 不要去深度超過一個孩子

相對XPath表達式:

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

這意味着:上下文節點的第一個子元素至少有一個與@name 10子元素屬性等於'animationUrl'

絕對XPath表達式:

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

這意味着:根元素具有至少一個property@name子元素等於屬性'animationUrl'

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

這意味着:文檔根的f具有至少一個property子元素的第一後裔元素@name屬性等於'animationUrl'

+0

作爲病人教育家+1。 :) – 2011-02-26 04:14:03