0
votes

i am a newbie and xslt and i created an xslt for my xml to XML transformation that sorts a field called catLineNum.

XSLT code

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>


    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
   
    
    <xsl:template match="category">
    <category><xsl:value-of select= "category"/></category>
    
    <xsl:variable name="min" select="min(//catLineNum)" />
    <catLineNum><xsl:value-of select="$min" /></catLineNum>
    
        <xsl:copy>
           
            <xsl:apply-templates select="categoryDescription">
                <xsl:sort select="catLineNum" data-type="number" />
            </xsl:apply-templates>
            
        </xsl:copy>
        
    </xsl:template>




</xsl:stylesheet>

input xml

<?xml version='1.0' encoding='UTF-8'?>
<root>
  <model>
    <models>
      <key>18322022AMECHANICAL &amp; PERFORMANCE</key>
      <models>
        <category>
          <category>MECHANICAL &amp; PERFORMANCE</category>
          <categoryDescription>
            <categoryDescription>with Valvematic Technology, CVT</categoryDescription>
            <catLineNum>002</catLineNum>
          </categoryDescription>
          <categoryDescription>
            <categoryDescription>-15-in Styled Steel Wheels</categoryDescription>
            <catLineNum>003</catLineNum>
          </categoryDescription>
          <categoryDescription>
            <categoryDescription>-1.8L 4-cyl Engine</categoryDescription>
            <catLineNum>001</catLineNum>
          </categoryDescription>
        </category>
      </models>
    </models>
  </model>
</root>

output

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <model>
      <models>
         <key>18322022AMECHANICAL &amp; PERFORMANCE</key>
         <models>
            <category>MECHANICAL &amp; PERFORMANCE</category>
            <catLineNum>1</catLineNum>
            <category>
               <categoryDescription>
                  <categoryDescription>-1.8L 4-cyl Engine</categoryDescription>
                  <catLineNum>001</catLineNum>
               </categoryDescription>
               <categoryDescription>
                  <categoryDescription>with Valvematic Technology, CVT</categoryDescription>
                  <catLineNum>002</catLineNum>
               </categoryDescription>
               <categoryDescription>
                  <categoryDescription>-15-in Styled Steel Wheels</categoryDescription>
                  <catLineNum>003</catLineNum>
               </categoryDescription>
            </category>
         </models>
      </models>
  </model>
</root>

The problem is that if I don't include this part of code

<xsl:template match="category"> <xsl:value-of select= "category"/>

the category field will be missing in the output. I feel that there is another way to do it just sort the values and include that category field. Thank you for your help.

3

3 Answers

0
votes

How about:

<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="models/models">
    <xsl:copy>
        <xsl:copy-of select="category/category"/>
        <catLineNum>
            <xsl:value-of select="min(category/categoryDescription/catLineNum)" />
        </catLineNum>
        <category>
            <xsl:apply-templates select="category/categoryDescription">
                <xsl:sort select="catLineNum" data-type="number"/>
            </xsl:apply-templates>
        </category>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
0
votes

Or one level deeper:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:math="http://www.w3.org/2005/xpath-functions/math"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map"
  xmlns:array="http://www.w3.org/2005/xpath-functions/array"
  exclude-result-prefixes="#all"
  version="3.0">
  
  <xsl:mode on-no-match="shallow-copy"/>
  
  <!-- Not needed, since you are using <xsl:mode on-no-match="shallow-copy"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  -->  
  
  <xsl:template match="category[category]">
    <xsl:copy>
      <xsl:copy-of select="category"/>
      <catLineNum>
        <xsl:value-of select="min(categoryDescription/catLineNum)" />
      </catLineNum>
      
      <xsl:apply-templates select="categoryDescription">
        <xsl:sort select="catLineNum" data-type="number" />
      </xsl:apply-templates>
      
    </xsl:copy>    
  </xsl:template>
  
</xsl:stylesheet>
0
votes

Using Saxon JS 2 or Saxon HE 10 or any Saxon 9.8 or later PE or EE with higher order function support you can also use

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="models/category">
    <xsl:copy>
      <xsl:copy-of select="category"/>
      <catLineNum>{min(categoryDescription/catLineNum)}</catLineNum>
      <category>
        <xsl:apply-templates select="sort(categoryDescription, (), function($c) { xs:integer($c/catLineNum) })"/>
      </category>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>