Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<blockquote> <p>What am I missing here?</p> </blockquote> <p>I think that one shouldn't be messing with the default indentation of the XSLT processor. </p> <p>Most often the combination of <code>&lt;xsl:output indent="yes"/&gt;</code> and <code>&lt;xsl:strip-space elements="*"/&gt;</code> is sufficient for getting good indentation.</p> <p><strong>This transformation</strong>:</p> <pre><code>&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt; &lt;xsl:output omit-xml-declaration="yes" indent="yes"/&gt; &lt;xsl:strip-space elements="*"/&gt; &lt;xsl:template match="node()|@*"&gt; &lt;xsl:copy&gt; &lt;xsl:apply-templates select="node()|@*"/&gt; &lt;/xsl:copy&gt; &lt;/xsl:template&gt; &lt;xsl:template match="unit"&gt; &lt;unit&gt; &lt;category1&gt; &lt;xsl:apply-templates select="*[not(position() &gt;2)]"/&gt; &lt;/category1&gt; &lt;category2&gt; &lt;xsl:apply-templates select="*[position() &gt;2]"/&gt; &lt;/category2&gt; &lt;/unit&gt; &lt;/xsl:template&gt; &lt;/xsl:stylesheet&gt; </code></pre> <p><strong>when applied on the provided XML document:</strong></p> <pre><code>&lt;list&gt; &lt;unit&gt; &lt;data1&gt;a&lt;/data1&gt; &lt;data2&gt;b&lt;/data2&gt; &lt;data3&gt;c&lt;/data3&gt; &lt;/unit&gt; &lt;/list&gt; </code></pre> <p><strong>Produces the wanted, well-indented result</strong>:</p> <pre><code>&lt;list&gt; &lt;unit&gt; &lt;category1&gt; &lt;data1&gt;a&lt;/data1&gt; &lt;data2&gt;b&lt;/data2&gt; &lt;/category1&gt; &lt;category2&gt; &lt;data3&gt;c&lt;/data3&gt; &lt;/category2&gt; &lt;/unit&gt; &lt;/list&gt; </code></pre> <p><strong>This same result is produced when the transformation is run with any of the following seven XSLT processors</strong>:</p> <ul> <li><p>AltovaXML (XML-SPY).</p></li> <li><p>.NET XslCompiledTransform.</p></li> <li><p>.NET XslTransform.</p></li> <li><p>Saxon 6.5.4.</p></li> <li><p>Saxon 9.1.05 (XSLT 2.0 processor).</p></li> <li><p>XQSharp/XMLPrime (XSLT 2.0 processor).</p></li> <li><p>AltovaXml (for XSLT 2.0).</p></li> </ul> <p><strong>The case with MSXML3/4/6 is more complicated</strong> -- these XSLT processors' indentation consists just of a new-line character, so every element is on a new line, but appears at the start of the line.</p> <p>For these XSLT processors I use the following two-pass processing, the first pass being the above transformation and the second applies to the result of the first pass <strong><a href="http://www.dpawson.co.uk/xsl/sect2/pretty.html#d8625e19" rel="nofollow">one of the XML pretty-printers</a></strong> proposed by Nikolai Grigoriev and available in the <strong><a href="http://www.dpawson.co.uk/xsl/index.html" rel="nofollow">XSLT FAQ</a></strong> site maintained by <strong><a href="http://www.dpawson.co.uk/" rel="nofollow">Dave Pawson</a></strong>:</p> <pre><code>&lt;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"&gt; &lt;xsl:output method="xml"/&gt; &lt;xsl:strip-space elements="*"/&gt; &lt;xsl:param name="indent-increment" select="' '" /&gt; &lt;xsl:variable name="vrtfPass1"&gt; &lt;xsl:apply-templates select="/*"/&gt; &lt;/xsl:variable&gt; &lt;xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)"/&gt; &lt;xsl:template match="node()|@*"&gt; &lt;xsl:copy&gt; &lt;xsl:apply-templates select="node()|@*"/&gt; &lt;/xsl:copy&gt; &lt;/xsl:template&gt; &lt;xsl:template match="/"&gt; &lt;xsl:apply-templates select="$vPass1/*" mode="pass2"/&gt; &lt;/xsl:template&gt; &lt;xsl:template match="unit"&gt; &lt;unit&gt; &lt;category1&gt; &lt;xsl:apply-templates select="*[not(position() &gt;2)]"/&gt; &lt;/category1&gt; &lt;category2&gt; &lt;xsl:apply-templates select="*[position() &gt;2]"/&gt; &lt;/category2&gt; &lt;/unit&gt; &lt;/xsl:template&gt; &lt;xsl:template match="*" mode="pass2"&gt; &lt;xsl:param name="indent" select="'&amp;#xA;'"/&gt; &lt;xsl:value-of select="$indent"/&gt; &lt;xsl:copy&gt; &lt;xsl:copy-of select="@*" /&gt; &lt;xsl:apply-templates mode="pass2"&gt; &lt;xsl:with-param name="indent" select="concat($indent, $indent-increment)"/&gt; &lt;/xsl:apply-templates&gt; &lt;xsl:value-of select="$indent"/&gt; &lt;/xsl:copy&gt; &lt;/xsl:template&gt; &lt;xsl:template match="comment()|processing-instruction()" mode="pass2"&gt; &lt;xsl:copy /&gt; &lt;/xsl:template&gt; &lt;!-- WARNING: this is dangerous. Handle with care --&gt; &lt;xsl:template match="text()[normalize-space(.)='']" mode="pass2"/&gt; &lt;/xsl:stylesheet&gt; </code></pre> <p><strong>When this transformation is performed on the same (provided) XML document (above), the produced result has the desired indentation</strong>:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-16"?&gt; &lt;list&gt; &lt;unit&gt; &lt;category1&gt; &lt;data1&gt;a &lt;/data1&gt; &lt;data2&gt;b &lt;/data2&gt; &lt;/category1&gt; &lt;category2&gt; &lt;data3&gt;c &lt;/data3&gt; &lt;/category2&gt; &lt;/unit&gt; &lt;/list&gt; </code></pre> <p>These are all XSLT processors I have on my computers. I suggest to try the last transformation -- the chances are that it will produce the wanted results with Xalan-C.</p> <p><strong>Do note</strong>:</p> <p>The last transformation uses an MSXML - specific extension function xxx:node-set(), belonging to an MSXML - specific namespace:</p> <pre><code>xmlns:ext="urn:schemas-microsoft-com:xslt" </code></pre> <p><strong>For Xalan this needs to be replaced with</strong>:</p> <pre><code>xmlns:ext="http://exslt.org/common" </code></pre> <p><strong>or, in case EXSLT isn't supported, then the native Xalan namespace</strong>:</p> <pre><code>xmlns:ext="http://xml.apache.org/xalan </code></pre> <p>In this last case, the call to the <code>ext:node-set()</code> function must be replaced with a call to <code>ext:nodeset()</code> (note the missing dash):</p> <pre><code> &lt;xsl:variable name="vPass1" select="ext:nodeset($vrtfPass1)"/&gt; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload