Reputation: 19996
I have an XSLT that is transformed to an XML using System.Xml.Xsl.XslCompiledTransform
. The problem is that tags with spaces are converted to empty tags. Below is a minimal sample to reproduce the problem.
Original data:
<data>
<content>A</content>
<content> </content>
<content>B</content>
</data>
Output data:
<?xml version="1.0" encoding="utf-8"?>
<data>
<content>A</content>
<content />
<content>B</content>
</data>
The second tag is wrong! The space must not be eaten like that.
And the XSLT:
<?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:preserve-space elements="content"/>
<xsl:template match="//data">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
Is the XSLT wrong? Or should I blame the .NET XSL transformer (I've tried both 3.5 SP1 and 4.0)?
Please help!
Upvotes: 3
Views: 1458
Reputation: 11983
As David pointed out the problem is that the spaces are stripped out before getting to the XSLT. The solution when using .NET is to use an XmlReader
to read the input XML - this code should do the trick:
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(@"c:\temp\space.xslt");
using (XmlReader reader = XmlReader.Create(@"c:\temp\spaceSample.xml")) {
using (XmlWriter writer = XmlWriter.Create(@"c:\temp\space.xml")) {
transform.Transform(reader, writer);
}
}
where spaceSample.xml
in the input file, space.xml
is the output and space.xslt
is the transformation.
(Tested with .NET 4.0)
Upvotes: 2
Reputation: 5652
If you are using msxml it has a documented non conformance with respect to the xml spec and strips white space by default. You can either add xml:space="preserve"
to your element so that white space in that file is correctly handled, or if calling msxml via an API (but not if directly parsing xml in Internet Explorer) set its preserveWhitespace property to true http://msdn.microsoft.com/en-us/library/windows/desktop/ms766466%28v=vs.85%29.aspx
Unrelated to the white space issue
<xsl:template match="//data/content">
<xsl:element name="{title}">
<xsl:apply-templates select="//data/content"/>
</xsl:element>
</xsl:template>
is never executed, as the template matching data
just copies the entire document, without applying templates recursively. If it were executed it would loop infinitely as it says, for each content element, apply templates to every content element.
UPDATE If you don't need to preserve the exact white space, just putting a space in to make it non-empty then you can correct for the broken parsing by putting space back in the stylesheet, first fix things so templates are recursively applied, then have an extra template for empty content elements, making them non empty by adding a space.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="content[not(node())]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:text> </xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2
Reputation: 86774
You need to include (at top level):
<xsl:preserve-space elements="content"/>
If there are several node types that have to preserve spaces, list them in the elements
attribute separated by blanks. This is documented here.
Upvotes: 4