Using XSLT to turn content of WYSIWYG stored in XML into HTML The CMS I use uses the Xalan XSLT processor which is a XSLT version 1.0 processor. Editors who use WYSIWYG fields within the CMS can save content that will look like either:

&lt;story&gt;
    &lt;p&gt;Story Text which may have &lt;em&gt;formatting&lt;/em&gt;.&lt;/p&gt;
&lt;/story&gt;


or:

&lt;story&gt;Story Text which may have &lt;em&gt;formatting&lt;/em&gt;.&lt;/story&gt;


or even:

&lt;story&gt;
    &lt;div&gt;Story Text which may&lt;br /&gt; have &lt;em&gt;formatting&lt;/em&gt;.&lt;/div&gt;
&lt;/story&gt;


In order to handle those varying cases I've been using:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
&lt;xsl:output method="html"/&gt; 
&lt;xsl:template match="/system-index-block"&gt;
    &lt;xsl:for-each select="story"&gt;
        &lt;xsl:choose&gt;
            &lt;!-- If wrapped in an element --&gt;
            &lt;xsl:when test="./p|./div"&gt;
                &lt;!-- copy what is inside story, allow for text outside of elements --&gt;
                &lt;xsl:copy-of select="./text()|./*"/&gt;
            &lt;/xsl:when&gt;
            &lt;!-- wrap the content in a paragraph tag --&gt;
            &lt;xsl:otherwise&gt;
                &lt;p&gt;
                    &lt;!-- copy text and tags from inside story --&gt;
                    &lt;xsl:copy-of select="./text()|./*"/&gt;
                &lt;/p&gt;
            &lt;/xsl:otherwise&gt;
        &lt;/xsl:choose&gt;
    &lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;


Is there a better way of producing well formed HTML from this data? Is there a way to simply this?
You should change your mindset when working with XSLT: look at it as a functional language, where you declare rules for the transformation of elements. Think about it in terms of events: when a p element is found in input, I expect this and that in the output.

First, regarding the definition of your data. You should ask for (or create) a more formal description of the data. There are different formats available to describe the structure (grammar), DTD and XML Schema being the more common. There are more simple alternatives such as RELAX NG and Schematron.

My guess, from your stylesheet and your descriptions:


there is always a &lt;system-index-block&gt; at the top
there is a list of &lt;story&gt; elements in &lt;system-index-block&gt;
there is mixed HTML contents in &lt;story&gt;, with &lt;p&gt;,&lt;div&gt;,&lt;br&gt;,&lt;em&gt; and text allowed


I am not sure about the last part: is it possible to have both text and div or paragraph at the top level in a story?

&lt;story&gt;
  Text before a &lt;p&gt;Paragraph&lt;/p&gt; in between or &lt;div&gt;Div&lt;/div&gt; even after ?
&lt;/story&gt;


You should break your unique template rule into several template rules, one or several for each element. Then to direct the flow from rule to rule, do not use for-each but rather apply-templates:

&lt;xsl:template match="system-index-block"&gt;
  &lt;!-- Note:
       You probably need to create the basic HTML structure Here: html, head, body
  --&gt;
  &lt;xsl:apply-templates /&gt; &lt;!-- you can specify select="story" but it is not required --&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="story[p|div]"&gt; &lt;!-- If wrapped in an element --&gt;
   &lt;xsl:apply-templates mode="copy" /&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="story"&gt; &lt;!-- wrap the content in a paragraph tag --&gt;
  &lt;p&gt;
    &lt;xsl:apply-templates mode="copy" /&gt;
  &lt;/p&gt;
&lt;/xsl:template&gt;


Note that I used the mode "copy" above: you can now create different rules for the same nodes depending on the mode, for example:

&lt;xsl:template match="text()" /&gt; &lt;!-- ignore text in normal mode, probably whitespace --&gt;

&lt;xsl:template match="text()" mode="copy"&gt;
    &lt;xsl:copy /&gt;
&lt;/xsl:template&gt;


Also, you will probably get into trouble because you only declared a namespace for the xsl prefix. You typically need a prefix/namespace declaration for the input and output formats. You will then need to use the prefix in match/select expressions and in the tag names for the output, for example, with input prefix bound to your input namespace and html bound to the html namespace:

&lt;xsl:template match="input:story"&gt; &lt;!-- wrap the content in a paragraph tag --&gt;
  &lt;html:p&gt;
    &lt;xsl:apply-templates mode="copy" /&gt;
  &lt;/html:p&gt;
&lt;/xsl:template&gt;


To go further, here are pointers that you will probably find useful:


Namespaces and XSLT Stylesheets
Identity transformation