简体   繁体   中英

Sorting XML based on several sub-elements using XSLT

I'm trying to sort some XML (using XSLT) based on a few child elements and return the result as XML. I know it's probably not that difficult but this is my first experience using XSLT and it's giving me some troubles. Here's the XML:

<root>
  <subject>
    <courseSubjectHeader>
        <subjectCode>B</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>B 200</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>B 100</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
  <subject>
    <courseSubjectHeader>
        <subjectCode>C</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>C 300</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>C 100</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
  <subject>
    <courseSubjectHeader>
        <subjectCode>A</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>A 300</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>A 200</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
</root>

I'd like to sort the 'subjects' by their 'subjectCode' child element, and all the courses within each subject by their 'subjectAndNumber' child element. So the resulting XML would be...

<root>
  <subject>
    <courseSubjectHeader>
        <subjectCode>A</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>A 200</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>A 300</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
  <subject>
    <courseSubjectHeader>
        <subjectCode>B</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>B 100</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>B 200</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
  <subject>
    <courseSubjectHeader>
        <subjectCode>C</subjectCode>
        <subjectName>text</subjectName>
        <unit>text</unit>
        <faculty>text</faculty>
    </courseSubjectHeader>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>C 100</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
    <course>
      <crsLevel>text</crsLevel>
      <subjectAndNumber>C 300</subjectAndNumber>
      <units>3.0</units>
      <hours>3-0</hours>
    </course>
  </subject>
</root>

And finally, here's my (pretty awful) attempt at the XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/ /Transform">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/">
        <xsl:copy>
            <xsl:apply-templates select="subject">
                <xsl:sort select="subjectCode"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="subject">
        <xsl:copy>
            <xsl:apply-templates select="course">
                <xsl:sort select="subjectAndNumber"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Any help would be much appreciated, thanks!

You only have a few minor mistakes - compare:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/*">
    <xsl:copy>
        <xsl:apply-templates select="subject">
            <xsl:sort select="courseSubjectHeader/subjectCode"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<xsl:template match="subject">
    <xsl:copy>
        <xsl:copy-of select="courseSubjectHeader"/>
        <xsl:apply-templates select="course">
            <xsl:sort select="subjectAndNumber"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Note : your most serious mistake is this: xmlns:xsl="http://www.w3.org/1999/ /Transform" . If you don't declare the XSLT namespace properly, then your document is not a stylesheet at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM