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



我有一个如下所示的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>

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

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

虽然这个搜索非常密集,但它完成了任务:

<?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>

首先,您显示的输入XML不是格式良好的。它缺少一个结束的</catalog>标记。

你的要求很微不足道。它可以用两个模板来解决,一个执行单位变换,另一个防止cd元素被发送到输出,如果它们前面有另一个具有相同recordNumber元素的cd元素。

样式表

<?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>

By the way:

  • @michael。hor257k已经注意到,这个解决方案在大型输入XML文档上的性能很差,因为必须进行大量的比较。更具可扩展性的解决方案是使用分组机制(如XSLT 2.0中的for-each-group)。
  • 永远不要相信www.w3schools.com上的任何输出。依赖可信赖的来源,如W3C。

相关内容

  • 没有找到相关文章

最新更新