I. Solution 1:
Let me first analyze the problem here:
Given this source XML document (invented, as you haven't provided any):
<Object>
<Table>
</Table>
<Table>
</Table>
<Table>
</Table>
<Table>
</Table>
</Object>
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
<!--
<xsl:template match="Table">
<a href="#">
Table here
</a>
</xsl:template>
-->
</xsl:stylesheet>
exactly reproduces the problem -- the result is:
<a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a>
Now, just uncomment the commented template and comment out the first template:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<!--
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
-->
<xsl:template match="Table">
<a href="#">
Table here
</a>
</xsl:template>
</xsl:stylesheet>
The result has the wanted indentation:
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
And this was solution 1
II. Solution 2:
This solution may reduce to minimum the required modifications to your existing XSLT code:
This is a two-pass transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
The idea is that we don't even touch the existing code, but capture its output and using a few lines of additional code only, we format the output to have the wanted, final appearance.
When this transformation is applied on the same XML document, the same, wanted result is produced:
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
Finally, here is a demonstration how this minor change can be introduced, without touching at all any existing XSLT code:
Let's have this existing code in c:\temp\delete\existing.xsl
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
If we run this we get the problematic output.
Now, instead of running existing.xsl
, we run this transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:import href="file:///c:/temp/delete/existing.xsl"/>
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-imports/>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
The result is the wanted one and the existing code is untouched at all:
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
Explanation:
We import any existing code that is at the top level of the import-precedence hierarchy (not imported by other stylesheets), using xsl:import
.
We capture the output of the existing transformation in a variable. It has the infamous RTF (Result Tree Fragment) that needs to be converted to regular tree to be processed further.
The key moment is performing xsl:apply-imports
when capturing the output of the transformation. This ensures that any template from the existing code (even one that we override -- such as the template matching /
) will be selected for execution as in the case when the existing transformation is performed by itself).
We convert the RTF into a regular tree using the msxsl:node-set()
extension function (XslCompiledTransform also supports the EXSLT node-set()
extension function).
We perform our cosmetic adjustments on the so produced regular tree.
Do Note:
This represents a general algorithm for post-processing existing transformations without touching the existing code.
XslTransform
leaves the XSL untoched. And, if you can, do you know a good source to learn XSL in general?, I can google but it's always better if it's readproof :). Thanks! – Brigitta