XSLT: Moving node in document

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Claudio Jolowicz

    XSLT: Moving node in document

    Suppose you have this document:

    <root>
    <node id="1">
    <node id="4"/>
    <node id="5"/>
    </node>
    <node id="2"/>
    <node id="3"/>
    </root>

    How to write an XSLT stylesheet to make the node with id=5 a child of
    the node with id=2?

    The resulting document should look as follows:

    <root>
    <node id="1">
    <node id="4"/>
    </node>
    <node id="2">
    <node id="5"/>
    </node>
    <node id="3"/>
    </root>

    Thanks,

    Claudio

    --
    ,= ,-_-. =. Claudio Jolowicz
    ((_/)o o(\_)) http://www.jolowicz.com
    `-'(. .)`-'
    \_/
  • David Carlisle

    #2
    Re: XSLT: Moving node in document


    mostly you want to copy

    <xsl:template match="*">
    <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    but you want to lose id 5

    <xsl:template match="node[@id='5']"/>

    and you want it to appear again in id 2

    <xsl:template match="node[@id='2']">
    <xsl:copy>
    <xsl:copy-of select="@*|//node[@id='5']"/>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    David

    Comment

    • Claudio Jolowicz

      #3
      Re: XSLT: Moving node in document

      Thanks, simple and elegant.

      Could you give me a hint how to parameterise this?

      The following approach doesn't seem to work:

      ------------------------------------------------------
      <xsl:styleshe et
      version="1.0"
      xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">

      <xsl:param name="nodeparen t" />
      <xsl:param name="nodeid" />

      <xsl:template match="*">
      <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
      </xsl:copy>
      </xsl:template>

      <xsl:template match="node[@id='{$nodeid}']"/>

      <xsl:template match="node[@id='{$nodepare nt}']">
      <xsl:copy>
      <xsl:copy-of select="@*|//node[@id='{$nodeid}']"/>
      <xsl:apply-templates/>
      </xsl:copy>
      </xsl:template>
      </xsl:stylesheet>
      ------------------------------------------------------

      Easy enough to put an <xsl:choose> construct inside the identity
      transform, and ignore the node satisfying "@id = $nodeid'. But how can
      we then add that node to $nodeparent?

      Claudio

      --
      ,= ,-_-. =. Claudio Jolowicz
      ((_/)o o(\_)) http://www.jolowicz.com
      `-'(. .)`-'
      \_/

      Comment

      • Volkm@r

        #4
        Re: XSLT: Moving node in document

        Claudio Jolowicz wrote:[color=blue]
        > Suppose you have this document:
        >
        > <root>
        > <node id="1">
        > <node id="4"/>
        > <node id="5"/>
        > </node>
        > <node id="2"/>
        > <node id="3"/>
        > </root>
        > [...][/color]

        Not yet tested, but ...

        <?xml version="1.0" encoding="UTF-8"?>
        <xsl:styleshe et version="1.0" xmlns="http://www.w3.org/1999/xhtml"
        xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">

        <!-- put "id=5" into "id=2" -->
        <xsl:template match="*[@id='2']">
        <xsl:copy>
        <xsl:apply-templates select="*[@id='5']"/>
        <xsl:apply-templates select="@*|node ()"/>
        </xsl:copy>
        </xsl:template>

        <!-- match "id=5" and do NOTHING -->
        <xsl:template match="*[@id='5']"/>

        <!-- copy all other stuff -->
        <xsl:template match="@*|node( )">
        <xsl:copy>
        <xsl:apply-templates select="@*|node ()"/>
        </xsl:copy>
        </xsl:template>
        </xsl:stylesheet>

        --
        Volkm@r

        Comment

        • David Carlisle

          #5
          Re: XSLT: Moving node in document

          [color=blue]
          > Could you give me a hint how to parameterise this?[/color]

          I knew you were going to ask that:-)

          <xsl:template match="node[@id='{$nodeid}']"/>


          that would never work, { _never_ has any special meaning in an XPath
          expression or, as here, in an XSLT pattern. They are used to _surround_
          Xpath expressions in XSLT Attribute value templates, but they are not
          part of Xpath.

          The syntax should be

          <xsl:template match="node[@id=$nodeid]"/>

          except that in a failed attempt to prevent circular definitions, any use
          of variables in match patterns is outlawed in XSLT1 so you can't do
          this. (You will be able to do it in XSLT2 as this restriction is
          dropped in XSLT2 draft.)

          Similarly for

          <xsl:copy-of select="@*|//node[@id='{$nodeid}']"/>

          except that here of course you can use a variable in XSLT1:

          <xsl:copy-of select="@*|//node[@id=$nodeid]"/>

          The reason why the restriction on variables in match patterns is
          annoying (and will be removed) is that it's easy to circumvent it, in
          this case for example you could do:

          <xsl:template match="node">
          <xsl:choose>
          <xsl:when test="@id='$nod eid"/>
          <xsl:otherwis e>
          <xsl:copy>
          <xsl:copy-of select="@*"/>
          <xsl:if test="@id=$node parent">
          <xsl:copy-of select="//node[@id='$nodeid']"/>
          </xsl:if>
          <xsl:apply-templates/>
          </xsl:copy>
          </xsl:otherwise>
          </xsl:choose>
          </xsl:template>

          Comment

          • David Carlisle

            #6
            Re: XSLT: Moving node in document



            oops sorry I left in two of your quotes

            <xsl:copy-of select="//node[@id='$nodeid']"/>
            ^ ^


            <xsl:copy-of select="//node[@id=$nodeid]"/>

            David

            Comment

            Working...