Warm tip: This article is reproduced from serverfault.com, please click

How to fetch elements with same name and order them based on a subnode value in XSLT

发布于 2020-12-02 10:43:38

I am trying to transform an input XML where all parent nodes say 'x' need to be extracted, sorted and then reordered in the final output XML based on their subnode say 'y' value. Below is my XML and I am trying to modify it so that the final XML will have the elements in ascending order where the sorting is done based on number values in the xpath notes/notesBODY/group/text, basically the element <text>1. </text> present in all notes elements. But the output XML is not as expected as I can't seem to figure how to use the sort exactly in XSLT. Any help appreciated.

Input XML:

 <root>
    <group>
       <text>group1</text>
    </group>
    <group>
       <text>group2</text>
    </group>
    <notes>
        <notesText>notes1</notesText>
        <notesBODY>
            <group>
                <text>2. </text>
                <text>notesbody1</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
        <notesText>notes2</notesText>
        <notesBODY>
            <group>
                <text>1. </text>
                <text>notesbody2</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
        <notesText>notes3</notesText>
        <notesBODY>
            <group>
                <text>3. </text>
                <text>notesbody3</text>
            </group>
        </notesBODY>
    </notes>
    <group>
        <text>group3</text>
        <notes>
            <notesText>notes4</notesText>
            <notesBODY>
                <group>
                    <text>4. </text>
                    <text>notesbody4</text>
                </group>
            </notesBODY>
        </notes>
    </group>
    <group>
       <text>group4</text>
    </group>
    <group>
       <text>group5</text>
       <notes>
            <notesText>notes5</notesText>
            <notesBODY>
                <group>
                    <text>6. </text>
                    <text>notesbody5</text>
                </group>
            </notesBODY>
        </notes>
    </group>
    <notes>
        <notesText>notes6</notesText>
        <notesBODY>
            <group>
                <text>5. </text>
                <text>notesbody6</text>
            </group>
        </notesBODY>
    </notes>
    <group>
       <text>group6</text>
    </group>
    <group>
       <text>group7</text>
    </group>
    <group>
        <text>group8</text>
        <notes>
            <notesText>notes7</notesText>
            <notesBODY>
                <group>
                    <text>8. </text>
                    <text>notesbody7</text>
                </group>
            </notesBODY>
        </notes>
    </group>
    <notes>
        <notesText>notes8</notesText>
        <notesBODY>
            <group>
                <text>7. </text>
                <text>notesbody8</text>
            </group>
        </notesBODY>
    </notes>
    <group>
       <text>group9</text>
    </group>
 </root>

Expected Output:

 <root>
    <group>
       <text>group1</text>
    </group>
    <group>
       <text>group2</text>
    </group>
    <group>
        <text>group3</text>
    </group>
    <group>
       <text>group4</text>
    </group>
    <group>
       <text>group5</text>
    </group>
    <group>
       <text>group6</text>
    </group>
    <group>
       <text>group7</text>
    </group>
    <group>
        <text>group8</text>
    </group>
    <group>
       <text>group9</text>
    </group>
    <notes>
        <notesText>notes2</notesText>
        <notesBODY>
            <group>
                <text>1. </text>
                <text>notesbody2</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
        <notesText>notes1</notesText>
        <notesBODY>
            <group>
                <text>2. </text>
                <text>notesbody1</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
        <notesText>notes3</notesText>
        <notesBODY>
            <group>
                <text>3. </text>
                <text>notesbody3</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
            <notesText>notes4</notesText>
            <notesBODY>
                <group>
                    <text>4. </text>
                    <text>notesbody4</text>
                </group>
            </notesBODY>
        </notes>
    <notes>
        <notesText>notes6</notesText>
        <notesBODY>
            <group>
                <text>5. </text>
                <text>notesbody6</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
            <notesText>notes5</notesText>
            <notesBODY>
                <group>
                    <text>6. </text>
                    <text>notesbody5</text>
                </group>
            </notesBODY>
    </notes>
    <notes>
        <notesText>notes8</notesText>
        <notesBODY>
            <group>
                <text>7. </text>
                <text>notesbody8</text>
            </group>
        </notesBODY>
    </notes>
    <notes>
        <notesText>notes7</notesText>
        <notesBODY>
            <group>
                <text>8. </text>
                <text>notesbody7</text>
            </group>
        </notesBODY>
    </notes>
 </root>

XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()" />
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="notes">
          <xsl:apply-templates select="@*" />
   <xsl:copy>
      <xsl:apply-templates select="node()">
         <xsl:sort select="notesBODY/group/text[position() = 0]" />
      </xsl:apply-templates>
   </xsl:copy>
</xsl:template>
    </xsl:stylesheet>
Questioner
shweta
Viewed
0
Martin Honnen 2020-12-02 19:56:27

I think you basically want to use two templates

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="root">
      <xsl:copy>
          <xsl:apply-templates select="group"/>
          <xsl:apply-templates select=".//notes">
              <xsl:sort select="notesBODY/group/text[1]"/>
          </xsl:apply-templates>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="group">
      <xsl:copy>
          <xsl:apply-templates select="* except notes"/>
      </xsl:copy>
  </xsl:template>

plus the identity transformation obviously you already have.