2011-02-16 31 views
3

我有以下XML,我試圖根據名稱子節點獲取唯一節點。如何使用Ruby選擇唯一的XML節點?

原始XML:

<products> 
    <product> 
    <name>White Socks</name> 
    <price>2.00</price> 
    </product> 
    <product> 
    <name>White Socks/name> 
    <price>2.00</price> 
    </product> 
    <product> 
    <name>Blue Socks</name> 
    <price>3.00</price> 
    </product> 
</products> 

我試圖讓:

<products> 
    <product> 
    <name>White Socks</name> 
    <price>2.00</price> 
    </product> 
    <product> 
    <name>Blue Socks</name> 
    <price>3.00</price> 
    </product> 
</products> 

我已經試過各種事情,但不值得在這裏上市,我得到的最接近使用XPath但那是隻是返回了下面的名字。但是,這是錯誤的,因爲我需要上面的完整XML,而不僅僅是節點值。

White Socks 
Blue Socks 

我使用Ruby和試圖遍歷像這樣的節點:

@doc.xpath("//product").each do |node| 

顯然,上述目前得到所有產品的節點,而我希望所有的獨特產品節點(使用子節點「名稱」作爲唯一標識符)

+0

好問題, +1。查看我的答案,獲得完整,簡短且容易的XSLT 1.0解決方案。還提供了廣泛的解釋。 :) – 2011-02-16 17:16:18

回答

1

該轉化

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kProdByName" match="product" 
    use="name"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match= 
    "product 
    [not(generate-id() 
     = 
     generate-id(key('kProdByName',name)[1]) 
     ) 
    ]"/> 
</xsl:stylesheet> 

當所提供的XML文檔應用(校正爲良好的形成):

<products> 
    <product> 
     <name>White Socks</name> 
     <price>2.00</price> 
    </product> 
    <product> 
     <name>White Socks</name> 
     <price>2.00</price> 
    </product> 
    <product> 
     <name>Blue Socks</name> 
     <price>3.00</price> 
    </product> 
</products> 

產生想要的,正確的結果:

<products> 
    <product> 
    <name>White Socks</name> 
    <price>2.00</price> 
    </product> 
    <product> 
    <name>Blue Socks</name> 
    <price>3.00</price> 
    </product> 
</products> 

請注意

  1. identity rule副本的每個節點 「原樣」。

  2. The Muenchian method for grouping被使用。

  3. 有一個覆蓋模板,排除不是組中第一個的任何product元素。


XPath的一個班輪(請注意,這是O(N^2) - 將很慢許多product元素):

/*/product[not(name = following-sibling::product/name)] 
+0

這可以單獨使用Xpath完成嗎?所以我可以結合到我的Ruby語句? @ doc.xpath(「// product」)。每個都做|節點| – Zinc 2011-02-16 17:15:49

0

通過XSLT,您可以使用Muenchian分組的消除重複如下:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:key name="prod-by-name" match="product" use="name"/> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="product[not(generate-id() = generate-id(key('prod-by-name', name)[1]))]"/> 

</xsl:stylesheet>