0
votes

OK, I have an XML document which comprises the results of two different reports:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="friends.xsl"?>
<root>
<report name="Type1">
<Datarow>
<Name>Fred</Name>
<Age>39</Age>
</Datarow>
<Datarow>
<Name>George</Name>
<Age>41</Age>
</Datarow>
</report>
<report name="Type2">
<Datarow>
<Name>Sheila</Name>
<Age>20</Age>
</Datarow>
<Datarow>
<Name>Susie</Name>
<Age>23</Age>
</Datarow>
</report>
</root>

I am transforming this with (in this example) a simple XSL file using XSL 1.0.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="report[@name='Type1']">
<table>
<tr><td>Name</td><td>Age</td></tr>
<xsl:apply-templates select="Datarow"/>
</table>
</xsl:template>

<xsl:template match="Datarow">
<tr><td> <xsl:value-of select="Name"/></td>
<td><xsl:value-of select="Age"/></td></tr>
</xsl:template>
</xsl:stylesheet>

My understanding is that the first template match statement sets the node pointer at the XML report node where the report name attribute is "Type1". I then have a apply templates select looking for Datarow. This matches my Datarow template which brings back the name and age details.

The problem is that it brings back the Name and Age for the Type1 report, formatted in a table as i specified, but then I get the text from the Type2 report node as unformatted text:

<div id="result_output">
<table style="border: solid 1px;">
<tbody><tr>
<td>Name</td>
<td>Age</td>
</tr>
<tr>
<td>Fred</td>
<td>39</td>
</tr>
<tr>
<td>George</td>
<td>41</td>
</tr>
</tbody></table>


Sheila
20


Susie
23


</div>

What am I doing wrong?

1
Could you post the expected result, please? -- Hint: what you see is the result of built-in template rules being applied to <report name="Type2">. - michael.hor257k

1 Answers

0
votes

You need to add a template match on the <report name="Type2"> node which also exists in the document's root. Because you do not redesign the <root> all document content will show including those with explicit template matches. With the libxslt engine, the Sheila and Susie data show with <tr> and <td> tags (due to the <Datarow> template match which they would follow). But output is a not well-formed XML since the new root, <table>, does not include such nodes.

To remove this unneeded node, consider adding an empty template match on unneeded report type. Yet, I would dub this a backward-looking, reactive approach.

<xsl:template match="report[@name='Type2']"/>

A preferred option is to re-write the root to only apply the needed report type. This would be the forward-looking, proactive approach (since other report types may potentially exist). Also, usually, in XSLT you would begin at the <root> and then work down the tree.

...
<xsl:template match="/root">
    <xsl:apply-templates select="report[@name='Type1']"/>
</xsl:template>

<xsl:template match="report">    
    <table>
        <tr><td>Name</td><td>Age</td></tr>
        <xsl:apply-templates select="Datarow"/>
    </table>
</xsl:template>
...