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>
dogbane
  • 266,786
  • 75
  • 396
  • 414
Siva Charan
  • 17,940
  • 9
  • 60
  • 95
  • 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`? –  Mar 19 '11 at 02:24

4 Answers4

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.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
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

Ptival
  • 9,167
  • 36
  • 53
  • 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... – Ptival Mar 17 '11 at 12:12
  • sorry ptival.. im expected the answer in a generic XSLT sorting format.. If you can, please post the relavent generic XSLT . – Siva Charan Mar 17 '11 at 12:14
  • So, how do you expect XSLT to be able to figure out on which of the attributes it should sort? – Ptival Mar 17 '11 at 12:19
  • 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.... – Siva Charan Mar 17 '11 at 12:23
  • Relying on the order of the attributes seem quite fragile, and I don't think it is even possible anyway. – Ptival Mar 17 '11 at 12:27
  • Can any one provide me XPATH for sorting by attribute name? This should be as generic XPATH....
    For example: @* is for attribute values... similarly i need for attribute names
    – Siva Charan Mar 19 '11 at 07:26
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.

Siva Charan
  • 17,940
  • 9
  • 60
  • 95
  • Do note that this is wrong because the reasons given by [Dr. Michael Kay](http://stackoverflow.com/questions/5338628/sort-xml-by-attribute-names-using-xslt/5338948#5338948). Because implicit casting this will be equal to `local-name(@*[1])`. –  Mar 20 '11 at 22:21
  • @Alejandro: local-name(@*) & local-name(@*[1]) 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 local-name(@*) & local-name(@*[1]) then it is always selecting the first attribute of the node for sorting. So I mentioned that it is possible. – Siva Charan Mar 21 '11 at 09:12
  • 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
    local-name(@*[position()])
    then it will sort based on all available attributes. If I said anything wrong, please correct me. Thanks @Alejandro for posting & updating me.
    – Siva Charan Mar 21 '11 at 09:13
  • 1
    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. –  Mar 21 '11 at 16:21
-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>