472,334 Members | 2,222 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,334 software developers and data experts.

XSLT sort based on attributes

given the following DOM snippet;

<root>
<sub1 foo="4">testing</sub1>
<sub1 foo="0">hello</sub1>
<sub1 foo="0">world</sub1>
<sub1>hello again</sub1>
</root>

I need to transform with XSL to something like;

start foo = 0
hello
world
end foo = 0

start foo = 4
testing
end foo = 4

hello again
The (hopefully clear) constraints are that the attribute foo is
optional and that it may be any whole number if present, though may or
may not be sequential.

Sorting the nodeset based on the value of foo I can manage (!), but I
can't figure out how to output the boundary markers shown. Can anyone
help??

Many TIA!
Jul 20 '05 #1
8 3310
Darren Davison wrote:
given the following DOM snippet;

<root>
<sub1 foo="4">testing</sub1>
<sub1 foo="0">hello</sub1>
<sub1 foo="0">world</sub1>
<sub1>hello again</sub1>
</root>

I need to transform with XSL to something like;

start foo = 0
hello
world
end foo = 0

start foo = 4
testing
end foo = 4

hello again
The (hopefully clear) constraints are that the attribute foo is
optional and that it may be any whole number if present, though may or
may not be sequential.

Sorting the nodeset based on the value of foo I can manage (!), but I
can't figure out how to output the boundary markers shown. Can anyone
help??
I think so. Try this:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"

<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="root/sub1[@foo]">
<xsl:sort select="@foo" order="ascending"/>
</xsl:apply-templates>
<xsl:apply-templates select="root/sub1[not(@foo)]">
<xsl:sort select="@foo" order="ascending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="sub1">
<xsl:if test="not(@foo=preceding::node()/@foo)">
<xsl:text>
</xsl:text>
<xsl:if test="@foo">
<xsl:text>start foo = </xsl:text>
<xsl:value-of select="@foo"/>
</xsl:if>
</xsl:if>
<xsl:text>
</xsl:text>
<xsl:value-of select="."/>
<xsl:if test="not(@foo=following::node()/@foo)">
<xsl:text>
</xsl:text>
<xsl:if test="@foo">
<xsl:text>end foo = </xsl:text>
<xsl:value-of select="@foo"/>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

When I run that on the data you've posted, I get this output:
start foo = 0
hello
world
end foo = 0

start foo = 4
testing
end foo = 4
hello again

That's pretty close to what you wanted, if I understood you correctly.
If not, you can probably see how to modify it. If you don't actually
need the non-foo nodes at the end (and could accept them at beginning of
the output) then you can just elimate the second apply-templates in the
root template and change the select clause of the first one to be just
root/sub1.

Ed

Jul 20 '05 #2

This is a standard grouping guestion, see
http://www.jenitennison.com/xslt/grouping

something like

<xsl:key name="x" match="sub1" use="foo"/>

<xsl:template match="root">
<xsl:for-each select="sub1[generate-id()=generate-id(key('x',@foo))]">
<xsl:sort select="@foo" data-type="number"/>
<xsl:if test="@foo">start foo = <xsl:value-of select="@foo"/></xsl:if>
<xsl:for-each select="key('x',@foo)">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
<xsl:if test="@foo">end foo = <xsl:value-of select="@foo"/></xsl:if>
</xsl:for-each>
</xsl:template>

David
Jul 20 '05 #3
David Carlisle wrote:
This is a standard grouping guestion, see
http://www.jenitennison.com/xslt/grouping
looks like a pretty useful site - bookmarked!
something like

<xsl:key name="x" match="sub1" use="foo"/>

<xsl:template match="root">
<xsl:for-each select="sub1[generate-id()=generate-id(key('x',@foo))]">
<xsl:sort select="@foo" data-type="number"/>
<xsl:if test="@foo">start foo = <xsl:value-of select="@foo"/></xsl:if>
<xsl:for-each select="key('x',@foo)">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
<xsl:if test="@foo">end foo = <xsl:value-of select="@foo"/></xsl:if>
</xsl:for-each>
</xsl:template>


Thanks very much for your help David

:)
--
darren@ public key
davisononline.org #DD356B0D

Jul 20 '05 #4
Ed Beroset wrote:
I think so. Try this:
- snip -
That's pretty close to what you wanted, if I understood you correctly.
If not, you can probably see how to modify it. If you don't actually
need the non-foo nodes at the end (and could accept them at beginning of
the output) then you can just elimate the second apply-templates in the
root template and change the select clause of the first one to be just
root/sub1.


Many thanks for your help Ed.

--
darren@****************public*key
davisononline.org******#DD356B0D
Jul 20 '05 #5
Darren Davison schrieb:
David Carlisle wrote:

This is a standard grouping guestion, see
http://www.jenitennison.com/xslt/grouping

...


I was thinking about the Problem with the optional @foo which is not
handled in Davids solution.

I tried to solve this but ended up in a bit messy code :-(

Are there more elegant solutions?

Jo

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:key name="fooKey" match="sub1" use="@foo" />
<xsl:output omit-xml-declaration="yes" method="text" />
<xsl:preserve-space elements="/" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>

<xsl:template match="root">
<xsl:for-each select="sub1[generate-id() =
generate-id(key('fooKey',@foo)[1])] | sub1[not(@foo)]">
<xsl:variable name="fooParm" select="@foo" />
start foo=<xsl:value-of select="$fooParm" /><xsl:text> </xsl:text>
<xsl:for-each select="../sub1[@foo = $fooParm or (not(@foo) and
not($fooParm))]">
<xsl:value-of select="." /><xsl:text> </xsl:text>
</xsl:for-each>
end foo=<xsl:value-of select="$fooParm" /><xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>

<xsl:template match="sub1[@foo]">
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>

Jul 20 '05 #6

I was thinking about the Problem with the optional @foo which is not
handled in Davids solution.

my code handles an omitted foo the same as foo="" Given that foo had
numeric values I assumed that "" would not be a legal value and so
no distinction between these cases was necessary.

David
Jul 20 '05 #7

I wrote
I was thinking about the Problem with the optional @foo which is not
handled in Davids solution.

my code handles an omitted foo the same as foo="" Given that foo had
numeric values I assumed that "" would not be a legal value and so
no distinction between these cases was necessary.


although in fairness I should say there were some typos so actually my
code wouldn't run at all, also the original poster wanted "" to sort
high whereas by default it sorts low. The code below fixes the typos and
negates the sort key so "" (NaN) sorts high.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:key name="x" match="sub1" use="string(@foo)"/>

<xsl:template match="root">
<xsl:for-each select="sub1[generate-id()=generate-id(key('x',string(@foo)))]">
<xsl:sort select="-@foo" data-type="number" order="descending"/>
<xsl:if test="@foo"> start foo = <xsl:value-of select="@foo"/></xsl:if>
<xsl:for-each select="key('x',string(@foo))">
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
<xsl:if test="@foo"> end foo = <xsl:value-of select="@foo"/></xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>
$ saxon8 sort.xml sort.xsl
Warning: Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
<?xml version="1.0" encoding="UTF-8"?>
start foo = 0
hello

world

end foo = 0
start foo = 4
testing

end foo = 4
hello again
Jul 20 '05 #8
David Carlisle schrieb:
I wrote

I was thinking about the Problem with the optional @foo which is not
handled in Davids solution.

my code handles an omitted foo the same as foo="" Given that foo had
numeric values I assumed that "" would not be a legal value and so
no distinction between these cases was necessary.

...


You 're right!

I created a problem, where no problem exists.

Jo

Jul 20 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Igor | last post by:
Is there any way to resort and xml document using xslt based on element position. For example if I have xml like this: <root> <element> 1st thing...
9
by: Iain | last post by:
I want to create an XML configuration file which might look like <REGION Name="Europe" WingDing="Blue"> <COUNTRY Name="UK" WingDing="white">...
1
by: David | last post by:
I would like to be able to re-sort data in an HTML table on the without returning to the server. It seems like an XSLT should be able to...
2
by: Jon Martin Solaas | last post by:
Hi, I have a general document somewhat like this: -------------------------------------- <root> <level1> <level2> <interestingstuff...
3
by: Alex | last post by:
I stumbled upon this while developing a custom XPathNavigator. It appears that copy action for attributes is broken in the .net framework XSLT...
3
by: Teksure | last post by:
Hi group, searching in the Internet I found two products for XML which incorporate a very robust debugger for XSL/XSLT, I would like you to see...
7
by: Harolds | last post by:
The code below worked in VS 2003 & dotnet framework 1.1 but now in VS 2005 the pmID is evaluated to "" instead of what the value is set to: .......
4
by: David S. Alexander | last post by:
How can I do simple subtraction in an XSLT. I want to read a few attribute values from an XML document, calculate their difference, and transform...
3
by: thomas.porschberg | last post by:
Hi, I want to read records from a database and export it in an arbitrary format. My idea was to feed a class with a String array fetched from...
0
by: concettolabs | last post by:
In today's business world, businesses are increasingly turning to PowerApps to develop custom business applications. PowerApps is a powerful tool...
0
better678
by: better678 | last post by:
Question: Discuss your understanding of the Java platform. Is the statement "Java is interpreted" correct? Answer: Java is an object-oriented...
0
by: teenabhardwaj | last post by:
How would one discover a valid source for learning news, comfort, and help for engineering designs? Covering through piles of books takes a lot of...
0
by: Kemmylinns12 | last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and...
0
by: CD Tom | last post by:
This only shows up in access runtime. When a user select a report from my report menu when they close the report they get a menu I've called Add-ins...
0
jalbright99669
by: jalbright99669 | last post by:
Am having a bit of a time with URL Rewrite. I need to incorporate http to https redirect with a reverse proxy. I have the URL Rewrite rules made...
0
by: antdb | last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was...
0
by: Matthew3360 | last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function. Here is my code. ...
0
hi
by: WisdomUfot | last post by:
It's an interesting question you've got about how Gmail hides the HTTP referrer when a link in an email is clicked. While I don't have the specific...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.