XSLT首次出现基于特定值的元素

时间:2014-08-22 13:48:12

标签: xml xslt xslt-1.0 xslt-2.0

我有一个xml文件,如下所示,预期输出应该只有基于recordNumber第一次出现的元素 Xml文件如下: -

      <catalog>
<cd>
      <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <year>1985</year>
              <recordNumber>100</recordNumber>
</cd>
<cd>
    <title>Hide your heart</title>
    <artist>Bonnie Tyler</artist>
    <year>1988</year>
              <recordNumber>101</recordNumber>

</cd>
<cd>
    <title>Greatest Hits</title>
    <artist>Dolly Parton</artist>
    <year>1982</year>
              <recordNumber>102</recordNumber>

</cd>
<cd>
    <title>Still got the blues</title>
    <artist>Gary Moore</artist>
    <year>1990</year>
              <recordNumber>100</recordNumber>

</cd>
<cd>
    <title>Eros</title>
    <artist>Eros Ramazzotti</artist>
    <year>1997</year>
              <recordNumber>100</recordNumber>
</cd>
<cd>
    <title>One night only</title>
    <artist>Bee Gees</artist>
    <year>1998</year>
              <recordNumber>101</recordNumber>
</cd>

预期输出: - 预期输出应该只包含基于recordNumber第一次出现的元素

 <?xml version="1.0" encoding="UTF-8"?>
 <catalog>
<cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <year>1985</year>
              <recordNumber>100</recordNumber>
</cd>
<cd>
    <title>Hide your heart</title>
    <artist>Bonnie Tyler</artist>
    <year>1988</year>
              <recordNumber>101</recordNumber>

</cd>
<cd>
    <title>Greatest Hits</title>
    <artist>Dolly Parton</artist>
    <year>1982</year>
              <recordNumber>102</recordNumber>

</cd>

3 个答案:

答案 0 :(得分:1)

更好的解决方案是使用XSLT 2.0分组:

<xsl:for-each-group select="cd" group-by="recordNumber">
  <xsl:copy-of select="current-group()[1]"/>
</xsl:for-each-group>

答案 1 :(得分:0)

虽然这种搜索非常密集,但它完成了这项工作:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

    <xsl:template match="cd[count(preceding-sibling::cd[recordNumber = current()/recordNumber]) > 0]" />
</xsl:stylesheet>

答案 2 :(得分:0)

首先,您显示的输入XML格式不正确。它缺少结束</catalog>标记。

您的要求非常简单。它可以通过两个模板来解决,一个执行身份转换,另一个将cd个元素保留在输出中,如果它们前面有另一个cd元素相同的recordNumber元素。

<强>样式表

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="cd[preceding::cd[recordNumber = current()/recordNumber]]"/>

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

XML输出

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <cd>
      <title>Empire Burlesque</title>
      <artist>Bob Dylan</artist>
      <year>1985</year>
      <recordNumber>100</recordNumber>
   </cd>
   <cd>
      <title>Hide your heart</title>
      <artist>Bonnie Tyler</artist>
      <year>1988</year>
      <recordNumber>101</recordNumber>
   </cd>
   <cd>
      <title>Greatest Hits</title>
      <artist>Dolly Parton</artist>
      <year>1982</year>
      <recordNumber>102</recordNumber>
   </cd>
</catalog>

顺便说一下:

  • 正如@ michael.hor257k所指出的,这个解决方案在大输入XML文档上表现不佳,因为必须进行多次比较。更具伸缩性的解决方案将使用分组机制(如XSLT 2.0中的for-each-group)。
  • 永远不要相信www.w3schools.com上任何内容的输出。依靠值得信赖的资源,如W3C。