Sort xml and output xml

J

Jim Andersen

I have this xml-file. I want to sort it, and create a new xml-file. The
result should be identical to the input except that it's sorted.

<?xml version="1.0" encoding="UTF-8"?>
<levelone>
<child ID="1" sort="5"><name>Paul</name></child>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
<root>

I now want to apply an xslt file and have the following output:
<?xml version="1.0" encoding="UTF-8"?>
<levelone>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
<child ID="1" sort="5"><name>Paul</name></child>
<root>

I've been searching for hours, but all the examples I have seen creates an
HTML file.

tia
/jim
 
P

p.lepin

Jim said:
I have this xml-file. I want to sort it, and create a
new xml-file. The result should be identical to the
input except that it's sorted.

Since you failed to mention what you're using for
processing, I assume it's some XSLT 1.0-compliant
processor.
<?xml version="1.0" encoding="UTF-8"?>
<levelone>
<child ID="1" sort="5"><name>Paul</name></child>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
<root>

That's not an XML file. It's not well-formed.
I've been searching for hours, but all the examples I
have seen creates an HTML file.

That's mighty strange, especially since XML is the
default output method. All the XSLT tutorials I remember
covered sorting, identity transformation and controlling
your output.

Presuming you meant something like:

<levelone>
<child ID="1" sort="5"><name>Paul</name></child>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
</levelone>

The following XSLT should do the trick:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="*[@sort][not(preceding-sibling::*[@sort])]">
<xsl:apply-templates select="../*[@sort]" mode="copy">
<xsl:sort select="@sort"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template
match="*[@sort][preceding-sibling::*[@sort]]"/>
<xsl:template match="node()|@*" mode="copy">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
 
J

Jim Andersen

Since you failed to mention what you're using for
processing

I'm using a .NET 2.0 XMLDataSource. I point it to my xml-file and my
xslt-file.
, I assume it's some XSLT 1.0-compliant
processor.


That's not an XML file. It's not well-formed.

Yes. A typo in my posting. The last element "root" should have been
"levelone"

That's mighty strange, especially since XML is the
default output method.

And now I found out why. I had (from one of the examples I found) learned
that I could also put an instruction in the XML document that said to always
use a specific XSL-file. Something along the lines of : <xsl-stylesheet
output="htm/txt">
Removing that line made the output into XML.
Presuming you meant something like:

<levelone>
<child ID="1" sort="5"><name>Paul</name></child>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
</levelone>

I did.
The following XSLT should do the trick:

And it did. Thx a heap. Now I can start to find out why :)

/jim
 
J

Joe Kesselman

Jim said:
As you can see from mr p.lepins posting the solution is far from "trivial".

I'm not sure I agree; that solution strikes me as overcomplicated for
the question you asked.

"Produce a new levelone document, copying the child elements in sorted
order."

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template select="/levelone">
<levelone>
<xsl:for-each select="child">
<xsl:sort select="@sort"/>
<xsl:copy-of select=".">
</xsl:apply-templates>
</levelone>
</xsl:template>

</xsl:stylesheet>

Yes, things may become more complicated when additional constraints are
applied... but this ought to do the job you asked for.
 
P

p.lepin

As Joe Kesselman said, it does a bit more than you asked
for. Partly because I wasn't really sure what you were
asking for, your original post being just a bit sloppy,
and partly because I tend to introduce what I perceive as
useful techniques/good practices when I post solutions to
problems on the usenet. Still, it's trivial enough even
then.

The transformation I posted copies any XML document fed to
it, sorting any siblings with sort attribute by the value
of that attribute (it breaks just a bit if there are
sibling elements without sort attribute interspersed with
elements it's trying to sort).
I'm not sure I agree; that solution strikes me as
overcomplicated for the question you asked.

"Produce a new levelone document, copying the child
elements in sorted order."

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template select="/levelone">
<levelone>
<xsl:for-each select="child">
<xsl:sort select="@sort"/>
<xsl:copy-of select=".">
</xsl:apply-templates>
</levelone>
</xsl:template>
</xsl:stylesheet>

Being my usual obnoxious self, I cannot resist the
temptation to point out that, in my opinion:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/levelone">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort select="@sort"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="child">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

is only a bit more complicated, and better from the
standpoint of teaching the Arguably Right Thing.
 
J

Joseph Kesselman

[example]
is only a bit more complicated, and better from the
standpoint of teaching the Arguably Right Thing.

Depends on the user's intent. Yes, we want to encourage folks to learn
to take advantage of XSLT's pattern-matching and recursion capabilities.
But sometimes processing the nodes directly really does do everything
that's needed.

If the question had been posed differently, I might have solved it
differently. Your milage will vary.
 
J

Jim Andersen

Joseph said:
Depends on the user's intent.

My intent was to have my immediate problem solved.
AND to learn something about xslt.
AND to get a piece of code I can re-use in other scenarios, as I will
problably need to sort stuff again.

These things, I think, is something many of us posting and answering q's
want.
So p.lepin guessed right. Even if I was sloppy when asking the q.
But this was my first post in this subject, so I do net yet know what is
important, and what isn't.

/jim
 
J

Joe Kesselman

Jim said:
My intent was to have my immediate problem solved.
AND to learn something about xslt.
AND to get a piece of code I can re-use in other scenarios, as I will
problably need to sort stuff again.

Either solution addresses those. Mine focuses on the specifics of
sorting, and trusts that you will learn to think recursively through
other examples. The other attempts to show some other aspects of the
language as well... which may be useful, or may risk obscuring the key
point.

Personally, I still think the p.lepin's solution is overcomplicated; the
use of a separate mode with its own copy of the identity template is
something worth understanding in the long run but I consider it a
distraction here.

Both are reusable. Which one is more reusable -- or teaches you more
about reuse -- is debatable.

As I say, there's always a question of just how far to digress when
answering a question. One of the nice things about asking on a newsgroup
is that you may get multiple solutions, as here, in which case you can
pick the one that matches your own needs... or, if you don't yet know
your needs, you'll at least be exposed to the fact that multiple valid
answers exist.

Have fun.
 
J

Jim Andersen

Joe said:
Personally, I still think the p.lepin's solution is overcomplicated;

I have yet to fully comprehend it :)
Both are reusable. Which one is more reusable -- or teaches you more
about reuse -- is debatable.

I tend to go with the p.lepin solution. Your solution demands that I
hard-code the names of the nodes "levelone" and "child".
p.lepins only need the "sort"-attribute to be hardcoded.

After I understand p.lepins solution better, I hope to find out if it will
work with a more deeper nested XML lilke

<levelone>
<child ID="1"
sort="5"><names><name>Paul</name><name>Anka</name></names></child>
<child ID="2" sort="1"><name>Adam</name></child>
<child ID="3" sort="2"><name>Will</name></child>
One of the nice things about asking on a
newsgroup is that you may get multiple solutions, as here, in which
case you can pick the one that matches your own needs... or, if you
don't yet know your needs, you'll at least be exposed to the fact
that multiple valid answers exist.

Have fun.

Thanks. To both of you. For guiding me from wet feet, to knee-deep :)

/jim
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top