Subject: Re: To control node duplication
From: "nick public" <nickpubl@xxxxxxxxx>
Date: Wed, 14 Jan 2009 10:28:34 +0100
|
Hi George.
Thank you very much for your precious help.
I analyzed your implementation and I realized that the trick to
bypass, in this case, the reset variable limitation is to recall the
processLevel template
passing it a new instance of $states shifting each time the first char
by one to right. Since the processLevel just take the first char by
$states, I have obtained my scope to provide each time a different
value of $states. Great! :-))
> <xsl:template name="processLevel">
> <xsl:param name="states"/>
> <xsl:if test="string-length($states)>0">
> <xsl:apply-templates mode="copy">
> <xsl:with-param name="state" select="substring($states, 1, 1)"/>
> </xsl:apply-templates>
> <xsl:call-template name="processLevel">
> <xsl:with-param name="states" select="substring($states, 2,
> string-length($states))"/>
> </xsl:call-template>
> </xsl:if>
> </xsl:template>
The way to exit by the recorsion is the empty $states
<xsl:if test="string-length($states)>0">
The thing that I have not understood is the attribute mode="copy" that
you use in the template statements calling and called. Seems that
works without it too.
Really, thank you very much, George. You have solved my problem and I
have learned something by you about XSLT Language.
Ciao. Nicola
2009/1/13 George Cristian Bina <george@xxxxxxxxxxxxx>:
> For XSLT 1.0 you can replace the for each with a recursive template as
> below:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> <xsl:template match="root">
> <xsl:copy><xsl:apply-templates/></xsl:copy>
> </xsl:template>
>
> <xsl:template match="level">
> <xsl:variable name="level" select="."/>
> <xsl:call-template name="processLevel">
> <xsl:with-param name="states" select="states"/>
> </xsl:call-template>
> </xsl:template>
>
> <xsl:template name="processLevel">
> <xsl:param name="states"/>
> <xsl:if test="string-length($states)>0">
> <xsl:apply-templates mode="copy">
> <xsl:with-param name="state" select="substring($states, 1, 1)"/>
> </xsl:apply-templates>
> <xsl:call-template name="processLevel">
> <xsl:with-param name="states" select="substring($states, 2,
> string-length($states))"/>
> </xsl:call-template>
> </xsl:if>
> </xsl:template>
>
> <xsl:template match="node() | @*" mode="copy">
> <xsl:param name="state"/>
> <xsl:copy>
> <xsl:apply-templates select="node() | @*" mode="copy">
> <xsl:with-param name="state" select="$state"/>
> </xsl:apply-templates>
> </xsl:copy>
> </xsl:template>
>
> <xsl:template match="elem1/text()" mode="copy">
> <xsl:param name="state"/>
> <xsl:value-of select="."/>
> <xsl:text>_</xsl:text>
> <xsl:value-of select="$state"/>
> </xsl:template>
> </xsl:stylesheet>
>
> Best Regards,
> George
> --
> George Cristian Bina
> <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
> http://www.oxygenxml.com
>
> nick public wrote:
>>
>> Hi George,
>> I appreciate very much your help.
>> Unfortunately, the middleware that I'm using and in which the XSLT
>> have to run, provide just XSLT version 1.0.
>> Is it possible to adapt your solution for XSLT 1.0?
>>
>> I tried to think to an alternative way but it seems a lot of complicated.
>> I could create three different versions of my script; each version is
>> specialized to work with a single status:
>> 1) script_4.xslt - evaluates the presence of status 4: if yes copies
>> <level> and modifies <elem1> with 4 status
>> 2) script_5.xslt - evaluates the presence of status 5: if yes,
>> appendes to the previous a new <level> copy with <elem1> modified with
>> 5 status. If 5 status doesn't exist, the output provided has to be
>> that of script_4.xslt
>> 3) script_6.xslt - evaluates the presence of status 6: if yes,
>> appendes to the previous a new <level> copy with <elem1> modified with
>> 6 status. If 6 status doesn't exist, the output provided has to be
>> that of script_5.xslt
>>
>> At the end, I could concatenate the three scripts in a job and should
>> obtain (I hope) the same result.
>>
>> Opinion about?
>>
>> Thanks a lot.
>> Ciao. Nicola
>>
>>
>> 2009/1/13 George Cristian Bina <george@xxxxxxxxxxxxx>:
>>>
>>> In XSLT 2.0 you can use something like this:
>>>
>>> <?xml version="1.0" encoding="UTF-8"?>
>>> <xsl:stylesheet version="2.0"
>>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>>> <xsl:template match="root">
>>> <xsl:copy><xsl:apply-templates/></xsl:copy>
>>> </xsl:template>
>>>
>>> <xsl:template match="level">
>>> <xsl:variable name="level" select="."/>
>>> <xsl:for-each select="string-to-codepoints(states)">
>>> <xsl:apply-templates select="$level" mode="copy">
>>> <xsl:with-param name="state" select="."/>
>>> </xsl:apply-templates>
>>> </xsl:for-each>
>>> </xsl:template>
>>>
>>> <xsl:template match="node() | @*" mode="copy">
>>> <xsl:param name="state"/>
>>> <xsl:copy>
>>> <xsl:apply-templates select="node() | @*" mode="copy">
>>> <xsl:with-param name="state" select="$state"/>
>>> </xsl:apply-templates>
>>> </xsl:copy>
>>> </xsl:template>
>>>
>>> <xsl:template match="elem1/text()" mode="copy">
>>> <xsl:param name="state"/>
>>> <xsl:value-of select="."/>
>>> <xsl:text>_</xsl:text>
>>> <xsl:value-of select="codepoints-to-string($state)"/>
>>> </xsl:template>
>>> </xsl:stylesheet>
>>>
>>> on your sample input it gives
>>>
>>> <root>
>>> <level>
>>> <states>456</states>
>>> <start>
>>> <elem1>element_4</elem1>
>>> </start>
>>> </level><level>
>>> <states>456</states>
>>> <start>
>>> <elem1>element_5</elem1>
>>> </start>
>>> </level><level>
>>> <states>456</states>
>>> <start>
>>> <elem1>element_6</elem1>
>>> </start>
>>> </level>
>>> </root>
>>>
>>> Best Regards,
>>> George
>>> --
>>> George Cristian Bina
>>> <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
>>> http://www.oxygenxml.com
>>>
>>> nick public wrote:
>>>>
>>>> Hi people.
>>>> I have the following need.
>>>> I have to duplicate a sub-tree basing of an element <states> contained
>>>> into the source XML.
>>>>
>>>> <root>
>>>> <level>
>>>> <states>456</states>
>>>> <start>
>>>> <elem1>element</elem1>
>>>> </start>
>>>> </level>
>>>> </root>
>>>>
>>>>
>>>> For each <level> copy, the <elem1> element have to contain the
>>>> corresponding states byte.
>>>> In this case I've create a XML target containing 3 <level> element and
>>>> for each copy, the <elem1> element contains the 4, 5 and 6 status.
>>>>
>>>> The target for the example have to be like this:
>>>>
>>>> <root>
>>>> <level>
>>>> <control>456</control>
>>>> <start>
>>>> <elem1>element_4</elem1>
>>>> </start>
>>>> </level>
>>>> <level>
>>>> <control>456</control>
>>>> <start>
>>>> <elem1>element_5</elem1>
>>>> </start>
>>>> </level>
>>>> <level>
>>>> <control>456</control>
>>>> <start>
>>>> <elem1>element_6</elem1>
>>>> </start>
>>>> </level>
>>>> </root>
>>>>
>>>> Now, I learned thanks to you how to copy the sub-tree. I haven't
>>>> problem with string processing.
>>>> My problem is to control the copy.
>>>> I need something like this (please, don't become frightened: it's the
>>>> minimal code and is commented)
>>>>
>>>> <?xml version="1.0" encoding="utf-8"?>
>>>> <xsl:stylesheet version="1.0"
>>>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>>>> <xsl:output method="xml" indent="yes"/>
>>>>
>>>> <!-- Load in a variable the states to manage -->
>>>> <xsl:variable name='states' select ='root/level/states'/>
>>>>
>>>> <xsl:template match="level">
>>>> <!-- Predisposes to manage all the three states
>>>> passing as parameter each status to check in
>>>> front to the states variable -->
>>>>
>>>> <!-- Invokes copyNode for the status 4.
>>>> In copyNodes, if 4 is contained in states
>>>> variable the level element will be copied
>>>> otherwise no -->
>>>> <xsl:call-template name='copyNode'>
>>>> <xsl:with-param name='status' select='4'/>
>>>> </xsl:call-template>
>>>>
>>>> <xsl:call-template name='copyNode'>
>>>> <xsl:with-param name='status' select='5'/>
>>>> </xsl:call-template>
>>>>
>>>> <xsl:call-template name='copyNode'>
>>>> <xsl:with-param name='status' select='6'/>
>>>> </xsl:call-template>
>>>> </xsl:template>
>>>>
>>>> <xsl:template match="@*|node()">
>>>> <xsl:copy>
>>>> <xsl:apply-templates select="@*|node()"/>
>>>> </xsl:copy>
>>>> </xsl:template>
>>>>
>>>> <xsl:template name="copyNode">
>>>> <xsl:param name='status'/>
>>>>
>>>> <!-- Checks if the current $status (4, 5 or 6)
>>>> is contained in the $states.
>>>> If yes, can copies the level element -->
>>>> <xsl:if test='contains($states,$status)'>
>>>>
>>>> <xsl:choose>
>>>> <!-- :-(( THIS when SEEMS NEVER PERFORMED :-(( -->
>>>> <xsl:when test="self::elem1">
>>>> <elem1>
>>>> <!-- The elem1 text value have to be manipulated by $status
>>>> -->
>>>> <xsl:value-of select ='concat(substring(.,1,5),$status)'/>
>>>> </elem1>
>>>> </xsl:when>
>>>>
>>>> <xsl:otherwise>
>>>> <xsl:copy-of select="."/>
>>>> </xsl:otherwise>
>>>> </xsl:choose>
>>>>
>>>> </xsl:if>
>>>> </xsl:template>
>>>>
>>>> </xsl:stylesheet>
>>>>
>>>> The critical point is that the <xsl:when test="self::elem1"> is
>>>> never reached and then I cannot operate the tranformation.
>>>>
>>>>
>>>> Could you help me URGENTLY?
>>>> Thanks a lot in advance.
>>>>
>>>> Ciao. Nicola
|