[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
reynaldo.rizzo@xxxxxxxxxxxxxxxx wrote:
Here is an XSLT 2.0 stylesheet that produces the above output, with the exception of the first line where I have left out the 'root,' at the beginning.
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="max-items" select="max(root/item/count((* except (code, name))))"/>
<xsl:variable name="item-list" select="root/item[count(* except (code, name)) eq $max-items][1]/(* except (code, name))"/>
<xsl:value-of select="('itemCode', 'itemName', $item-list/(concat(substring-before(name(), 'List'), 'Code'), concat(substring-before(name(), 'List'), 'Description')))" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:template>
<xsl:template name="mf:make-lines">
<xsl:param name="item" as="element()"/>
<xsl:param name="item-list" as="element()*"/>
<xsl:param name="line" as="item()*" select="()"/>
<xsl:variable name="current-list" as="element()?" select="$item/*[node-name(.) eq node-name($item-list[1])]"/>
<xsl:choose>
<xsl:when test="count($item-list) eq 1">
<xsl:choose>
<xsl:when test="$current-list">
<xsl:for-each select="$current-list/*">
<xsl:value-of select="($item/code, $item/name, $line, code, description)" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="($item/code, $item/name, $line, $default, $default)" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$current-list">
<xsl:for-each select="$current-list/*">
<xsl:call-template name="mf:make-lines">
<xsl:with-param name="item" select="$item"/>
<xsl:with-param name="item-list" select="$item-list[position() gt 1]"/>
<xsl:with-param name="line" select="($line, code, description)"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="mf:make-lines">
<xsl:with-param name="item" select="$item"/>
<xsl:with-param name="item-list" select="$item-list[position() gt 1]"/>
<xsl:with-param name="line" select="($line, $default, $default)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
To decide which *List elements to output the stylesheet looks for the maximum number of child elements of an 'item' element, then for each 'item' element the named template mf:make-lines is called, passing in the item element and the item list.
That template recursively builds each line to be output as a sequence, shortening the item list each time.
--
Re: [xsl] How to "flatten" a XML file with n-ary Cartesian product over n sequences X1, ..., Xn using XSL
Subject: Re: [xsl] How to "flatten" a XML file with n-ary Cartesian product over n sequences X1, ..., Xn using XSL From: Martin Honnen <Martin.Honnen@xxxxxx> Date: Sat, 29 Aug 2009 13:53:00 +0200 |
reynaldo.rizzo@xxxxxxxxxxxxxxxx wrote:
The desired output is a delimited file shown as follows:
'output.csv' root,itemCode,itemName,aCode,aDescription,bCode,bDescription,cCode,cDescription 01,name0,10,description0,100,description2,996,description4 01,name0,10,description0,100,description2,997,description5 01,name0,10,description0,200,description3,996,description4 01,name0,10,description0,200,description3,997,description5 02,name1,20,description6,null,null,998,description10 02,name1,20,description6,null,null,999,description11
Output is the Cartesian product of each item with its own sub-sequences.
Here is an XSLT 2.0 stylesheet that produces the above output, with the exception of the first line where I have left out the 'root,' at the beginning.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mf="http://example.com/2009/mf" version="2.0">
<xsl:output method="text"/>
<xsl:param name="lf" select="' '" as="xs:string"/> <xsl:param name="sep" select="','" as="xs:string"/> <xsl:param name="default" select="'null'" as="xs:string"/>
<xsl:template match="/">
<xsl:variable name="max-items" select="max(root/item/count((* except (code, name))))"/>
<xsl:variable name="item-list" select="root/item[count(* except (code, name)) eq $max-items][1]/(* except (code, name))"/>
<xsl:value-of select="('itemCode', 'itemName', $item-list/(concat(substring-before(name(), 'List'), 'Code'), concat(substring-before(name(), 'List'), 'Description')))" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
<xsl:for-each select="root/item"> <xsl:call-template name="mf:make-lines"> <xsl:with-param name="item" select="."/> <xsl:with-param name="item-list" select="$item-list"/> </xsl:call-template> </xsl:for-each>
</xsl:template>
<xsl:template name="mf:make-lines">
<xsl:param name="item" as="element()"/>
<xsl:param name="item-list" as="element()*"/>
<xsl:param name="line" as="item()*" select="()"/>
<xsl:variable name="current-list" as="element()?" select="$item/*[node-name(.) eq node-name($item-list[1])]"/>
<xsl:choose>
<xsl:when test="count($item-list) eq 1">
<xsl:choose>
<xsl:when test="$current-list">
<xsl:for-each select="$current-list/*">
<xsl:value-of select="($item/code, $item/name, $line, code, description)" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="($item/code, $item/name, $line, $default, $default)" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$current-list">
<xsl:for-each select="$current-list/*">
<xsl:call-template name="mf:make-lines">
<xsl:with-param name="item" select="$item"/>
<xsl:with-param name="item-list" select="$item-list[position() gt 1]"/>
<xsl:with-param name="line" select="($line, code, description)"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="mf:make-lines">
<xsl:with-param name="item" select="$item"/>
<xsl:with-param name="item-list" select="$item-list[position() gt 1]"/>
<xsl:with-param name="line" select="($line, $default, $default)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
To decide which *List elements to output the stylesheet looks for the maximum number of child elements of an 'item' element, then for each 'item' element the named template mf:make-lines is called, passing in the item element and the item list.
That template recursively builds each line to be output as a sequence, shortening the item list each time.
--
Martin Honnen http://msmvps.com/blogs/martin_honnen/
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] How to "flatten" a XML fi, Martin Honnen | Thread | [xsl] Problems with xsl:result-docu, Luis A Ortiz |
[xsl] Resolved: Problems with xsl:r, Luis A Ortiz | Date | Re: [xsl] Some attribute not displa, lee qm |
Month |
Keywords