0

I'm getting a hang of XML and am now experimenting with XSLT. I'd like to transform an XML file into a new XML file with a different format. I've been messing around with this for two days, but as you can see with the code I have posted below, I am not getting the desired results. If anything I'm continuing to make it worse.

You might be able to figure out what I want to change just by looking at the code I posted, but if not, here are the main changes I want to make: I want the root element to be classes and consist of class elements and a "count" attribute that counts the number of classes that have "Classroom" as a delivery. Course's "number" attribute should instead be a child element of class. Instead of having room being a child element of section, I'd like it to be an attribute of class, along with credits. If possible, I'd like to sort the class elements based on enrollment size (smallest to biggest). I'd also like to avoid using <xsl:for-each> as I've heard it is bad to use.

Original XML file:

<?xml version="1.0" encoding="UTF-8"?>
<courses>
  <course number="341" credits="4.0">
    <title>Physics</title>
    <section number="01" delivery="Classroom">
      <enrollment>15</enrollment>
      <room>EA244</room>
      <instructor>
        <first>Herman</first>
        <last>Johnson</last>
      </instructor>
    </section>
    <section number="02" delivery="Online">
      <enrollment>10</enrollment>
      <instructor>
        <first>Herman</first>
        <last>Johnson</last>
      </instructor>
      <instructor>
        <first>Mike</first>
        <last>Miller</last>
      </instructor>
    </section>
    <section number="03" delivery="Classroom">
      <enrollment>12</enrollment>
      <room>SH102</room>
      <instructor>
        <first>Allison</first>
        <last>Sweeney</last>
      </instructor>
    </section>
  </course>
  <course number="368" credits="4.0">
      <title>Psychology</title>
    <section number="01" delivery="Classroom">
      <enrollment>9</enrollment>
      <room>AT102</room>
      <instructor>
        <first>Mike</first>
        <last>Miller</last>
      </instructor>
      <instructor>
        <first>Alex</first>
        <last>Holmquist</last>
      </instructor>
    </section>
  </course>
  <course number="375" credits="4.0">
      <title>Biology</title>
    <section number="01" delivery="ITV">
      <enrollment>18</enrollment>
            <room>EA244</room>
      <instructor>
        <first>Mike</first>
        <last>Miller</last>
      </instructor>
    </section>
  </course>
  <course number="385" credits="3.0">
      <title>Calculus</title>
    <section number="01" delivery="Classroom">
      <enrollment>26</enrollment>
            <room>ST108</room>
      <instructor>
        <first>Herman</first>
        <last>Johnson</last>
      </instructor>
    </section>
  </course>
  <course number="413" credits="3.0">
      <title>Chemistry</title>
    <section number="01" delivery="Online">
      <enrollment>10</enrollment>
      <instructor>
        <first>Mike</first>
        <last>Miller</last>
      </instructor>
    </section>
  </course>
</courses>

Desired XML output:

<?xml version="1.0" encoding="UTF-8"?>
<classes count="4">
  <class credits="4.0" room="AT102">
    <number>368</number>
    <title>Psychology</title>
    <enrollment>9</enrollment>
    <instructor>
      <first>Mike</first>
      <last>Miller</last>
    </instructor>
    <instructor>
      <first>Alex</first>
      <last>Holmquist</last>
    </instructor>
  </class>
  <class credits="4.0" room="SH102">
    <number>341</number>
    <title>Physics</title>
    <enrollment>12</enrollment>
    <instructor>
      <first>Allison </first>
      <last>Sweeney</last>
    </instructor>
  </class>
  <class credits="4.0" room="EA244">
    <number>341</number>
    <title>Physics</title>
    <enrollment>15</enrollment>
    <instructor>
      <first>Herman</first>
      <last>Johnson</last>
    </instructor>
  </class>
  <class credits="3.0" room="ST108">
    <number>385</number>
    <title>Calculus</title>
    <enrollment>26</enrollment>
    <instructor>
      <first>Herman</first>
      <last>Johnson</last>
    </instructor>
  </class>
</classes>

Current XML output (Undesired)

<?xml version="1.0" encoding="UTF-8"?>
<classes count="">
   <class credits="4.0" room="EA244">
      <number>341</number>
      <title>Physics</title>
      <enrollment>15</enrollment>
      <instructor>Herman
        Johnson

        Herman
        Johnson

        Mike
        Miller

        Allison
        Sweeney

        Mike
        Miller

        Alex
        Holmquist

        Mike
        Miller

        Herman
        Johnson

        Mike
        Miller</instructor>
   </class>
</classes>

XSLT file:

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

<!-- Define output method to XML -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

  <xsl:template match="/">

  <classes>
  <xsl:attribute name="count"> <!--
      <xsl:apply-templates select="/courses/course/section" /> -->
</xsl:attribute>

<class>
  <xsl:attribute name="credits">
      <xsl:value-of select="/courses/course/@credits" />
  </xsl:attribute>
   <xsl:attribute name="room">
       <xsl:value-of select="/courses/course/section/room" />
  </xsl:attribute>
   <number>
       <xsl:value-of select="/courses/course/@number" />
  </number>
   <title>
       <xsl:value-of select="/courses/course/title" />
   </title>
   <enrollment>
       <xsl:value-of select="/courses/course/section/enrollment" />
    </enrollment>
   <instructor>
     <xsl:apply-templates select=" courses/course/section/instructor" />
   </instructor>
</class>
</classes>

<!--template for instructor names -->

<xsl:template match="instructor">
 <xsl:copy/>
</xsl:template>
  <xsl:template match="courses/course/title">
  <xsl:value-of select="title" />
  </xsl:template>
  </xsl:template>
<!--template to count number of classes use "Classroom" delivery -->
<xsl:template match="section">
 <xsl:variable name="classroomCount" select="/{@delivery='Classroom']" />
  <xsl:value-of select="count($classroomCount)" />
  </xsl:template>

  </xsl:stylesheet>
4
  • 1
    "You might be able to figure out what I want to change just by looking at the code I posted" Actually, I can't figure it out even after reading your explanation. What is a class, and how is it different from a room? Commented Aug 2, 2014 at 22:40
  • Class (like a class you take in school) is an element in my classes document. Room is the room the class is held in. Commented Aug 2, 2014 at 23:06
  • Sorry for not being more clear. Commented Aug 2, 2014 at 23:11
  • 1
    The thing is, there is no "class" in your input. The missing part, I think, is that a "section" (of certain type) needs to become a "class". Anyway, it was either this or a sudoku, so don't let it worry you too much :-). Commented Aug 2, 2014 at 23:15

1 Answer 1

2

I think this may do what you described. At least the result received is the same as the desired one, AFAICT:

XSLT 1.0

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

<xsl:template match="/courses">
    <classes count="{count(course/section[@delivery='Classroom'])}">
        <xsl:apply-templates select="course/section[@delivery='Classroom']">
            <xsl:sort select="enrollment" data-type="number" order="ascending"/>
        </xsl:apply-templates>
    </classes>
</xsl:template>

<xsl:template match="section">
    <class credits="{../@credits}" room="{room}">
        <number><xsl:value-of select="../@number"/></number>
        <xsl:copy-of select="../title | enrollment | instructor"/>
    </class>
</xsl:template>

</xsl:stylesheet>

I'd also like to avoid using <xsl:for-each> as I've heard it is bad to use.

Don't believe all you hear. As it happens, it's not convenient to use it here, but I would not hesitate to use it otherwise.

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

1 Comment

Looks like it's doing the trick. Thank you! I'll study this code to see what I can learn from it. And I'll keep that in mind about using for-each.

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.