By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,009 Members | 2,866 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,009 IT Pros & Developers. It's quick & easy.

Combining XML elements with XSL

P: n/a
I am having trouble combining similar elements. Elements can be
combined if they have the same name and the same attribute values. I
can handle single level elements but am having problems with
multi-level elments (level of element nesting is unbound). I cannot
rely on fixed element names in the translator code since the translator
will be general purpose, elements names are not fixed.

Example input

<test>
<A x="0">
<B>1</B>
</A>
<A x="0">
<C>2</C>
</A>
<A x="0">
<D x="0">
<E>3</E>
</D>
</A>
<A x="0">
<D x="0">
<E>3</E>
</D>
</A>
<A x="0">
<D x="1">
<E>5</E>
</D>
</A>
<A x="1">
<B>4</B>
</A>
</test>

example output:

<test>
<A x="0">
<B>1</B>
<C>2</C>
<D x="0">
<E>3</E>
</D>
<D x="1">
<E>5</E>
</D>
</A>
<A x="1">
<B>4</B>
</A>
</test>

Any help would be greatly appreciated - still an XSL newbie

Jul 20 '05 #1
Share this Question
Share on Google+
8 Replies


P: n/a
On 15 Feb 2005 13:50:10 -0800, mikea_59 <mi******@yahoo.com> wrote:
I am having trouble combining similar elements. Elements can be
combined if they have the same name and the same attribute values. I
can handle single level elements but am having problems with
multi-level elments (level of element nesting is unbound). I cannot
rely on fixed element names in the translator code since the translator
will be general purpose, elements names are not fixed.

Hi,

I'm afraid you'll have to use an 'xx:node-set' extension function to solve
this (in XSLT1.0).

Here's one solution (tested with Saxon), gives correct output for your
input.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">

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

<xsl:strip-space elements="*"/>
<xsl:key name="element" match="*" use="concat(local-name(),@*)"/>

<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:variable name="set">
<xsl:copy-of select="key('element',concat(local-name(),@*))/*"/>
</xsl:variable>
<xsl:apply-templates select="text()"/>
<xsl:apply-templates
select="exsl:node-set($set)/*[generate-id()=generate-id(key('element',concat(local-name(),@*)))]"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

regards,
Joris Gillis
--
Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 20 '05 #2

P: n/a

That worked - thanks a lot! What a great NG.

So, is this strictly a 1.0 solution? Doesn't 2.0 eliminate the need
to use node-set() by enabling temporary templates? Is node-set() even
available in 2.0 - in Saxon? How would I change this for 2.0?

Sorry for all the ???

Thanks again
mikea

Jul 20 '05 #3

P: n/a
On 17 Feb 2005 11:56:09 -0800, mikea_59 <mi******@yahoo.com> wrote:
So, is this strictly a 1.0 solution? Everything that can be achieved in XSLT1.0 certainly can in XSLT2.0, isn't
that logic;)
Doesn't 2.0 eliminate the need
to use node-set() by enabling temporary templates? Excerpt form the latest XSLT2.0 working draft:
"The result tree fragment data-type is eliminated. A variable-binding
element with content (and no as attribute) now constructs a temporary
tree, and the value of the variable is the root node of this tree (see 9.3
Values of Variables and Parameters). With an as attribute, a
variable-binding element may be used to construct an arbitrary sequence.
These features eliminate the need for the xx:node-set extension function
provided by many XSLT 1.0 implementations."
available in 2.0 - in Saxon? How would I change this for 2.0?


I don't have experience with 2.0, but I guess writing '$set' in stead of
'exsl:node-set($set)' will do...
regards,
Joris Gillis
--
Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 20 '05 #4

P: n/a

Joris Gillis wrote:
On 17 Feb 2005 11:56:09 -0800, mikea_59 <mi******@yahoo.com> wrote:
So, is this strictly a 1.0 solution? Everything that can be achieved in XSLT1.0 certainly can in XSLT2.0,

isn't that logic;)
Yes, very logical, but when I set stylesheet to version=2.0 and
re-run the translation in Saxon, I get an error:

"A sequence of more than one item is not allowed as the first
argument of generate-id()"

I guess it's not related to node-set()
Doesn't 2.0 eliminate the need
to use node-set() by enabling temporary templates? Excerpt form the latest XSLT2.0 working draft:
"The result tree fragment data-type is eliminated. A variable-binding

element with content (and no as attribute) now constructs a temporary tree, and the value of the variable is the root node of this tree (see 9.3 Values of Variables and Parameters). With an as attribute, a
variable-binding element may be used to construct an arbitrary sequence. These features eliminate the need for the xx:node-set extension function provided by many XSLT 1.0 implementations."
available in 2.0 - in Saxon? How would I change this for 2.0?
I don't have experience with 2.0, but I guess writing '$set' in stead

of 'exsl:node-set($set)' will do...
regards,
Joris Gillis
--
Using Opera's revolutionary e-mail client: http://www.opera.com/m2/


Jul 20 '05 #5

P: n/a
On 17 Feb 2005 13:21:49 -0800, mikea_59 <mi******@yahoo.com> wrote:
"A sequence of more than one item is not allowed as the first
argument of generate-id()"


Really? Then they have changed the behaviour of generate-id().

Solution:
change
<xsl:apply-templates
select="exsl:node-set($set)/*[generate-id()=generate-id(key('element',concat(local-name(),@*)))]"/>
into
<xsl:apply-templates
select="exsl:node-set($set)/*[generate-id()=generate-id(key('element',concat(local-name(),@*))[1])]"/>

--
Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 20 '05 #6

P: n/a
Really? Then they have changed the behaviour of generate-id().


it's a more or less pervasive change, as part of the stricter tying
introduced in 2 most instances of functions that expect a single node
complain if given more than one node rather than silently taking the
first in doc order.

David
Jul 20 '05 #7

P: n/a

It looks like that did the trick, thanks a lot. I'm still not sure I
follow the syntax of the select attribute, I guess I'll go back to my
Kay book...

Thanks again,
mikea

Jul 20 '05 #8

P: n/a
Tempore 23:15:45, die Thursday 17 February 2005 AD, hinc in foro {comp.text.xml} scripsit mikea_59 <mi******@yahoo.com>:

It looks like that did the trick, thanks a lot. I'm still not sure I
follow the syntax of the select attribute


you mean this line?

<xsl:apply-templates select="$set/*[generate-id()=generate-id(key('element',concat(local-
name(),@*))[1])]"/>

well, the trick is to let the xslt processor create a key lookup table based on the node-set in the variable in stead of a lookup table indexing all nodes in the input XML document.

The 'generate-id()' + 'key()' stuff is just basic Muenchian grouping technique...

--
Joris Gillis (http://www.ticalc.org/cgi-bin/acct-v...i?userid=38041)
"Φιλήκοον ειναι μαλλον η Ï*ιλόλαλον" - Κλεόβουλος
Jul 20 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.