473,473 Members | 1,960 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

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 3362
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 </element> <element> 2nd thing </element>...
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"> <TOWN Name="London" WingDing="Orange" /> </COUNTRY>...
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 accomplish this, but I can't find enough information... ...
2
by: Jon Martin Solaas | last post by:
Hi, I have a general document somewhat like this: -------------------------------------- <root> <level1> <level2> <interestingstuff number="2"/> <interestingstuff number="3"/>...
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 processor. The intent was to just copy the entities...
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 these products and then, give me your opinion about...
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: .... xmlItems.Document = pmXML // Add the pmID...
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 that value to an attribute in the XML output...
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 the database and let this class fire SAX events as...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

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.