TAN-C-F-OK
TAN-C-F-OK

Reputation: 179

XSLT - xsl:for-each 238 iterations - I just want 1

My output is actually looking fine, but the xslt-prozessor does it 238 (exactly) times. Like he does 238 iterations, I get 238 copys of the same... The original XML-file has 1000 row-elements, the output XML-file has 238000 post-elemnts. What am I missing?

My XML

<csv_data><row>
    <stuff1>Stuff_here_1</stuff1>
    <stuff2>Stuff_here_2</stuff2>
    <stuff3>Stuff_here_3</stuff3>
    <stuff4>Stuff_here_4</stuff4>
    <stuff5>Here will be some text</stuff5>
</row>
<row>
    <stuff1>Stuff_here_11</stuff1>
    <stuff2>Stuff_here_22</stuff2>
    <stuff3>Stuff_here_33</stuff3>
    <stuff5>Here will be some text</stuff5>
</row></csv_data>

My XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
        <xsl:template match="csv_data">
        <TEI xmlns="http://www.tei-c.org/ns/1.0">
            <someHeader>
            <text>
                <body>
                    <div type="sometype">
                            <xsl:apply-templates select="@* | node()"/>
                    </div>
                </body>
            </text>
        </TEI>
    </xsl:template>
    <xsl:template match="//row">
            <xsl:for-each select="//row">
                <post attribute1="{stuff1}" attribute2="{stuff2}" attribute3="{stuff3}" attribute4="{stuff4}">
                   <p>
<xsl:value-of select="stuff5"/>
</p>
                    </post>
            </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 29

Answers (2)

Tomalak
Tomalak

Reputation: 338316

You are missing the fact that <xsl:apply-templates> already works like a loop. You don't need the <xsl:for-each> at all.

Write your <xsl:template match="row"> so that it produces the correct output for one <row>. The template will be executed multiple times automatically.

I recommend to a more specific <xsl:apply-templates> call, though. You only want to select <row> elements, so the logical thing would be to use select="row".

<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
>
    <xsl:template match="csv_data">
        <TEI xmlns="http://www.tei-c.org/ns/1.0">
            <someHeader>
            <text>
                <body>
                    <div type="sometype">
                        <xsl:apply-templates select="row" />
                    </div>
                </body>
            </text>
        </TEI>
    </xsl:template>

    <xsl:template match="row">
        <post attribute1="{stuff1}" attribute2="{stuff2}" 
            attribute3="{stuff3}" attribute4="{stuff4}" />
    </xsl:template>
</xsl:stylesheet>

Another thing to note is that you don't need to (and should not) write absolute XPaths in <xsl:template match="..."> expressions. Only part of the expression needs to match, so using match="//row" is unnecessary and match="row" is perfectly fine.

Upvotes: 2

Gottfried Lesigang
Gottfried Lesigang

Reputation: 67311

I think you can change //row to .

In these lines you define a template for any <row>

<xsl:template match="//row">
        <xsl:for-each select="//row">

The for-each will again(!) perform the action for any <row>

Try it like this

<xsl:template match="row">
        <xsl:for-each select=".">

The for-each will run with the data below the <row>

Upvotes: 1

Related Questions