1

Can any one please suggest how to sort an XML by attribute names using XSLT?

For example: my XML is as below

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <!-- test 1 -->
    <test g="r">
        <a g="c" d="e">one</a>
        <!-- a k z d b -->
        <a k="z" d="b">two</a>
        <a s="h" d="5">three</a>
        <!-- a a b d 4 -->
        <a a="b" d="4">four</a>
        <a b="q" d="3">five</a>
        <a s="a" d="8">3three</a>
        <a x="i" d="2">six</a>
        <!-- six 2 a f h i 2 -->
        <a f="h" i="2">six</a>
        <a l="t" d="1">seven</a>
    </test>
    <!-- test 2 -->
    <test t="b">
        <!-- six 2 a z i d 2 -->
        <a z="i" d="2">six</a>
        <a r="z" d="b">two</a>
        <a a="c" d="e">one</a>
        <a u="h" d="5">three</a>
        <!-- four -->
        <a c="b" d="4">four</a>
        <a h="q" d="3">five</a>
        <a p="t" d="1">seven</a>
    </test>
</root>

expected output should be:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <!-- test 1 -->
    <test g="r">
        <!-- a a b d 4 -->
        <a a="b" d="4">four</a>
        <a b="q" d="3">five</a>
        <a g="c" d="e">one</a>
        <!-- six 2 a f h i 2 -->
        <a f="h" i="2">six</a>      
        <!-- a k z d b -->
        <a k="z" d="b">two</a>
        <a l="t" d="1">seven</a>
        <a s="a" d="8">3three</a>
        <a s="h" d="5">three</a>
        <a x="i" d="2">six</a>
    </test>
    <!-- test 2 -->
    <test t="b">
        <a a="c" d="e">one</a>
        <!-- four -->
        <a c="b" d="4">four</a>
        <a h="q" d="3">five</a>
        <a p="t" d="1">seven</a>
        <a r="z" d="b">two</a>
        <a u="h" d="5">three</a>
        <!-- six 2 a z i d 2 -->
        <a z="i" d="2">six</a>
    </test>
</root>
1
  • I could give you an answer but it might be not enough for your task... Do you want to sort for the first (alphabetical order) attribute not named d? Commented Mar 19, 2011 at 2:24

4 Answers 4

2

I suspect you might be wanting it to sort on the name of the first attribute. That can't be done, because the order of attributes has no significance in XML, and you can't predict which attribute @*[1] will select.

Sign up to request clarification or add additional context in comments.

Comments

0
  <xsl:template match="test">
    <xsl:apply-templates>
      <xsl:sort select="@d"/>
    </xsl:apply-templates>
  </xsl:template>

will get you the elements under test sorted by attribute d.

You can do multiple sort-levels by adding another xsl:sort.

More about sorting here: http://www.w3.org/TR/xslt#sorting

6 Comments

Oh I did not see your expected output. So you want to sort by attribute name. I'm not sure it's possible, let's see...
sorry ptival.. im expected the answer in a generic XSLT sorting format.. If you can, please post the relavent generic XSLT .
So, how do you expect XSLT to be able to figure out on which of the attributes it should sort?
nice question.. But we should write the XSLT code in such as way XSLT will sort based on below order 1. root node 2. sub node 3. sub node - first attribute name 4. sub node - first attribute value and so on....
Relying on the order of the attributes seem quite fragile, and I don't think it is even possible anyway.
|
0

I found the solution myself.. Below is the line of code to be used for sorting by attribute names.

<xsl:sort select="local-name(@*)"/>

Guys, thanks for all your efforts.

4 Comments

Do note that this is wrong because the reasons given by Dr. Michael Kay. Because implicit casting this will be equal to local-name(@*[1]).
@Alejandro: <code>local-name(@*)</code> & <code>local-name(@*[1])</code> both represents first attribute of that node. This is what looking. In the case of Michael solution, he said "you can't predict which attribute @*[1] will select..." but when i'm using <code>local-name(@*)</code> & <code>local-name(@*[1])</code> then it is always selecting the first attribute of the node for sorting. So I mentioned that it is possible. <CONT..1/2>
In this case, it will sort based on only first attribute. This should be expanded in such a way that by passing position of attributes <pre>local-name(@*[position()])</pre> then it will sort based on all available attributes. If I said anything wrong, please correct me. Thanks @Alejandro for posting & updating me. <CONT.. 2/2>
I think you are not taking into account that there is no guarantee that @*[1] selects the first attibute in the source according XML/XPath specifications. You need to repharse this condition into something with more semantic meaning like: "sort by first attibute's name in alphabetical order except @d". That's posible in XSLT with a two phase transformation.
-1
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  <xsl:output indent="yes" />
  <xsl:strip-space elements="*"/> 
  <xsl:template match="*">
    <xsl:copy> 
      <xsl:apply-templates select="@*">        
        <xsl:sort select="name()"/> 
    </xsl:apply-templates>
      <xsl:apply-templates>
        <xsl:sort select="name()"/>
        <xsl:sort select= "name(@*)"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
 <xsl:template match="@*">
    <xsl:copy />     
  </xsl:template>
</xsl:stylesheet>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.