|
Subject: Re: [xsl] flatten a hierachy and change positions From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx> Date: Thu, 25 Sep 2003 10:18:18 +0100 |
Hi Andreas,
> I have to make some suppositions first, however...
>
> You have:
>>
> <root>
>> <g1>
>> <u1><s></s></u1>
> </g1> <!-- I presume... -->
>> <g2>
>> <u2></u2>
>> </g2>
> </root>
>
>>
> You need:
>>
>> <u1></u1>
>> <s></s>
>> <g1></g1>
>> <u2></u2>
>> <g2></g2>
> <root></root>
>
> Correct? Needs some kind of a recursive template, I think.
You *could* also do it by iterating through all the elements in the
document, after collecting them with the path "//*":
<xsl:for-each select="//*">
<xsl:copy />
</xsl:for-each>
This gives the output:
<root />
<g1 />
<u1 />
<s />
<g2 />
<u2 />
Now there's some reordering to do. I don't think that the order that
Elke originally asked for is derivable from the order of the elements
in the document, but the ordering that your recursive template gave
is: it's the order in which the end tags appear, which is the same as
the number of preceding elements + the number of descendant elements.
So you could order them with:
<xsl:for-each select="//*">
<xsl:sort select="count(preceding::* | descendant::*)"
data-type="number" />
<xsl:copy />
</xsl:for-each>
Having said that, sorting on a count of preceding and descendant
elements is going to be pretty inefficient if you have a document of
any size, so a recursive approach similar to yours is likely to be
better. I'd do it with the single template:
<xsl:template match="*">
<xsl:apply-templates select="*" />
<xsl:copy />
</xsl:template>
Which says that to process an element, you process its children first
and then create a copy of the element itself.
> Needs some adjustments, as I received error messages complaining
> about 'Illegal values being used for attribute name' (Xalan-J
> 2.5.1).
The error occurs when you call the 'another' template:
> <xsl:template name="another">
> <xsl:param name="parname" select="empty"/>
>
> <xsl:element name="{$parname}">
> <xsl:value-of select="$parname"/>
> </xsl:element>
> </xsl:template>
with an empty string as the value of the $parname parameter. If
$parname is an empty string then name="{$parname}" resolves to
name="", which means that you're not supplying a name for the element
that you want created. This is an error, but an XSLT processor can
recover from it by not creating the element.
The reason that $parname is an empty string is that in the 'one'
template, you're iterating over all the children of the $parnode
using:
> <xsl:for-each select="$parnode/node()">
> <xsl:call-template name="one">
> <xsl:with-param name="parnode" select="."/>
> </xsl:call-template>
> <xsl:call-template name="another">
> <xsl:with-param name="parname" select="name(.)"/>
> </xsl:call-template>
> </xsl:for-each>
Some of the children of $parnode are likely to be text nodes; text
nodes don't have names. If you only select the element children of the
$parnode instead, with $parnode/*, then you don't get the error.
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| RE: [xsl] flatten a hierachy and ch, Andreas L. Delmelle | Thread | [xsl] Re: xsl:key, andrew . curry |
| RE: [xsl] How to open a page in xsl, Michael Kay | Date | Antw: RE: [xsl] flatten a hierachy , Elke Naraschewski |
| Month |