Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old September 5th, 2003, 11:49 PM
Registered User
 
Join Date: Sep 2003
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default Losing parameters in <for-each> block?

Hi all. I have been pulling out my hair trying to figure this one out.

I am writing an XSLT to merge two xml files together using a 3rd xml file as a guide telling me what needs to be updated vs. what just needs to be copied. Everything seems to go OK until I call a recursive template from some other template passing in some parameters. At this point my recursive template begins acting weird: If I stay out of a <xsl:for-each> block, I can still use the parameter I passed in. However, if I try to use this parameter within this block...poof! it's empty! Even stranger, this approach has no problems when I used XSelerator 2.6 to write it (I have the problem using Microsoft's .NET Processor) Here is basically what I'm doing:


<xsl:template name="recursiveTemplate">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>

    <xsl:call-template name="doStuffwAttributes">
        <xsl:with-param name="aNode" select="$aNode"/>
        <xsl:with-param name="bNode" select="$bNode"/>
    </xsl:call-template>

    <xsl:for-each select="*">
        <xsl:choose>
            <xsl:when test="some condition is met">
                <xsl:call-template name="auxillaryTemplate">
                    <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
                    <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="recursiveTemplate">
                    <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
                    <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>




<xsl:template name="doStuffwAttributes">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>

        ...$aNode and $bNode contain nodes for all cases at this scope
    <xsl:for-each select="@*">
        ...do stuff with $aNode and $bNode
               ...but $aNode and $bNode are empty in this context
if auxiallryTemplate is down the stack </xsl:for-each>

</xsl:template>



<xsl:template name="auxillaryTemplate">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>

    ...do stuff
    <xsl:for-each select="*">
        <xsl:call-template name="recursiveTemplate">
            <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
            <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
        </xsl:call-template>
    </xsl:for-each>

</xsl:template>


Thanks in advance.


 
Old September 6th, 2003, 03:58 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

Hi,

In the following code-snippet

Quote:
quote:
       ...$aNode and $bNode contain nodes for all cases at this scope
    <xsl:for-each select="@*">
        ...do stuff with $aNode and $bNode
               ...but $aNode and $bNode are empty in this context
if auxiallryTemplate is down the stack </xsl:for-each>
before executing the xsl:for-each instruction, the current node may be of any type(you didn't show us the entire stylesheet: we can't see the current node-set). I guess you are confused by that: if that current node is not an element-node, the xsl:for-each will never be executed(since the XPath expression "@*" will return empty node-set), and may be you put xsl:value-of inside it to test the values of aNode and bNode(which will be never reached if the context node before executing the xsl:for-each is not an element node). Or the context node can be an element node, but without attributes and the same effect will be reached. I think the recursion (the stack, etc.) doesn't matter here. Try to separate the template "doStuffwAttributes" and call it separately(without changing the current node-set, of course): localize the problem. Theoretically, if the isolated template will work fine, it should work in the context of the templates you presented.

Hope this helps.

Regards,
Armen
 
Old September 6th, 2003, 01:16 PM
Registered User
 
Join Date: Sep 2003
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanks for the reply armmarti.

I'm sorry I can't post the actual stylesheet.
I'll try and clarify:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="A"/>
<xsl:param name="B" select="'guideDocument.xml'"/>
<xsl:variable name="aRootNode" select="$A"/>
<xsl:variable name="bRootNode" select="document($B)"/>

<xsl:template match select = "/">
   <xsl:apply-templates/>
<xsl:template/>

<xsl:template match="*">
    <xsl:copy>
    <xsl:call-template name="MergeNode">
        <xsl:with-param name="aNode" select="$aRootNode/*[1]"/>
        <xsl:with-param name="bNode" select="$bRootNode/*[1]"/>
    </xsl:call-template>



    </xsl:copy>
</xsl:template>
Elements are the only nodes that are in context when 'recursiveTemplate' is called. And I'm positive that that this node contains attributes. In the following code snippet:

 
Quote:
quote: <xsl:for-each select="@*">
Quote:
        ...do stuff with $aNode and $bNode
               ...but $aNode and $bNode are empty in this context
if auxiallryTemplate is down the stack </xsl:for-each>
 for-each select ="@*" does not return an empty node set because I put an
<xsl:comment>This is the name of $aNode: <xsl:value-of select="name($aNode)"/></xsl:comment> inside the for-each block just to see what was happening. In this case, name($aNode) returns nothing. But if I put this same line of code, outside of the <xsl:for-each select="@*">, name($aNode) gives me SomeNodeName. And again, I've only seen this behavior when 'auxillaryTemplate' gets called and only on a certain processor.

Again, thanks for replying

 
Old September 6th, 2003, 05:04 PM
Registered User
 
Join Date: Sep 2003
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

whoops...."MergeNode" should be recursiveTemplate

 
Old September 8th, 2003, 02:07 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

Ok,
I'm using Saxon 6.5.2 and the code presented below is working fine.

Here is the stylesheet(I changed it slightly by adding debug-messages):
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:param name="A" select="'document.xml'"/>
<xsl:param name="B" select="'guideDocument.xml'"/>
<xsl:variable name="aRootNode" select="document($A)"/>
<xsl:variable name="bRootNode" select="document($B)"/>

<xsl:template match="/">
   <xsl:apply-templates/>
</xsl:template>

<xsl:template match="*">
    <xsl:copy>
    <xsl:call-template name="recursiveTemplate">
        <xsl:with-param name="aNode" select="$aRootNode/*[1]"/>
        <xsl:with-param name="bNode" select="$bRootNode/*[1]"/>
        <xsl:with-param name="depth" select="1"/>
    </xsl:call-template>
    </xsl:copy>
</xsl:template>

<xsl:template name="recursiveTemplate">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>
    <xsl:param name="depth"/>
    <p>
        [recursiveTemplate  called in depth <xsl:value-of select="$depth"/> !]
    </p>

    <xsl:call-template name="doStuffwAttributes">
        <xsl:with-param name="aNode" select="$aNode"/>
        <xsl:with-param name="bNode" select="$bNode"/>
    </xsl:call-template>

    <xsl:for-each select="*">
        <xsl:choose>
            <xsl:when test="position() mod 2 = 0">
                <xsl:call-template name="auxillaryTemplate">
                    <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
                    <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
                    <xsl:with-param name="depth" select="$depth"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="recursiveTemplate">
                    <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
                    <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
                    <xsl:with-param name="depth" select="$depth + 1"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>




<xsl:template name="doStuffwAttributes">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>
    <p>
        [doStuffwAttributes called!]<br/>
        current node is <b><xsl:value-of select="name(current())"/></b>
    </p>


    doStuffwAttributes: aNode contains <xsl:value-of select="count($aNode)"/> node(s). <br/>
    doStuffwAttributes: bNode contains <xsl:value-of select="count($bNode)"/> node(s). <br/>     
    <xsl:for-each select="@*">
        doStuffwAttributes (inside for-each):   aNode contains <xsl:value-of select="count($aNode)"/> node(s). <br/>
        doStuffwAttributes (inside for-each):   bNode contains <xsl:value-of select="count($bNode)"/> node(s). <br/>     
    </xsl:for-each>
</xsl:template>



<xsl:template name="auxillaryTemplate">
    <xsl:param name="aNode"/>
    <xsl:param name="bNode"/>
    <xsl:param name="depth"/>
    <p>
        [auxillaryTemplate called!]<br/>
        current node is <b><xsl:value-of select="name(current())"/></b>
    </p>
    <xsl:for-each select="*">
        <xsl:call-template name="recursiveTemplate">
            <xsl:with-param name="aNode" select="$aNode/*[name() = name(current())]"/>
            <xsl:with-param name="bNode" select="$bNode/*[name() = name(current())]"/>
            <xsl:with-param name="depth" select="$depth + 1"/>
        </xsl:call-template>
    </xsl:for-each>

</xsl:template>


</xsl:stylesheet>
where
1) source XML doc to which the stylesheet is applied is:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<root attr="a0">
    <child1 attr1="a1" attr2="a2">
        <child11 attr11="a11" attr2="a2" attr3="a3"/>
    </child1>
    <child2 attr1="a1" attr2="a2">
        <child21 attr11="a11" attr2="a2" attr3="a3"/>
    </child2>
</root>
1) document.xml is:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <x-el1>initial element 1</x-el1>
    <x-el2>initial element 2</x-el2>
</doc>
3) guideDocument.xml is:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<guide>
    <el1>element 1</el1>
    <el2>element 2</el2>
</guide>
and the output I get is(the output is malformed HTML, which is just a debug-stuff):

*******************************************

[recursiveTemplate called in depth 1 !]

[doStuffwAttributes called!]
current node is root

doStuffwAttributes: aNode contains 1 node(s).
doStuffwAttributes: bNode contains 1 node(s).
doStuffwAttributes (inside for-each): aNode contains 1 node(s).
doStuffwAttributes (inside for-each): bNode contains 1 node(s).

[recursiveTemplate called in depth 2 !]

[doStuffwAttributes called!]
current node is child1

doStuffwAttributes: aNode contains 0 node(s).
doStuffwAttributes: bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).

[recursiveTemplate called in depth 3 !]

[doStuffwAttributes called!]
current node is child11

doStuffwAttributes: aNode contains 0 node(s).
doStuffwAttributes: bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).

[auxillaryTemplate called!]
current node is child2

[recursiveTemplate called in depth 2 !]

[doStuffwAttributes called!]
current node is child21

doStuffwAttributes: aNode contains 0 node(s).
doStuffwAttributes: bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
doStuffwAttributes (inside for-each): aNode contains 0 node(s).
doStuffwAttributes (inside for-each): bNode contains 0 node(s).
************************************

The output shows(the first pass of the recursion) that the values of those variables are the same inside and outside the xsl:for-each.
To get richer output, you can change the XPath expressions $aNode/*[name() = name(current())] and $bNode/*[name() = name(current())], or alternatively change the appropriate element types in the input XML documents.
If your output is different from mine, it probably means that there is a bug in the XSLT processor you're using (the output I get here is expected one, and also Saxon 6.5.2 is reliable enough upon my experience).

Regards,
Armen





Similar Threads
Thread Thread Starter Forum Replies Last Post
Ch 8: <asp:image> inside <a> & ext.CSS (pg. 274) epc BOOK: Beginning ASP.NET 3.5 : in C# and VB BOOK ISBN: 978-0-470-18759-3 1 July 12th, 2008 04:37 AM
<style> tags in a <body> vs. <div> bcat BOOK: Beginning CSS: Cascading Style Sheets for Web Design ISBN: 978-0-7645-7642-3 1 March 27th, 2005 08:50 AM
<marquee><b>About CHAT App. in PHP4</b></marquee> Ramkrishna PHP How-To 1 September 11th, 2004 07:01 AM
line-height -n- background-color with <DIV> block anshul HTML Code Clinic 11 September 5th, 2004 02:15 PM
<STRONG> vs <B> and <EM> vs <I> anshul HTML Code Clinic 12 September 1st, 2004 05:22 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.