views:

53

answers:

2

Hi,

Hopefully this will be a simple fix. I'm completely new to XSL but I've managed to get a little script that sorts my data by date. I now want to use ASP to limit this data to all entries within a month (this works by using a DateDiff() function). When I go to load in the XSL scripts output it says that my XML is malformed. Can anyone help me out here please?

Here's my XML File:

<?xml version="1.0"?>
<Rota>
   <Shift>
      <date>23/07/2010</date>
      <title1>GM Neurosciences</title1>
      <gm>Katie Cusick</gm>
      <title2>Chief Operating Officer</title2>
      <director>Patrick Mitchell</director>
      <nurse>n/a</nurse>
    </Shift>
    <Shift>
      <date>30/07/2010</date>
      <title1>GM Specialised Medicine</title1>
      <gm>Alison Watson</gm>
      <title2>DDO Medicine &amp; Cardio.</title2>
      <director>Suzanne Marsello</director>
      <nurse>n/a</nurse>
    </Shift>
</Rota>

Here's my XSL File:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" omit-xml-declaration="no" version="1.0" />
   <xsl:param name="sortBy" select="'date'"/>
   <xsl:param name="strXPath" select="//Shift"/>
   <xsl:template match="/"> 
      <xsl:apply-templates select="$strXPath">
               <xsl:sort select="substring(date,7,4)"/> <!-- year sort -->
               <xsl:sort select="substring(date,4,2)"/> <!-- month sort -->  
               <xsl:sort select="substring(date,1,2)"/> <!-- day sort -->
          </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="Shift"> 
       <Shift>
           <date><xsl:value-of select="date"/></date>
           <title1><xsl:value-of select="title1"/></title1>
           <gm><xsl:value-of select="gm"/><gm>
           <title2><xsl:value-of select="title2"/></title2>
           <director><xsl:value-of select="director"/></director>
           <nurse><xsl:value-of select="nurse"/></nurse>
       </Shift>
    </xsl:template>
</xsl:stylesheet>

And Here's my ASP Code:

<%

Set entries = Server.CreateObject("Microsoft.XMLDOM")
Set entry = Server.CreateObject("Microsoft.XMLDOM")
Set xml = Server.CreateObject("Microsoft.XMLDOM")
Set xsl = Server.CreateObject("Microsoft.XMLDOM")
Set newxml = Server.CreateObject("Microsoft.XMLDOM")

xml.async = False
xml.load (Server.MapPath("rota.xml"))

xsl.async = False
xsl.load(Server.MapPath("indexrota.xsl"))
newxml.async = False
newxml.load(xml.transformNode(xsl))

set entries = newxml.getElementsbyTagName("Shift")
noOfEntries = entries.length
startDate = "15/07/2010"
LastDate = DateAdd("m",1,date())


Response.Write("<table><tr><th>Date</th><th>Title</th><th>GM</th><th>Title</th><th>Director</th><th>Nurse / Matron</th></tr>")
For i = 0 To (noOfEntries - 1)
    Set entry = entries.item(i)
    If isDate(entry.childNodes(0).text) Then
        meh = CDate(entry.childNodes(0).text)
        beginning = DateDiff("d", meh, startDate)
        ended = DateDiff("d", meh, LastDate)
        If beginning + 1 <= 0 And ended >= 0 Then
            Response.Write("<tr>"&_
            "<td>" & entry.childNodes(0).text & "</td>"&_
            "<td>" & entry.childNodes(1).text & "</td>"&_
            "<td>" & entry.childNodes(2).text & "</td>"&_
            "<td>" & entry.childNodes(3).text & "</td>"&_
            "<td>" & entry.childNodes(4).text & "</td>"&_
            "<td>" & entry.childNodes(5).text & "</td>"&_
            "</tr>")
            End If
        End If
    Next
    Response.Write("</table>")
%>

I'm sure it's a case of the XSL because the ASP has worked perfecton the XML before

+1  A: 

There are two problems with your XSL.

Firstly, where you copy the gm element, you have not correctly closed off the gm tag.

<gm><xsl:value-of select="gm"/><gm> 

This should become

<gm><xsl:value-of select="gm"/></gm> 

Secondly, althuogh you are copying the Shift elements, your resultant XML does not contain a root element. You need to put a Rota element outside your xsl:apply-templates call

<xsl:template match="/"> 
   <Rota>  
       <xsl:apply-templates select="$strXPath">  
           <xsl:sort select="substring(date,7,4)"/> <!-- year sort -->  
           <xsl:sort select="substring(date,4,2)"/> <!-- month sort -->    
           <xsl:sort select="substring(date,1,2)"/> <!-- day sort -->  
        </xsl:apply-templates>  
    </Rota>
</xsl:template>  

Note that you can simplify the copying of the Shift element, simply by doing this

<xsl:template match="Shift">  
   <xsl:copy-of select="." />
</xsl:template> 

There is also a problem with the ASP code. The line newxml.load(xml.transformNode(xsl)) is incorrect. Because transformNode returns a string containing the XML, you really need to do the following

newxml.loadXml(xml.transformNode(xsl))

Use load when loading xml from a file. Use loadXml when loading a string containing Xml

Tim C
Hi, thank you your suggestions worked on the XML and it now loads properly. I see that it's lowercased the S on Shift.I've had another issue though, this time on the ASP side of things.Im using set entries = newxml.getElementsbyTagName("shift") noOfEntries = entries.lengthto feed the number of shifts into the for loop that then only displays the ones for the current month. When I run the getElementsByTagName it returns 0, even though a response.write of the newxml code reveals it is coming out correctly.Any idea how to solve this? Thanks.
Colin Wren
Try newxml.documentElement.SelectNodes("Shift")
Tim C
I've tried that and it returnedError Type:Microsoft VBScript runtime (0x800A01A8)Object required: '[object]'I am loading the converted document correctly aren't I?//EDIT// I just took the documentElement part out and it's not causing an error but still isn't finding the nodes
Colin Wren
I have just noticed the problem is with the line **newxml.load(xml.transformNode(xsl))**. Because transformNode returns a string containing the XML, you really need to do **newxml.loadXml(xml.transformNode(xsl))**. Use **load** when loading xml from a file. Use **loadXml** when loading a string containing Xml.
Tim C
This worked, Thanks alot. Sorry for not replying over the weekend but this was for work.
Colin Wren
A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Rota">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:sort select="substring(date,7)"/>
                <xsl:sort select="substring(date,4,2)"/>
                <xsl:sort select="substring(date,1,2)"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

With this input:

<Rota>
    <Shift>
      <date>30/07/2010</date>
      <title1>GM Specialised Medicine</title1>
      <gm>Alison Watson</gm>
      <title2>DDO Medicine &amp; Cardio.</title2>
      <director>Suzanne Marsello</director>
      <nurse>n/a</nurse>
    </Shift>
   <Shift>
      <date>23/07/2010</date>
      <title1>GM Neurosciences</title1>
      <gm>Katie Cusick</gm>
      <title2>Chief Operating Officer</title2>
      <director>Patrick Mitchell</director>
      <nurse>n/a</nurse>
    </Shift>
</Rota>

Output:

<Rota>
    <Shift>
        <date>23/07/2010</date>
        <title1>GM Neurosciences</title1>
        <gm>Katie Cusick</gm>
        <title2>Chief Operating Officer</title2>
        <director>Patrick Mitchell</director>
        <nurse>n/a</nurse>
    </Shift>
    <Shift>
        <date>30/07/2010</date>
        <title1>GM Specialised Medicine</title1>
        <gm>Alison Watson</gm>
        <title2>DDO Medicine &amp; Cardio.</title2>
        <director>Suzanne Marsello</director>
        <nurse>n/a</nurse>
    </Shift>
</Rota>

Also, this stylesheet works:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:sort select="substring(date,7)"/>
                <xsl:sort select="substring(date,4,2)"/>
                <xsl:sort select="substring(date,1,2)"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Note: Correct substring. I change input order because default order is ascending. If you want descendent order add to xsl:sort this attribute order="descending".

EDIT: Reverted wrong substring. Also, why don't you do all with XSLT? As example, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:param name="startDate" select="20100715"/>
    <xsl:param name="endDate" select="$startDate + 100"/>
    <xsl:template match="Rota">
        <table>
            <tr>
                <th>Date</th>
                <th>Title</th>
                <th>GM</th>
                <th>Title</th>
                <th>Director</th>
                <th>Nurse / Matron</th>
            </tr>
            <xsl:apply-templates select="Shift[concat(substring(date,7),
                                                      substring(date,4,2),
                                                      substring(date,1,2))
                                               >= $startDate]
                                               [$endDate >=
                                               concat(substring(date,7),
                                                      substring(date,4,2),
                                                      substring(date,1,2))]">
                <xsl:sort select="substring(date,7)"/>
                <xsl:sort select="substring(date,4,2)"/>
                <xsl:sort select="substring(date,1,2)"/>
            </xsl:apply-templates>
        </table>
    </xsl:template>
    <xsl:template match="Shift">
        <tr>
            <xsl:apply-templates/>
        </tr>
    </xsl:template>
    <xsl:template match="Shift/*">
        <td>
            <xsl:value-of select="."/>
        </td>
    </xsl:template>
</xsl:stylesheet>

Output:

<table>
    <tr>
        <th>Date</th>
        <th>Title</th>
        <th>GM</th>
        <th>Title</th>
        <th>Director</th>
        <th>Nurse / Matron</th>
    </tr>
    <tr>
        <td>23/07/2010</td>
        <td>GM Neurosciences</td>
        <td>Katie Cusick</td>
        <td>Chief Operating Officer</td>
        <td>Patrick Mitchell</td>
        <td>n/a</td>
    </tr>
    <tr>
        <td>30/07/2010</td>
        <td>GM Specialised Medicine</td>
        <td>Alison Watson</td>
        <td>DDO Medicine &amp; Cardio.</td>
        <td>Suzanne Marsello</td>
        <td>n/a</td>
    </tr>
</table>
Alejandro
Thanks, I'm still getting not getting a responce when running newxml.getElementByTagName("Shift"). Any idea why that would be?
Colin Wren
Thanks for your responce. I managed to do what I needed with Tim C's solution but thanks for showing me how to use XSL
Colin Wren
@Colin Wren: You are wellcome. I don't work any more with clasic ASP... For me, it's important that you take notice that all the job (including building the table) can be done easily with XSLT.
Alejandro