Yalmar
Yalmar

Reputation: 435

xslt move node inside sibling node part 2

This is a further question to what I posted on xslt move node inside sibling node

This is my input:

<div class="a" >aaa
  <div class="b">b1</div>
  <div class="c">b1c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="b">b2</div>
  <div class="c">b2c1</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="b">b3</div>
  <div class="c">b3c1</div>
  <div class="d">b3d1</div>
</div>

and this is the output I would like to get:

<div class="a" >aaa
  <div class="b">b1
    <div class="c">b1c1</div>
    <div class="d">b1d1</div>
    <div class="d">b1d2</div>
  </div>
  <div class="b">b2
    <div class="c">b2c1</div>
    <div class="d">b2d1</div>
    <div class="d">b2d2</div>
    <div class="d">b2d3</div>
  </div>
  <div class="b">b3
    <div class="c">b3c1</div>
    <div class="d">b3d1</div>
  </div>
</div>

The only difference from the previous problem is that has a value, that is aaa.

I am using the following xslt:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])" />

 <!-- Identity template, copies everything as is -->
 <xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>

 <!-- Override for target element -->
 <xsl:template match="div[@class='a']">
  <xsl:copy>
   <xsl:apply-templates select="@*|div[@class='b']"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="div[@class='b']">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()" />
   <xsl:apply-templates select="key('b', generate-id())" />
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

But it gives me the following result, that is "aaa" (after div class="a") has disappeared :(

<div class="a" >
  <div class="b">b1
    <div class="c">b1c1</div>
    <div class="d">b1d1</div>
    <div class="d">b1d2</div>
  </div>
  <div class="b">b2
    <div class="c">b2c1</div>
    <div class="d">b2d1</div>
    <div class="d">b2d2</div>
    <div class="d">b2d3</div>
  </div>
  <div class="b">b3
    <div class="c">b3c1</div>
    <div class="d">b3d1</div>
  </div>
</div>

What am I doing wrong? I thank you in advance for your help.

Upvotes: 0

Views: 86

Answers (1)

Tim C
Tim C

Reputation: 70618

The problem is with this line, in the template that matches "div[@class='a']"

<xsl:apply-templates select="@*|div[@class='b']"/>

This select attributes, and divs with class "b", but it does not select anything else, including text nodes. Replace it with this to select your "aaa" text

<xsl:apply-templates select="@*|text()|div[@class='b']"/>

Alternatively, this would also work

<xsl:apply-templates select="@*|node() except div[@class !='b']"/>

Upvotes: 1

Related Questions