0
votes

I've following structure of xml-file:

<root-element>
    <child1>
        Some text
    </child1>
    <child2>
        <grandchild>
            Some text
        </grandchild>
    </child2>
</root-element>

My aim is to generate html-output with the aid of a xslt-file. In doing so I want to apply a template to direct children of root element, which outputs the name of the tag as heading 1 and it contents enclosed in <p></p>. As to grandchildern, i want to use almost the same template, but to output their names as heading 2.

To make easier to understand what I want here is sample how HTML-Output would look like:

<html>
    <head>
        <title>Sample</title>
    </head>
    <body>
        <h1>Child1</h1>
        <p>Some text</p>

        <h1>Child2</h1>
        <h2>Grandchild</h2>
        <p>Some text</p>
    </body>
</html>

Now my attempt looks like this: http://pastebin.com/wKgSLbcE

But it doesn't work with <xsl:for-each select="./*"> and <xsl:for-each select="././*"> so I want to ask you for help.

1
Please edit your markup sample to show well-formed XML. Currently you have a start tag <child1> that is not closed at all so it is hard to tell how your input looks and is nested. Then consider to provide a sample of the corresponding HTML you want to create.Martin Honnen
You're right. Now it looks correctly.Danny Lo

1 Answers

1
votes

It might be better to use template matching to achieve your aim, as this is much more in the spirit of XSLT.

For example, to match your 'child' elements, which I guess can be named anything, you could do something like this to match the child elements of the top level element

<xsl:template match="/*/*">
   <h1>
      <!-- Output name here -->
   </h1>
   <xsl:apply-templates />
</xsl:template>

Similarly to match grandchildren elements, use this

<xsl:template match="/*/*/*">

As for paragraphs, you would have a template matching the text nodes

<xsl:template match="text()">
   <p>
      <xsl:value-of select="normalize-space(.)" />
   </p>
</xsl:template>

Here is the full XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output version="4.0" method="html" indent="no" encoding="UTF-8" use-character-maps="spaces" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" doctype-system="http://www.w3.org/TR/html4/loose.dtd"/>

   <xsl:template match="/*">
      <html>
         <head>
            <title>Abschlussarbeit</title>
         </head>
         <body>
            <xsl:apply-templates />
         </body>
      </html>
   </xsl:template>

   <xsl:template match="/*/*">
      <h1>
         <xsl:value-of select="concat(translate(substring(name(), 1, 1), abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ), substring(name(), 2))"/>
      </h1>
      <xsl:apply-templates />
   </xsl:template>

   <xsl:template match="/*/*/*">
      <h2>
         <xsl:value-of select="concat(translate(substring(name(), 1, 1), abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ), substring(name(), 2))"/>
      </h2>
      <xsl:apply-templates />
   </xsl:template>

   <xsl:template match="text()">
      <p>
         <xsl:value-of select="normalize-space(.)" />
      </p>
   </xsl:template>
</xsl:stylesheet>

When applied to your XML, the following is output

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
   <head>
      <META http-equiv="Content-Type" content="text/html">
      <title>Abschlussarbeit</title>
   </head>
   <body>
      <h1>child1</h1>
      <p>Some text</p>
      <h1>child2</h1>
      <h2>grandchild1</h2>
      <p>Some text</p>
   </body>
</html>

Note, if you are using XSLT 2.0, there is the xpath function "upper-case" you can use to convert the first character of your element name to upper case, rather than using the "translate" method which is used in XSLT 1.0