[xsl] Selecting a tree...

Subject: [xsl] Selecting a tree...
From: Klaus-Georg Adams <Klaus-Georg.Adams@xxxxxxx>
Date: Wed, 30 Jan 2002 11:31:29 +0100 (MET)
Hi,
I have an XML file which represents multiple trees like so:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE document [
<!ELEMENT document (node*)>
<!ELEMENT node (subnode*)>
<!ATTLIST node name NMTOKEN #REQUIRED
               isroot (true|false) "false">
<!ELEMENT subnode EMPTY>
<!ATTLIST subnode name NMTOKEN #REQUIRED>
]>
<document>
  <node name="root1" isroot="true">
    <subnode name="node1"/>
    <subnode name="node2"/>
  </node>
  <node name="root2" isroot="true">
  </node>
  <node name="node1">
    <subnode name="node3"/>
  </node>
  <node name="node2">
    <subnode name="node3"/>
  </node>
  <node name="node3"/>
</document>

A node can refer to subnodes by their name. Names are unique. There
can be multiple roots in the XML file. A node can be referenced
multiple times in any given tree.

I would like to write a stylesheet which gets as parameter a nodename
of a rootnode, and which spits out an XML file containing all nodes
referenced by the tree, but, and here's the catch: only once for each
node.

Thus, the transformation should remove root2 from the XML file above
if $rootnode is set to root1.

Following the tree and spitting out all nodes in that tree is easy:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0">

  <xsl:output method="xml"
    indent="yes"/>

  <xsl:param name="rootnode"/>

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

  <xsl:template match="document">
    <document>
      <xsl:apply-templates select="node[@name = $rootnode]" mode="follow"/>
    </document>
  </xsl:template>

  <xsl:template match="node" mode="follow">
    <xsl:apply-templates select="."/>
    <xsl:apply-templates select="//node[@name=current()/subnode/@name]" mode="follow"/>
  </xsl:template>

  <!-- identity transformation -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

But this will spit out nodes as often as they apear in the tree. Does
anybody see a way around this?

The only solution I can think of (in pure XSLT) would need two
transformations: the first would write an intermediate file with a
list of nodenames which have to appear in the final document (with
duplicates) and a second one, which would remove the duplicates and
write the real output file.

Is there a way to do it in one transformation?

Regards, kga


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread