RE: [xsl] Selecting a tree...

Subject: RE: [xsl] Selecting a tree...
From: "McNally, David" <David.McNally@xxxxxxxxxx>
Date: Wed, 30 Jan 2002 12:47:30 -0500
I think this'll do it.  Rather than walking down the tree, I'm starting at
the bottom for each node, and walking back up, returning a TRUE value if I
ever hit a node with the correct rootname.  Then, if I get any TRUE values,
output the node - so each node only gets output once, no matter how many
true paths there are up to the rootname node.  There may be a way to handle
the test as a boolean - I'm just returning the string "TRUE" and then
testing for it.


<?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" select="'root1'"/>

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

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

<xsl:template match="subnode">
	<xsl:call-template name="outputElement"/>
</xsl:template>

<xsl:template match="node">
	<xsl:variable name="thisTest">
		<xsl:call-template name="testParents"/>
	</xsl:variable>
	<xsl:if test="contains($thisTest,'TRUE')">
		<xsl:call-template name="outputElement"/>
	</xsl:if> 
</xsl:template>

<xsl:template name="testParents">
	<xsl:choose>
		<xsl:when test="@name=$rootnode">
			<xsl:text>TRUE</xsl:text>
		</xsl:when> 
		<xsl:otherwise>
			<xsl:for-each
select="../node[subnode/@name=current()/@name]">
				<xsl:call-template name="testParents"/>
			</xsl:for-each>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template> 

<xsl:template name="outputElement">
	<xsl:element name="{name(.)}">
		<xsl:copy-of select="@*"/>
		<xsl:apply-templates/>
	</xsl:element>
</xsl:template>

</xsl:stylesheet>

David.

--
David McNally            Moody's Investors Service
Software Engineer        99 Church St, NY NY 10007 
David.McNally@xxxxxxxxxx            (212) 553-7475 

> -----Original Message-----
> From: Klaus-Georg Adams [mailto:Klaus-Georg.Adams@xxxxxxx]
> Sent: Wednesday, January 30, 2002 5:31 AM
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] Selecting a tree...
> 
> 
> 
> 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
> 


---------------------------------------

The information contained in this e-mail message, and any attachment thereto, is confidential and may not be disclosed without our express permission.  If you are not the intended recipient or an employee or agent responsible for delivering this message to the intended recipient, you are hereby notified that you have received this message in error and that any review, dissemination, distribution or copying of this message, or any attachment thereto, in whole or in part, is strictly prohibited.  If you have received this message in error, please immediately notify us by telephone, fax or e-mail and delete the message and all of its attachments.  Thank you.

Every effort is made to keep our network free from viruses.  You should, however, review this e-mail message, as well as any attachment thereto, for viruses.  We take no responsibility and have no liability for any computer virus which may be transferred via this e-mail message.

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


Current Thread