Hofftari
Hofftari

Reputation: 106

How to use different xpath in a for-each loop for a XSLT transform

This is the issue: The transformed XSLT is supposed to show two phone numbers, <Phone_1> and <Phone_2>, one for each. The Fax tag is just added for reference.

This is a snippet of the XML I have to transform:

    <DirPartyContactInfoView>
        <Locator>08-922100</Locator>
        <Type>Phone</Type>
    </DirPartyContactInfoView>
        <Locator>073-6564865</Locator>
        <Type>Phone</Type>
    </DirPartyContactInfoView>    
        <Locator>08-922150</Locator>
        <Type>Fax</Type>
    </DirPartyContactInfoView>

And here's my current take on the XSLT for this snippet. So far I've tried setting a variable as a condition, knowing that it can only set the variable value once and not modify it.

<xsl:for-each select="DirPartyContactInfoView">
    <xsl:choose>
        <xsl:when test="Type='Phone'">
            <xsl:variable name="Phone1" />
            <xsl:choose>                                        
                <xsl:when test="Phone1=''">     
                    <xsl:variable name="Phone1" select="Locator" />                                 
                    <Phone_1>
                        <xsl:value-of select="Locator" />
                    </Phone_1>
                </xsl:when>
                <xsl:otherwise>
                    <Phone_2>
                        <xsl:value-of select="Locator" />
                    </Phone_2>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:when test="Type='Fax'">
            <Fax>
                <xsl:value-of select="Locator" />
            </Fax>
        </xsl:when>
    </xsl:choose>
</xsl:for-each>

Yet I get two <Phone_2> on the output, and I'm all out of ideas. I'm guessing I can't use a variable like this. Any way to fix this?

Upvotes: 0

Views: 471

Answers (3)

Michael Kay
Michael Kay

Reputation: 163458

@flaskis has responded to previous answers by changing the question, so I'm a bit reluctant to weigh in, but it might be that an appropraiate solution here is of the form

<xsl:template match="phone[1]">...</xsl:template>
<xsl:template match="phone[2]">...</xsl:template>

where different template rules are applied to the first and second phone elements.

Upvotes: 0

Mitya
Mitya

Reputation: 34576

That's hugely complicated for the (seemingly) simple requirements you have. If I've understood you right, try this:

<xsl:template match="/">
    <xsl:apply-templates select='root/DirPartyContactInfoView[Type="Phone"]' />
</xsl:template>
<xsl:template match='DirPartyContactInfoView'>
    <xsl:element name='phone_{position()}'>
        <xsl:value-of select='Locator' />
    </xsl:element>
</xsl:template>

I've assumed a root node root because your XML doesn't show us the root node you have.

Demo (see output source).

A good rule of thumb in XSLT is that, if you find yourself heavily relying on for-each constructs or variables, there's possibly a better way.

Upvotes: 1

Mark Veenstra
Mark Veenstra

Reputation: 4739

Do you really need to have a xsl:for-each loop? You can access the <Locator> element also directly with XPath:

 //DirPartyContactInfoView[1]/Locator
 //DirPartyContactInfoView[2]/Locator

If you still need the xsl:for-each loop, maybe something like this helps:

<xsl:for-each select="DirPartyContactInfoView">
    <xsl:choose>
        <xsl:when test="Type='Phone'">
            <xsl:choose>                                        
                <xsl:when test="position()='1'">     
                    <Phone_1>
                        <xsl:value-of select="Locator" />
                    </Phone_1>
                </xsl:when>
                <xsl:otherwise>
                    <Phone_2>
                        <xsl:value-of select="Locator" />
                    </Phone_2>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
    </xsl:choose>
</xsl:for-each>

Upvotes: 1

Related Questions