Subject: Re: [xsl] 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
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] To control node duplicati, George Cristian Bina | Thread | Re: [xsl] To control node duplicati, George Cristian Bina |
Re: [xsl] Re-arranging an XML file, Mike Stroud | Date | Re: [xsl] Using XSLT as a namespace, Ken Starks |
Month |