2011-02-16 66 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>