I have a large xml file with a lot of row nodes. I want to sort it by each row's id value.
So this would be an example input:
<database>
<table>
<row>
<id>10</id>
<foo>bar</foo>
</row>
<row>
<id>5</id>
<foo>poit</foo>
</row>
<row>
<id>1</id>
<foo>narf</foo>
</row>
</table>
</database>
and this the expected output:
<database>
<table>
<row>
<id>1</id>
<foo>narf</foo>
</row>
<row>
<id>5</id>
<foo>poit</foo>
</row>
<row>
<id>10</id>
<foo>bar</foo>
</row>
</table>
</database>
How can I achieve that? I have xmlstarlet
at my disposal. It features a transform and appearantly I can provide a xslt stylecheet in a xsl file.
I haven't worked with xslt before and am unsure how to proceed.
I have found some related sorting questions providing some XSLT examples, yet I could not get them working in my use case.
My current sort.xslt
(Note: I don't know what I am doing) looks like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:sort select="row()"/>
</xsl:apply-templates>
<xsl:apply-templates select="node()">
<xsl:sort select="id()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Yet it fails:
$ xmlstarlet tr sort.xsl example.xml
Invalid number of arguments
xmlXPathCompiledEval: evaluation failed
Invalid number of arguments
xmlXPathCompiledEval: evaluation failed
Invalid number of arguments
xmlXPathCompiledEval: evaluation failed
<database>
<table/>
</database>
I don't know anything about xmlstarlet, but I can say that your XSLT should really look like this...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="table">
<xsl:copy>
<xsl:apply-templates select="row">
<xsl:sort select="id" data-type="number" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note how you do not need ()
after element names in your XSLT.
See it in action at http://xsltransform.net/pNmBy1b
(I also note the tag xmlstarlet
only has 20 followers. You might want to try out some other tools instead. See https://stackoverflow.com/tags/xslt/info for some help. xsltproc, perhaps?)