Re: [xsl] To control node duplication

Subject: Re: [xsl] To control node duplication
From: George Cristian Bina <george@xxxxxxxxxxxxx>
Date: Tue, 13 Jan 2009 09:45:09 +0200
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