Search code examples
xsltindentationpre

XSLT: is selective indentation possible?


I'm using XSLT to turn XML into HTML. If I specify indent='no' in <xsl:output>, adjacent tags in the generated HTML are run together into a single long line (all whitespace for layout between them is removed), which makes it very hard to read and understand. However, if I specify "indent-'yes'", the HTML is nicely indented, but this completely ruins the layout of text enclosed in <pre> ... </pre>.

Is there any way to get the best of both worlds, having indent='yes' while leaving <pre> blocks unchanged?

Edit: I tried to come up with a minimal example, but I can't reproduce what I'm seeing, so there's obviously something else going on. FWIW, this is what I tried:

<?xml version='1.0'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method="html" encoding="UTF-8" indent="yes"/>

<xsl:template match="demo">
  <html>
    <head>
       <title>Demo</title>
    </head>
    <body>
      <h1>This is a demo</h1>
      <hr/>
      <xsl:apply-templates/>
      <hr/>
    </body>
  </html>
</xsl:template>

<xsl:template match="foo">
  <h2>This is foo</h2>
</xsl:template>

<xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

I applied this stylesheet to this input:

<demo>
    <p>Some HTML</p>
    <pre>this is
preformatted text
which should not be<br/>
indented</pre>
    <foo/>
    <hr/>
</demo>

and the output looked like this: not indented, but at least readable.

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Demo</title>
</head>
<body>
<h1>This is a demo</h1>
<hr>

<p>Some HTML</p>

<pre>this is
preformatted text
which should not be<br>
indented</pre>

<h2>This is foo</h2>

<hr>

<hr>
</body>
</html>

The implementation I'm using is whatever comes with Java 1.8.


Solution

  • It turned out that the original XML had pre> blocks all on one line, with lines separated by <br/> rather than newlines. This meant that the following input:

    <pre>        public static void main(String[] args) {<br />          <textarea cols='60' rows='10'></textarea><br />        }</pre>
    

    produced this output:

    <pre>        public static void main(String[] args) {<br>          
    <textarea cols="60" rows="10"></textarea>
    <br>        }</pre>
    

    The solution was to add the following rule to replace the <br/>s with newlines:

    <xsl:template match="pre//br">
      <xsl:text>&#10;</xsl:text>
    </xsl:template>
    

    Sorry to have wasted your time.