如何使用Ruby选择唯一的XML节点?

时间:2011-02-16 16:43:58

标签: ruby ruby-on-rails-3 xslt xpath

我有以下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|

显然上面目前获得所有产品节点,而我想要所有独特的产品节点(使用子节点“name”作为唯一标识符)

2 个答案:

答案 0 :(得分: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. 使用 Muenchian method for grouping

  3. 有一个覆盖模板可以排除任何不属于其组中第一个的product元素。


  4. XPath-one-liner (注意这是O(N ^ 2) - 在许多product元素上非常慢):

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

答案 1 :(得分: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>