Using Visual Studio to perform the transform during development the resulting xml contains text from the source xml in the destination that was contained in tags that do not match my template criteria
I was expecting that my select Group in the first template to find any elements named Group that are immediate children of CrystalReport and pass them along in the apply template call. I understood that the match filter on my second template would only take in Group‘s that have an attribute of Level=1 and write them out. I’d expect everything else to be ignored.
Why does “not this” appear in my output?
source
<?xml version="1.0" encoding="utf-8" ?>
<!--
UPDATE: Note that adding the xmlns attribute causes all output
to disappear unless you use Chris's second solution.
-->
<CrystalReport xmlns="urn:crystal-reports:schemas:report-detail" >
<Group Level="1">
<GroupHeader>
<Section>
<Field FieldName="apple" />
</Section>
</GroupHeader>
<Group Level="2">
not this
</Group>
</Group>
</CrystalReport>
transform
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/CrystalReport">
<root>
<xsl:apply-templates select="Group"/>
</root>
</xsl:template>
<xsl:template match="Group[@Level='1']/GroupHeader">
<tag1><xsl:value-of select="Section/Field/@FieldName"/></tag1>
</xsl:template>
</xsl:stylesheet>
output
<?xml version="1.0" encoding="utf-8"?>
<root>
<tag1>apple</tag1>
not this
</root>
You are facing the problem where the built in templates of the XML parser are coming into play. You are apply templates to all of the
Groupelements, but only catching one of them with your own templates. The other is handled by the default templates which out put the values of all nodes. I suggest that you changeinto
This will override the root default templates which are producing the extra output. You can find more on the built in template rules at http://www.w3.org/TR/xslt#built-in-rule
Then override the basic text() template so you final XSLT looks a bit like this
UPDATE
Or even simpler you could just match the desired elements and use something like this
This will leave the default text() templates in place which can be very handy.