2010-12-09 98 views
1

我有一個XML文檔如下:排序的XPath結果

<objects> 
    <object uid="0" /> 
    <object uid="1" /> 
    <object uid="2" /> 
</objects> 

我可以使用下面的查詢選擇多個元素:

doc.xpath("//object[@uid=2 or @uid=0 or @uid=1]") 

但這返回元素按照它們在XML文檔(uid = 0,uid = 1,uid = 2)中聲明的順序排列,我希望結果與執行XPath查詢時的順序相同(uid = 2,uid = 0, UID = 1)。

我不確定這是否可以使用XPath,並且已經研究了XSLT排序,但是我還沒有找到解釋我如何實現這一點的示例。

我在Ruby與Nokogiri圖書館工作。

+0

好問題,+1。請參閱我的答案以獲取解釋和兩種不同的解決方案:XPath 2.0和XSLT 1.0解決方案。 – 2010-12-09 19:25:03

回答

0

的XSLT例如:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:param name="pSequence" select="'2 1'"/> 
    <xsl:template match="objects"> 
     <xsl:for-each select="object[contains(concat(' ',$pSequence,' '), 
               concat(' ',@uid,' '))]"> 
      <xsl:sort select="substring-before(concat(' ',$pSequence,' '), 
               concat(' ',@uid,' '))"/> 
      <xsl:copy-of select="."/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<object uid="2" /><object uid="1" /> 
1

我假設您使用的是XPath 1.0。 W3C規範說: XPath中的主要語法結構是表達式。表達式與生產Expr相匹配。一個表達式產生一個對象,它具有以下四種基本類型之一:

* node-set (an unordered collection of nodes without duplicates) 
* boolean (true or false) 
* number (a floating-point number) 
* string (a sequence of UCS characters) 

所以我不認爲你可以重新排序只是使用XPath。 (規範的其餘部分定義了文檔順序和反向文檔順序,所以如果後者做了你想要的東西,你可以使用適當的座標軸來獲取它(例如前面的)。 XSLT FAQ是非常好的,你應該找到答案

0

我不認爲有辦法在xpath中做到這一點,但如果你想切換到XSLT你可以使用xsl:sort標籤:

<xsl:for-each select="//object[@uid=1 or @uid=2]"> 
    <xsl:sort: select="@uid" data-type="number" /> 
    {insert new logic here} 
</xsl:for-each> 

更完整的信息在這裏: http://www.w3schools.com/xsl/el_sort.asp

4

有XPath 1.0中無法指定所選節點的順序。

的XPath 2.0允許節點的sequence與任何特定的順序

//object[@uid=2], //object[@uid=1] 

計算結果爲序列,其中所有object項與@uid=2位於所有object項與@uid=1

如果一個沒有按」沒有可用的XPath 2.0引擎,仍然可以使用XSLT以按任何所需順序輸出節點。

在這種特定情況以下XSLT指令序列:

<xsl:copy-of select="//object[@uid=2]"/> 

<xsl:copy-of select="//object[@uid=1]"/> 

產生所需的輸出

<object uid="2" /><object uid="1" /> 
+0

謝謝Dimitre,我已經標記爲有用。我選擇接受Alejandro的答案,因爲它正是我需要的 - 包括傳遞包含我正在搜索的ID的參數的能力。 – 2010-12-13 10:47:11

+0

@Cameron:你在你的問題中沒有提到你想要parameterizarion。當然,如果想要參數化,那麼排序就是要走的路。大概一個月前,我用一個使用參數和排序的解決方案回答了類似的問題 - 這根本不是什麼新鮮事。 :) – 2010-12-13 16:40:11

0

這是我願意做它在引入nokogiri:

require 'nokogiri' 

xml = '<objects><object uid="0" /><object uid="1" /><object uid="2" /></objects>' 

doc = Nokogiri::XML(xml) 
objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort_by { |n| n['uid'].to_i }.reverse 
puts objects_by_uid 

運行輸出:

<object uid="2"/> 
<object uid="1"/> 

到搜索另一種方法是:

objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort { |a,b| b['uid'].to_i <=> a['uid'].to_i } 

,如果你不喜歡使用sort_byreverse

XPath對於定位和檢索節點非常有用,但是我們想要做的過濾通常在訪問器中過於複雜,所以我讓語言去做,無論是Ruby,Perl還是Python。我在哪裏放置過濾邏輯取決於XML數據集有多大,以及是否有很多不同的uid值。有時,讓XPath引擎完成繁重的工作很有意義,其他時候更容易讓XPath抓取所有的節點,並以調用語言進行過濾。