first last element

2019-02-27 02:14发布

问题:

XSLT XML Question.

Looking into a simple transformation. I have simple index xml input. I have to output the the first and last element with a for each chapter. AS shown below. any help will be much appreciated.

Regards JJ

Input

<book>
  <page number="1">Chapter01</page> 
  <page number="2">Chapter01</page> 
  <page number="3">Chapter01</page> 
  <page number="4">Chapter01</page> 
  <page number="5">Chapter01</page> 
  <page number="6">Chapter01</page> 
  <page number="7">Chapter02</page> 
  <page number="8">Chapter02</page> 
  <page number="9">Chapter02</page> 
  <page number="10">Chapter02</page> 
  <page number="11">Chapter02</page> 
  <page number="12">Chapter02</page> 
  <page number="13">Chapter03</page> 
  <page number="14">Chapter03</page> 
  <page number="15">Chapter03</page> 
  <page number="16">Chapter03</page> 
  <page number="17">Chapter03</page> 
  <page number="18">Chapter03</page> 
 </book>

Output

<book>
  <page number="1">Chapter01</page>  
  <page number="6">Chapter01</page> 
  <page number="7">Chapter02</page> 
  <page number="12">Chapter02</page> 
  <page number="13">Chapter03</page> 
  <page number="18">Chapter03</page> 
</book>

回答1:

Updated to take advantage of a cleaner predicate - thanks to @SeanB.Durkin.

I. XSLT 1.0 Solution

When this XSLT:

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

  <xsl:key name="kChapters" match="page" use="." />

  <xsl:template match="/*">
    <book>
      <xsl:apply-templates 
        select="page[generate-id() = generate-id(key('kChapters', .)[1])]" />
    </book>
  </xsl:template>

  <xsl:template match="page">
    <xsl:copy-of select=".|key('kChapters', .)[last()]" />
  </xsl:template>

</xsl:stylesheet>

...is applied to the original XML:

<book>
  <page number="1">Chapter01</page>
  <page number="2">Chapter01</page>
  <page number="3">Chapter01</page>
  <page number="4">Chapter01</page>
  <page number="5">Chapter01</page>
  <page number="6">Chapter01</page>
  <page number="7">Chapter02</page>
  <page number="8">Chapter02</page>
  <page number="9">Chapter02</page>
  <page number="10">Chapter02</page>
  <page number="11">Chapter02</page>
  <page number="12">Chapter02</page>
  <page number="13">Chapter03</page>
  <page number="14">Chapter03</page>
  <page number="15">Chapter03</page>
  <page number="16">Chapter03</page>
  <page number="17">Chapter03</page>
  <page number="18">Chapter03</page>
</book>

...the desired result is produced:

<?xml version="1.0"?>
<book>
  <page number="1">Chapter01</page>
  <page number="6">Chapter01</page>
  <page number="7">Chapter02</page>
  <page number="12">Chapter02</page>
  <page number="13">Chapter03</page>
  <page number="18">Chapter03</page>
</book>

Explanation:

  • Note the proper use of Muenchian Grouping to determine the unique <page> elements by their value.
  • For each unique <page> element, two <page> elements are copied: the first and last from the group that contains the unique value.

II. XSLT 2.0 Solution

Note that in XSLT 2.0, the solution becomes even simpler.

When this XSLT:

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

  <xsl:template match="/*">
    <book>
      <xsl:for-each-group select="page" group-by=".">
        <xsl:copy-of select=".|current-group()[last()]" />
      </xsl:for-each-group>
    </book>
  </xsl:template>

</xsl:stylesheet>

...is applied to the original XML, the same desired result is produced:

<?xml version="1.0"?>
<book>
  <page number="1">Chapter01</page>
  <page number="6">Chapter01</page>
  <page number="7">Chapter02</page>
  <page number="12">Chapter02</page>
  <page number="13">Chapter03</page>
  <page number="18">Chapter03</page>
</book>

Explanation:

  • The same methodology is applied, but instead of Muenchian Grouping, XSLT 2.0's for-each-group element and current-group() instruction are used.


标签: xml xslt