Home > Enterprise >  Is there a way to store transformed xml withing xslt template or variable etc and then use it for fu
Is there a way to store transformed xml withing xslt template or variable etc and then use it for fu

Time:11-21

Is there a way to store transformed xml withing XSLT template or variable etc and then use it for further processing? Transformed xml will have different elements (count and names) and I need to process them within the same stylesheet to produce final transformed XML.

I'm trying to solve following problem.

STARTING XML

<shop>

    <product>
        <name />
        <categorytxt> Garden > Tables > Blue </categorytxt>
    </product>

    <product>
        <name/>
        <categorytxt> Garden > Tables > Green </categorytxt>
    </product>
     
    
    <product>
        <name />
        <categorytxt> Home > Tables > Green </categorytxt>
    </product>

    <product>
        <name />
        <categorytxt> Home > Chairs > White </categorytxt>
    </product>

</shop>

And my desired output XML would be this...

<!-- category treeview structure -->
<categories>
    <category id="1" parent="root">Garden</category>
    <category id="2" parent="1">Tables</category>
    <category id="3" parent="2">Blue</category>
    <category id="4" parent="2">Green</category>

    <category id="5" parent="root">Home</category>
    <category id="6" parent="5">Tables</category>
    <category id="7" parent="6">Green</category>

    <category id="8" parent="5">Chairs</category>
    <category id="9" parent="8">White</category>
</categories>

So far I was only able to filter unique categorytxt elements and split them up into category elements

But the problem is how to filter out duplicates (can't have more than one 'Home' in result xml etc.) and assigning correct id and parent to the elements. Any ideas how to solve this?

Thank you.

This is the working code in progress so far

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

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


<xsl:template match="/">

        

        
        <categories>

            <xsl:for-each select="//categorytxt[not(.=../../preceding-sibling::categorytxt/product)]">

                <xsl:sort select="." />

                <!-- try to save it to the parameter variable whatever -->
                <!-- splits each row into elements -->
                 
                    <xsl:call-template name="output-tokens">

                        
                        <xsl:with-param name="num" select="1" />
                        <xsl:with-param name="list" select="concat(. ,' > ')" />
                          
                    </xsl:call-template>
               

            </xsl:for-each>

        </categories>

</xsl:template>



<xsl:template name="output-tokens">

    
    <xsl:param name="num" />
 
    <xsl:param name="list" />
    <xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" />
    <xsl:variable name="first" select="substring-before($newlist, '>')" />
    <xsl:variable name="remaining" select="substring-after($newlist, '>')" />

   

    <xsl:if test="$first">
        
         <category id="{$num}">
            <xsl:copy-of select="normalize-space($first)" />
         </category>
       
    </xsl:if>

    <xsl:if test="$remaining">
        <xsl:call-template name="output-tokens">
            <xsl:with-param name="num" select="$num   1"/>
            <xsl:with-param name="list" select="$remaining" />
        </xsl:call-template>
    </xsl:if>

</xsl:template>

</xsl:stylesheet>

CodePudding user response:

In general, in XSLT 1, if you create nodes in a variable/parameter e.g.

<xsl:variable name="intermediary-result-rtf">
  <foo>
   <xsl:apply-templates/>
  </foo>
</xsl:variable>

that variable is of type result tree fragment on which standard/pure XSLT 1.0 only allows xsl:copy-of select="$intermediary-result-rtf or xsl:value-of select="$intermediary-result-rtf".

However, most XSLT 1.0 processors support an extension function (in a proprietary namespace or in the EXSLT namespace http://exslt.org/common) to convert a result tree fragment into a node-set e.g.

<xsl:variable name="intermediary-result"
  select="exsl:node-set($intermediary-result-rtf)"
  xmlns:exsl="http://exslt.org/common"/>

then you can select e.g. $intermediary-result/foo, i.e. do XPath selections on the node-set.

  • Related