1
votes

I'm creating a csv from an xml file using xslt. The xml document I'm actually working with is enormous, but I am stuck on an issue and have a simplified example below.

I'm attempting to create something like this

Item1,Item2,Item3,Item4,Item5,

1,2,3,,,

1,2,3,4,,

1,2,3,4,5,

1,2,,,,

My highest item count is how many column names I will need. I will then need each items group to print out its values, and also keep iterating and plugging in empty values up to the highest count. I need to do this because I have no idea how many items in a group I will have, so I want to eventually create a db table that has up to the highest count of items... Its confusing and hard and that is why I need help.

My xml

<example>
<items>
    <item>1</item>
    <item>2</item>
    <item>3</item>
</items>
<items>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
</items>
    <items>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
    <item>5</item>
</items>
<items>
    <item>1</item>
    <item>2</item>
</items>

My xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/" name="test">
    <xsl:for-each select="example/items">
            <xsl:sort select="count(item)" data-type="number" order="descending"/>
            <xsl:if test="position() = 1">
                <xsl:value-of select="count(item)"/>
            </xsl:if>
    </xsl:for-each>
</xsl:template>

So far I've been able to get the number of the highest count out of all the groups, which is 5. Can I some how use this number to generate the rest of my output?

Any help would be greatly appreciated :)

1
The logic of the requested process is not quite clear. Do you simply want to enumerate all given items as "item1,item2,item3 ... item14" or is there something else?michael.hor257k
Well its a little more complicated than what I have placed here, but initially I am using the for-each to get the item counts for each items group and then I want to use the highest count, in this case it's 5 and then use this number as a marker for my iteration. I would like my final result to be item1,item2,item3,item4,item5, printed out to the screen. As of now Im getting an error "Error loading stylesheet: Parsing an XSLT stylesheet failed." So I think I'm close, but am not sure where I went wrong as I am basing what I have off of several examples I have looked at.Taylor Tay
You are currently calling a template that iterates through your items that calls a template that iterates through your items that calls... well you get the idea.Matthew Green
I have been using xslt for a week so I dont really get it... Help :)Taylor Tay
I am afraid you haven't answered my question at all. I suggest you edit your question and post the entire result you're hoping to get from the input. I suspect that changing the input to something less abstract would also help in understanding what are you trying to accomplish here.michael.hor257k

1 Answers

2
votes

Try it this way?

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:variable name="maxCount">
    <xsl:for-each select="/example/items">
        <xsl:sort select="count(item)" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
            <xsl:value-of select="count(item)"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="maxItems" select="/example/items[count(item)=$maxCount][1]" />

<xsl:template match="/">
    <!-- header -->
     <xsl:for-each select="$maxItems/item">
        <xsl:text>Item</xsl:text>
        <xsl:value-of select="position()"/>
        <xsl:text>,</xsl:text>
     </xsl:for-each>
     <xsl:text>&#10;</xsl:text>
    <!-- rows -->
    <xsl:for-each select="example/items">
        <xsl:variable name="this" select="."/>
        <xsl:for-each select="$maxItems/item">
            <xsl:variable name="i" select="position()"/>
            <xsl:value-of select="$this/item[$i]"/>
                <xsl:text>,</xsl:text>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
     </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Or, if you prefer:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:variable name="maxCount">
    <xsl:for-each select="/example/items">
        <xsl:sort select="count(item)" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
            <xsl:value-of select="count(item)"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

<xsl:template match="/">
    <!-- header -->
    <xsl:call-template name="header"/>
    <xsl:text>&#10;</xsl:text>
    <!-- rows -->
    <xsl:for-each select="example/items">
        <xsl:call-template name="row"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

<xsl:template name="header">
    <xsl:param name="i" select="1"/>
    <xsl:if test="$i &lt;= $maxCount">
        <xsl:text>Item</xsl:text>
        <xsl:value-of select="$i"/>
        <xsl:text>,</xsl:text>
        <!-- recursive call -->
        <xsl:call-template name="header">
            <xsl:with-param name="i" select="$i + 1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name="row">
    <xsl:param name="i" select="1"/>
    <xsl:if test="$i &lt;= $maxCount">
        <xsl:value-of select="item[$i]"/>
        <xsl:text>,</xsl:text>
        <!-- recursive call -->
        <xsl:call-template name="row">
            <xsl:with-param name="i" select="$i + 1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>