Arkahys
Arkahys

Reputation: 3

Xslt : rewrite tree to sort child attribute in different parents before exploit data

I'm stumbling on a step of what i want to do :

What i have :

    <cat>
        <cat2>
             <item name="ddd">...</item>
        </cat2>
        <cat3>
             <cat4>
                  <cat5>
                          <item name="aaa">...</item>
                          <item name="fff">...</item>
                  </cat5>
                  <item name="bbb">...</item>
             </cat4>
             <item name="eee">...</item>
        </cat3>
        <item name="ccc">...</item>
    </cat>

And i would like to sort it by name of item (to be exported), so with all "cat" rewrited for the sort, such :

 <cat>
    <cat3>
         <cat4>
              <cat5>
                      <item name="aaa">...</item>
              </cat5>
              <item name="bbb">...</item>
         </cat4>
    </cat3>
    <item name="ccc">...</item>
    <cat2>
         <item name="ddd">...</item>
    </cat2>
    <cat3>
         <item name="eee">...</item>
         <cat4>
              <cat5>
                      <item name="fff">...</item>
              </cat5>
         </cat4>
    </cat3>
</cat>

I don't care if result is long, because I will export it in (...| itemName|cat|cat1|cat2|...) But I have to keep parents for each, and get them order by name, because sort after exported is quite impossible.

Upvotes: 0

Views: 44

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167696

XSLT 3 has a snapshot function that allows you to easily create a copy of a node and its ancestors so using XSLT 3 (as available in the open source version Saxon 9.8 HE for .NET and Java and C/C++) you could at least easily order the item elements by name and then recreate the ancestor hierarchy for each item separately:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

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

  <xsl:template match="/*">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:variable name="sorted-items" as="element(item)*">
              <xsl:perform-sort select="descendant::item">
                  <xsl:sort select="@name"/>
              </xsl:perform-sort>
          </xsl:variable>
          <xsl:sequence select="$sorted-items!root(snapshot())"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

The result for your sample then is

<cat>
   <cat>
      <cat3>
         <cat4>
            <cat5>
               <item name="aaa">...</item>
            </cat5>
         </cat4>
      </cat3>
   </cat>
   <cat>
      <cat3>
         <cat4>
            <item name="bbb">...</item>
         </cat4>
      </cat3>
   </cat>
   <cat>
      <item name="ccc">...</item>
   </cat>
   <cat>
      <cat2>
         <item name="ddd">...</item>
      </cat2>
   </cat>
   <cat>
      <cat3>
         <item name="eee">...</item>
      </cat3>
   </cat>
   <cat>
      <cat3>
         <cat4>
            <cat5>
               <item name="fff">...</item>
            </cat5>
         </cat4>
      </cat3>
   </cat>
</cat>

which might suffice if your export only needs the ancestors of each item and preserving the sibling structure does not matter.

Online sample is at https://xsltfiddle.liberty-development.net/bFDb2C2.

Upvotes: 1

Related Questions