Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old September 23rd, 2010, 10:11 AM
Authorized User
 
Join Date: Jan 2010
Posts: 12
Thanks: 2
Thanked 0 Times in 0 Posts
Default How to copy all elements within the path to the root

Hello,

I am looking for some hours for a solution for a very simple problem:
Copy all leaves from a tree with all elements on the way to the root.

I tried:

java -jar saxon9he.jar -s:in.xml -xsl:test.xsl -o:out.xml

in.xml

Code:
<nodes>
	<node id="a1">
		<node id="b1">
			<node id="c1"/>
			<node id="c2"/>
		</node>
	</node>
	<node id="a2"/>
</nodes>
test.xsl

Code:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- copy elements without children including all the elements within the path to the root (i.e. full path)  -->
<xsl:template match="/">
	<nodes>
		<xsl:apply-templates />
	</nodes>
</xsl:template>

<xsl:template match="node[not(descendant::node)]"> 
	<xsl:for-each select="ancestor-or-self::*[count(ancestor::*)>0]"> 
		<node id="{@id}" />
	</xsl:for-each> 
</xsl:template> 
 
</xsl:stylesheet>
out.xml should be a simple copy of the "full path" to the elements, that do not have any children

Code:
<nodes>
	<node id="a1">
		<node id="b1">
			<node id="c1"/>
		</node>
	</node>
	<node id="a1">
		<node id="b1">
			<node id="c2"/>
		</node>
	</node>
	<node id="a2"/>
</nodes>

with the given stylesheet the xml transforms to a list (not surprisingly).

Code:
<nodes>
<node id="a1"/><node id="b1"/><node id="c1"/>
<node id="a1"/><node id="b1"/><node id="c2"/>
<node id="a2"/>
</nodes>
Any hints how to copy all ancestors of a given node?

Best regards

Chrsitian
 
Old September 23rd, 2010, 10:30 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Interesting problem, here is an XSLT 2.0 stylesheet that does the job with Saxon 9, at least for the sampleinput you posted:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="descendant::*[not(node())]"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="*[not(descendant::node())]">
    <xsl:variable name="ancestors" select="ancestor-or-self::*[position() lt last()]"/>
    <xsl:apply-templates select="$ancestors[1]" mode="tree">
      <xsl:with-param name="ancestors" select="$ancestors"/>
    </xsl:apply-templates>
  </xsl:template>
  
  <xsl:template match="*" mode="tree">
    <xsl:param name="ancestors"/>
    <xsl:if test="$ancestors intersect .">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="tree">
          <xsl:with-param name="ancestors" select="$ancestors"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old September 23rd, 2010, 10:41 AM
Authorized User
 
Join Date: Jan 2010
Posts: 12
Thanks: 2
Thanked 0 Times in 0 Posts
Default

Thank you very much. The code is running fine.

The problem looked quite simple to me - the solution quite complicated. Normaly XSLT is exactly the other way. Is this a problem I should better solve within the relational database?

Best regards

Christian
 
Old September 23rd, 2010, 11:41 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Three templates is a complicated solution? The first template creates the root element of the result tree and select the nodes you are interested in (i.e. those without child nodes) for further processing, then for each of the selected nodes the second template finds the elements forming a subtree you want to copy and the third template does the copying.

As for solving the problem "within the relational database", I don't know how the XML input relates to any relational data so I can't tell anything about that.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog





Similar Threads
Thread Thread Starter Forum Replies Last Post
How to copy elements to new file geek.shrek XSLT 6 January 10th, 2010 08:35 AM
copy-of select= not returning all elements jay_c XSLT 8 August 8th, 2009 01:38 PM
path for nested elements rjonk XSLT 7 November 20th, 2006 05:43 AM
changing root path in file manager codergirl BOOK: ASP.NET Website Programming Problem-Design-Solution 3 November 11th, 2004 04:21 PM
Fixing virtual directory root path issue seanmayhew BOOK: ASP.NET Website Programming Problem-Design-Solution 1 November 10th, 2004 10:45 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.