XSLT Filter Templates

Tridion editors need to be able to copy/paste rich text content but remove unwanted markup that can break the published page. This is easily achieved in Tridion by using XSLT filters, but these can be tricky to get right so I will walk through the process to help you understand how XLST works and how to write more readable XSLT.

Copy Text Filter

The basic xsl filter shown below only accepts text from the original content and will remove unwanted markup

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" cdata-section-elements="script"/> 
 <xsl:template match="/">
  <xsl:apply-templates select="*"/>
 </xsl:template>
 
 <xsl:template match="*">
  <xsl:apply-templates select="node()"/>
 </xsl:template>
 <xsl:template match="text()">
  <xsl:value-of select="."/>
 </xsl:template>
</xsl:stylesheet>

This is because the filter matches the root node <xsl:template match="/">
and all of the nodes from the root <xsl:template match="*">
but only has a template to copy the content of the text nodes <xsl:template match="text()">

This is fine if you want to strip all markup but that would not be a typical case.

Copy Text and Selected Markup

Normally the template code would be very compact but not easy to understand. So, in the following examples I show simple expanded templates to make it easier to follow what is going on.

Empty templates containing only comments are included to explain what is going on, but these are not needed in your real filter.

Its perfectly fine to write your templates in this way. The performance of your template transform is not impacted by the extra instructions or comments. The XSL parser will ignore the extra code to and comments but it does makes your XSLT transform clearer for others to understand.

If you want to allow editors to copy/paste content and still maintain the formatting we add templates for each of the elements we want to allow to be pasted in.

  • paragraph
  • lists
  • links
  • images
  • heading
  • form
  • table

Filter HTML Elements

 <xsl:template match="p|em|strong|ul|ol|li|a|img|blockquote">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <!--  Heading Elements  Permitted -->
 <xsl:template match="h1|h2|h3|h4|h5|h6">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <!--  Form Elements Permitted -->
 <xsl:template match="form|legend|label|input|caption|fieldset|select|textarea|button|submit">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <!--  Table Elements Permitted -->
 <xsl:template match="table|th|tr|td|thead|tbody|tfoot|caption">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

Filter HTML Attributes

Now that we are copying html elements (tags) we need to be careful and handle the attributes that we want to allow on each element so that we can guarantee standards compliant html.

 <xsl:template match="@*">
  <!-- Filter out all Attributes except those permitted -->
 </xsl:template>
 <!-- Standard Attributes id, class, title, style, dir, lang, xml:lang -->
 <xsl:template match="@id|@title|@dir|@lang|@xml:lang">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted Label Element Attributes -->
 <xsl:template match="label/@for|label/@accesskey">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted Input Element Attributes -->
 <xsl:template match="input/@type|input/@value">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted Form Element Attributes -->
 <xsl:template match="form/@method|form/@action|form/@enctype">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted A Element Attributes -->
 <xsl:template match="a/@href">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted IMG Element Attributes -->
 <xsl:template match="img/@src|img/@alt|img/@width|img/@height|img/@longdesc">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
 <!-- Permitted table Element Attributes -->
 <xsl:template match="table/@*|thead/@*|tbody/@*|th/@*|td/@*|tr/@*">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

Convert Legacy HTML Elements

There may be old style HTML markup that we want to convert such as bold, italic, line breaks and horizontal rule.

 <!--  Bold Element Convertion  to strong text -->
 <xsl:template match="b">
  <xsl:element name="strong">
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
 <!--  Italic Element Convertion to emphasized text -->
 <xsl:template match="i">
  <xsl:element name="em">
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
 <!--  Span Element Convertion  -->
 <xsl:template match="span">
  <xsl:apply-templates select="node()|@*"/>
 </xsl:template>
 <!--  Div Element Convertion  -->
 <xsl:template match="div">
  <xsl:apply-templates select="node()|@*"/>
 </xsl:template>
 <!--  BR Element Convertion  -->
 <xsl:template match="br">
  <xsl:element name="br"/>
 </xsl:template>
 <!--  HR Element Convertion  -->
 <xsl:template match="hr">
  <xsl:element name="hr"/>
 </xsl:template>

Tridion GUI Formatting Features Configuration

The Tridion schema XSLT filter also requires a a couple of extra templates for the filter to work. These are the body, the R5GUIToolbar and the FormatingFeatures.

  <xsl:template match="body|R5GUIToolbar">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="@tcmuri">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

<xsl:template name="FormattingFeatures">
  <FormattingFeatures xmlns="http://www.tridion.com/ContentManager/5.2/FormatArea">
   <Doctype>Strict</Doctype>
   <AccessibilityLevel>3</AccessibilityLevel>
   <DisallowedStyles/>
   <DisallowedActions>
    <Underline/>
    <AlignLeft/>
    <Center/>
    <AlignRight/>
    <Font/>
    <Background/>
    <TableHeight/>
    <TableHAlign/>
    <TableBackground/>
    <TableCellWidth/>
    <TableCellHeight/>
    <TableCellBackground/>
   </DisallowedActions>
  </FormattingFeatures>
 </xsl:template>

Leave a Reply

Your email address will not be published. Required fields are marked *