2012-04-04 35 views
2

在這個XML片段我需要更換的UID的數據爲一些塊。實際文件包含超過100個相似的塊。使用引入nokogiri使用多個搜索元素

雖然我基於name="Track (Timeline)"能夠提取的子集,我奮力如果name="Track (TimeLine)"這個子集減少到特定塊,我需要還通過使用在<TrackID>的數據,以及<TrackID>文字0x1200然後設置UID到xxxx。

我是新來引入nokogiri,雖然我編寫的測試腳本,我不認爲我是一個程序員。

<StructuralMetadata key="06.0E.2B.34.02.53.01.01.0D.01.01.01.01.01.3B.00" length="116" name="Track (TimeLine)"> 
    <EditRate>25/1</EditRate> 
    <Origin>0</Origin> 
    <Sequence>32-04-25-67-E7-A7-86-4A-9B-28-53-6F-66-74-65-6C</Sequence> 
    <TrackID>0x1200</TrackID> 
    <TrackName>Softel VBI Data</TrackName> 
    <TrackNumber>0x17010101</TrackNumber> 
    <UID>34-C1-B9-B9-5F-07-A4-4E-8F-F4-53-6F-66-74-65-6C</UID> 
</StructuralMetadata> 
<StructuralMetadata key="06.0E.2B.34.02.53.01.01.0D.01.01.01.01.01.3B.00" length="116" name="Track (TimeLine)"> 
    <EditRate>25/1</EditRate> 
    <Origin>0</Origin> 
    <Sequence>35-12-2D-86-E6-74-0B-4C-B4-24-53-6F-66-74-65-6C</Sequence> 
    <TrackID>0x1300</TrackID> 
    <TrackName>Softel VBI Data</TrackName> 
    <TrackNumber>0x0</TrackNumber> 
    <UID>37-0C-80-34-4C-8D-CE-41-85-F3-53-6F-66-74-65-6C</UID> 
</StructuralMetadata> 

回答

1

一個偉大的方式來解決這個問題是規劃的「地圖縮小」的風格,其作品拿東西的大名單,並縮小它,並將其合併到你之後的結果。具體來說,Array#findArray#select對於這類問題非常有用。看看這個例子:

require 'nokogiri' 
xml = Nokogiri::XML.parse(File.read "sample.xml") 
element = xml.css('StructuralMetadata').find { |item| 
    item['name'] == "Track (TimeLine)" and item.css('TrackID').text == "0x1200" 
} 
puts element.to_xml 

這個小程序首先使用CSS選擇器來獲取所有文檔中的<StructuralMetadata>元素。它返回一個數組,我們可以過濾我們想要使用Array#find方法什麼。 Array#select是其表妹返回所有匹配的對象,而不是正好找到的第一個陣列。

我們要檢查測試,如果<StructuralMetadata>標籤是一個我們之後是塊內。然後,它把element.to_xml字符串到控制檯,所以你可以看到它發現了事情,如果你運行這是一個命令行腳本。現在,你可以找到的元素,你可以修改它以通常的方式,節省了一個新的XML文件或什麼的。

+1

這樣你實際上忽略引入nokogiri的XPath或CSS搜索功能,所有數據拋出去'.find'。爲什麼不解決「縮小」與引入nokogiri? – karatedog 2012-04-04 11:15:22

+0

謝謝blixxy - 爲我做的工作 – Trevor 2012-04-04 13:01:03

+0

@karatedog Trevor說他們不認爲自己是程序員,這讓我覺得他們是初學者學習Ruby。在深入研究xpath和css選擇器,regexps和其他語言等新語言之前,最好先適應一種語言。我認爲首先開始學習這些東西時,保持簡單明瞭的東西非常重要。作爲旁註,我不認爲這個問題可以用CSS選擇器解決,可以嗎? Xpath肯定。 :) – Blixxy 2012-04-04 14:32:49

2

使用XPath:

//StructuralMetadata 

將選擇在XML的所有StructuralMetadata元素。開始處的雙斜槓意味着選擇節點出現在文檔中的任何節點。

你不想所有的,雖然節點,就可以過濾你想要的那些與謂詞:

//StructuralMetadata[@name="Track (TimeLine)" and TrackID="0x1200"] 

這將選擇有name屬性與價值Track (TimeLine)所有StructuralMetadata元素,並與內容0x1200一個TrackID子元素。

正如你所感興趣的UID元素,你可以進一步細化的表達:

//StructuralMetadata[@name="Track (TimeLine)" and TrackID="0x1200"]/UID 

這個表達式將匹配所有UID元素是符合上述謂詞StructuralMetadata元素的孩子。

把這個使用方法:

require 'nokogiri' 

# Parse the document, assuming xml_file is a File object containing the XML 
doc = Nokogiri::XML(xml_file) 

# I'm assuming there is only one element in the document that matches 
# the criteria, so I'm using at_xpath 
node = doc.at_xpath('//StructuralMetadata[@name="Track (TimeLine)" and TrackID="0x1200"]/UID') 

# At this point, doc contains a representation of the xml, and node points to 
# the UID node within that representation. We can update the contents of 
# this node 
node.content = 'XXX' 

# Now write out the updated XML. This just writes it to standard output, 
# you could write it to a file or elsewhere if needed 
puts doc.to_xml 
+0

我喜歡這個。 XPath是一種很好的方法,如果你要使用XML,那肯定值得學習。 – Blixxy 2012-04-06 04:02:37

+0

謝謝馬特。想想這是要走的路 - 猜猜我會學習更多關於xpath的知識。 – Trevor 2012-04-10 08:38:57