Re: Problems with XSL, XML code

Subject: Re: Problems with XSL, XML code
From: "John E. Simpson" <simpson@xxxxxxxxxxx>
Date: Tue, 03 Oct 2000 11:15:06 -0400
At 05:24 AM 10/03/2000 -0700, Marcos Coelho wrote:
I felt I was not very clear, so I made an Webpage where I explainedmy
problem better I wish.
There I put my XML, XSL, and the OUT PUTS files which I want and what I
got!
The address is
http://www.geocities.com/marcos_coelho/xml/doubt.htm

Marcos, I looked at your page. Actually, I'm surprised you got *any* output, as your stylesheet is not legitimate. (What XSLT processor are you using?)


First, you don't need the xmlns:fo namespace declaration, since you're not using any elements whose names begin with "fo:".

Second, you *do* need a default namespace declaration for the HTML namespace, since all the result-tree (HTML) elements in the stylesheet have no prefixes. So just replace the xmlns:fo declaration with:

xmlns="http://www.w3.org/TR/REC-html40";

Third, you've got an <xsl:value-of> element which contains an <xsl:template> element. Saxon reports (rightly) that <xsl:value-of> must be an empty element. Remove the <xsl:value-of...> and </xsl:value-of> start and end tags. (Leave what it contains for now.)

Saxon now reports (rightly) that <xsl:template> is a top-level element. That means it must be a child of the root <xsl:stylesheet> element. So move the start and end tags of the xsl:template element so they contain everything else. That is, you should at this point have:

<xsl:stylesheet [...namespace decls....]>
<xsl:template match="COSMO">
  <html>
    <head>
      <title>XML --> XSL ---> HTML </title>
    </head>
  <body>
    <table>
      <tr>
        <xsl:for-each select="NOTICIAS">
          <td><!-- 1 col --><xsl:for-each select="TITULO"/></td>
          <td><!-- 2 col --><xsl:for-each select="DATA"/></td>
          <td><!-- 3 col --><xsl:for-each select="HORA"/></td>
          <td><!-- 4 col --><xsl:for-each select="CONTEUDO"/></td>
          <td><!-- 5 col --><xsl:for-each select="AUTOR"/></td>
          <td><!-- 6 col --><xsl:for-each select="CODIGO"/></td>
          <td><!-- 7 col --><xsl:for-each select="TIPO"/></td>
        </xsl:for-each>
      </tr>
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

(Btw, to run this in Saxon or IE5.5+, you'll probably also need to add an encoding declaration to your XML document, that is:
<?xml version="1.0" encoding="iso-8859-1" ?>
That's because of the extended ASCII characters such as ã that are in your document.)


When you run this, you indeed get an empty table displayed. Why is that? For an answer, look at any one of your <td> elements in the stylesheet, e.g.:

<td><!-- 1 col --><xsl:for-each select="TITULO"/></td>

What you're inserting in there within the <td> element is... precisely nothing! The <xsl:for-each> element doesn't place anything at all in the result tree.

So let's try replacing each of those <xsl:for-each> elements with an <xsl:value-of>, e.g.:

<td><!-- 1 col --><xsl:value-of select="TITULO"/></td>

Let's also add a border to the table which (I can safely report) will now be displayed, to help in debugging the output.

As you can see if you've done the above, now you've got output, but the order/display is goofed up -- it's all in one long row! And why is that? Because that's what your template for the <COSMO> template says to do. There's only one <tr> element created in the result tree for a given <COSMO> element. But according to your explanation at the page you cited above, you want one row for each *child* of each <NOTICIAS> element.

So let's change the one template rule to two. The first will handle your <COSMO> element more or less as is; the second will handle all children of the <NOTICIAS> element. The most important change is to break out the <tr> and <td> elements to be created in the result tree so that they're in this second template rule.

<xsl:template match="COSMO">
  <html>
    <head>
      <title>XML --> XSL ---> HTML </title>
    </head>
  <body>
    <table border="1">
      <xsl:for-each select="NOTICIAS">
        <!-- Line below invokes template rule for all children
        of the <NOTICIAS> elements. -->
        <xsl:apply-templates/>
      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

<xsl:template match="TITULO|DATA|TIPO|AUTOR|CODIGO|HORA|CONTEUDO">
  <tr>
    <td><xsl:value-of select="."/></td>
  </tr>
</xsl:template>

Output from this is not exactly as you'd requested. For example, you didn't want to display the <HORA> element; if that's the case, simply remove it (and the "|" of course!) from the second template rule's match pattern.

Does that help -- not just to solve your problem(s), but to understand what you need to do from here?

==========================================================
John E. Simpson | "Curiosity killed the cat,
http://www.flixml.org | but for a while I was a
XML Q&A: http://www.xml.com | suspect." (Steven Wright)



XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list



Current Thread