Mayank
Mayank

Reputation: 1631

How to sort this XML?

This is the XML that I am trying to sort:

<?xml version="1.0" encoding="utf-8"?>
<Proposal>
  <MobileKey>test string</MobileKey>
  <RevisionNumber>9</RevisionNumber>
  <CreationDate>2014-04-30T13:21:00</CreationDate>
  <ProposalDueDate>test string</ProposalDueDate>
  <ProposalJobs>
    <ProposalID>56</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
  <ProposalJobs>
    <ProposalID>42</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
  <ProposalJobs>
    <ProposalID>21</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
</Proposal>

The output should be (sorted on ProposalID):

<?xml version="1.0" encoding="utf-8"?>
<Proposal>
  <MobileKey>test string</MobileKey>
  <RevisionNumber>9</RevisionNumber>
  <CreationDate>2014-04-30T13:21:00</CreationDate>
  <ProposalDueDate>test string</ProposalDueDate>
  <ProposalJobs>
    <ProposalID>21</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
  <ProposalJobs>
    <ProposalID>42</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
  <ProposalJobs>
    <ProposalID>56</ProposalID>
    <ProposalRevision>9</ProposalRevision>
    <ProposalJobNumber>9</ProposalJobNumber>
    <ServiceLine>test string</ServiceLine>
    <SubServiceLine>test string</SubServiceLine>
  </ProposalJobs>
</Proposal>

I have used the following XSLT. It does the sorting correctly but deletes all the child elements of Proposal except the ProposalJobs nodes. Please help me out here:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="Proposal">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="ProposalJobs">
        <xsl:sort select="ProposalID"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Views: 65

Answers (3)

michael.hor257k
michael.hor257k

Reputation: 117175

Change this:

<xsl:apply-templates select="ProposalJobs">
    <xsl:sort select="ProposalID"/>
</xsl:apply-templates>

to:

<xsl:apply-templates select="*">
    <xsl:sort select="ProposalID"/>
</xsl:apply-templates>

Alternatively, add this:

<xsl:apply-templates select="*[not(self::ProposalJobs)]"/>

just before:

<xsl:apply-templates select="ProposalJobs">
    <xsl:sort select="ProposalID"/>
</xsl:apply-templates>

Not related to your question, but you should change this:

<xsl:sort select="ProposalID"/>

to:

<xsl:sort select="ProposalID" data-type="number"/>

Otherwise ProposalID #101 will come before #21.


Edit:

To preserve the order of internal "blocks", use:

<xsl:template match="Proposal">   
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(preceding-sibling::ProposalJobs)]"/>
        <xsl:apply-templates select="ProposalJobs">
            <xsl:sort select="ProposalID" data-type="number"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="node()[preceding-sibling::ProposalJobs]"/>
    </xsl:copy>  
</xsl:template>

Upvotes: 3

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56222

Use:

<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="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Proposal">   
    <xsl:copy>
      <xsl:apply-templates select="node()[not(self::ProposalJobs)]|@*"/>
      <xsl:apply-templates select="ProposalJobs">
        <xsl:sort select="ProposalID"/>
      </xsl:apply-templates>
    </xsl:copy>   

  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Ken de Guzman
Ken de Guzman

Reputation: 2820

You can do this. I've tested and works fine.

<xsl:template match="Proposal">
    <xsl:copy>
     <xsl:apply-templates select="@*|node()[not(self::ProposalJobs)]" />
      <xsl:apply-templates select="ProposalJobs">
        <xsl:sort select="ProposalID"/>
      </xsl:apply-templates>

    </xsl:copy>
 </xsl:template>

Upvotes: 1

Related Questions