[xsl] creating container elements

Subject: [xsl] creating container elements
From: Rob Exley <rob.exley@xxxxxxxxxxx>
Date: Tue, 6 Apr 2004 13:05:44 +0100
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This is the first time I have looked at XSLT in anger and have what I thought 
was a simple question.

Given an input document containing amongst other things a recurring element I 
would like to create a container element in the output document. To my mind 
this was a case of output an opening container tag prior to the first 
occurrent of the recurrent element and a closing tag after the last 
occurrence.

When I first approached this I tried using something such as

<xsl:if test="postion() = 1">
  <container>
</xsl:if>

but this complained as it was not valid XML.

Upon seeking advice from a colleague it was suggested I use modes to control 
the output and output the container element in the template matching the 
first element. Given the following test document

<foo>
  <bar id="bar-1">
    <barfoo id="barfoo-1"/>
  </bar>
  <bar id="bar-2">
    <barfoo id="barfoo-2"/>
  </bar>
  <bar id="bar-3">
    <barfoo id="barfoo-3"/>
  </bar>
</foo>

My XSL looked like the following:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
xmlns:xalan="http://xml.apache.org/xslt"; exclude-result-prefixes="xalan">
  <xsl:output method="xml" indent="yes" xalan:indent-amount="2" />

  <xsl:template match="foo">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="bar[1]">
    <xsl:element name="container">
      <xsl:apply-templates select="../bar" mode="standard"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="bar" mode="standard">
    <xsl:element name="foobar">
      <xsl:attribute name="id">
        <xsl:value-of select="@id"/>
      </xsl:attribute>
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

  <xsl:template match="barfoo">
    <xsl:element name="barfoo">
      <xsl:value-of select="@id"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

The following is my resulting document:

<?xml version="1.0" encoding="UTF-8"?>
<foo>
  <container>
    <foobar id="bar-1">
    <barfoo>barfoo-1</barfoo>
  </foobar>
    <foobar id="bar-2">
    <barfoo>barfoo-2</barfoo>
  </foobar>
    <foobar id="bar-3">
    <barfoo>barfoo-3</barfoo>
  </foobar>
  </container>

    <barfoo>barfoo-2</barfoo>


    <barfoo>barfoo-3</barfoo>

</foo>

Which seems to have spurious <barfoo> elements following the closing 
</container> element. From my continued efforts I seem to have this down to 
the behaviour when using the mode and I can resolve this be added the mode 
attribute to my <barfoo> template match. I am suprised I need this as I would 
have thought it would work without this.

I would appreciate any help anyone can give regarding this. How should this be 
done and any explanation as to why this occurs.

FYI - the following is the required information regarding the xslt engine I am 
using which for this was Xalan-J 2.5.2

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/TR/xhtml1/strict"; 
xmlns:msxsl="http://www.w3.org/TR/WD-xsl";><head><title>XSLT Processor 
Version</title></head><body><msxsl:choose><msxsl:when 
test="."/><msxsl:otherwise><p>Vendor: Apache Software Foundation<br/>Vendor 
URL:
              http://xml.apache.org/xalan-j</p></msxsl:otherwise></msxsl:choose></body></html>

- --
Rob Exley <rob.exley@xxxxxxxxxxx>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFAcp0bIQSbu4H8vOQRAjRFAJ4v5J+7uHGAfZbcXuNtnI6DOiY1EACfbOqY
R2d67/fWJCit11WOpF/dNC8=
=5Agl
-----END PGP SIGNATURE-----

Current Thread