3

I'm using Tridion 2011 SP1 HR1 and have created a new schema with one RTF field and have applied the following filtering XSLT:

<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <output omit-xml-declaration="yes" method="xml" cdata-section-elements="script"/>
  <template match="/ | node() | @*">      
    <copy>
      <apply-templates select="node() | @*"/>
    </copy>
  </template>
  <template match="*[      (self::br or self::p or self::div)     and      normalize-space(translate(., &apos; &apos;, &apos;&apos;)) = &apos;&apos;     and      not(@*)     and      not(processing-instruction())     and      not(comment())     and      not(*[not(self::br) or @* or * or node()])     and      not(following::node()[not(         (self::text() or self::br or self::p or self::div)        and         normalize-space(translate(., &apos; &apos;, &apos;&apos;)) = &apos;&apos;        and         not(@*)        and         not(processing-instruction())        and         not(comment())        and         not(*[not(self::br) or @* or * or node()])       )])     ]">
    <!-- ignore all paragraphs and line-breaks at the end that have nothing but (non-breaking) spaces and line breaks -->
  </template>
  <template match="br[parent::div and not(preceding-sibling::node()) and not(following-sibling::node())]">
    <!-- Chrome generates <div><br/></div>. Renders differently in different browsers. Replace it with a non-breaking space -->
    <text> </text>
  </template>
  <!-- remove disallowed elements but keep its children -->
  <template match="li/p">
    <apply-templates/>
  </template>
  <template match="h1">
    <element name="p">
        <apply-templates/>
    </element>
  </template>
  <template match="head | title | meta | base | style | scriptlink | font | ilayer | layer | small | u | span">
    <apply-templates/>
  </template>
  <!-- remove dissallowed attributes -->
  <template match="@style" />
  <template match="@bordercolor" />
  <template match="@class[.=&apos;MsoNormal&apos; or .=&apos;MsoNormalCxSpMiddle&apos; or .=&apos;MsoNormalCxSpLast&apos; or .=&apos;MsoTableGrid&apos; or .=&apos;MsoListParagraphCxSpFirst&apos; or .=&apos;MsoListParagraphCxSpMiddle&apos; or .=&apos;MsoListParagraphCxSpLast&apos;]" />
  <!--<template match="@align | @valign | @border | @cellpadding | @cellspacing"/>-->  
  <!-- remove all style attributes except those for a table cel to allow center alignment -->
  <!--<template match="*[not(local-name() = &apos;td&apos;)]/@style"/>
  <template match="td/@style">
    <if test="contains(.,&apos;text-align&apos;)">
      <attribute name="style">
        <text>text-align:center;</text>
      </attribute>
    </if>
  </template>-->
  <!-- remove rowspan and collspan when set to 1 -->
  <template match="@colspan[.=&apos;1&apos;] | @rowspan[.=&apos;1&apos;]"/>
</stylesheet>

This works fine except for this match:

<template match="h1">
    <element name="p">
        <apply-templates/>
    </element>
  </template>

Whenever the input is:

<h1>Test</h1>

I expect the following output:

<p>Test</p>

but instead, I'm getting a copy of the full xmlns as an attribute:

<p xmlns="http://www.w3.org/1999/XSL/Transform">Test</p>

From the research I've done so far, it has to do with the <copy> element from the XSLT transformation. How should I modify my filtering XSLT to fix this?

4 Answers 4

5

In order to remove the namespace from the <p> element, all you have to do is apply a blank namespace attribute. The final (correct) filtering XSLT is the same as the original except for this line:

<element name="p" namespace="">

Once I applied this change, I was able to get the correct output:

<p>Test</p>
1
  • Hacky... but I don't know of another solution right now. Nov 15, 2013 at 17:39
4

You may try to put 'exclude-result-prefixes' in stylesheet header. There are so many links with explanation how to do this. I just picked up one as example. https://stackoverflow.com/questions/827600/how-can-i-prevent-these-redundant-namespaces-from-an-xslt-stylesheet

2
  • It didn't work. I tried the following: <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0" exclude-result-prefixes="#default"> and <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0" exclude-result-prefixes="#all"> Nov 15, 2013 at 14:58
  • I never used #all in this attribute - could you try explicitly adding the prefixes instead (separated by spaces)?
    – Nuno Linhares
    Nov 15, 2013 at 18:47
2

With the disclaimer of not having tried it, this is what I suggest:

Declare an xhtml namespace in your stylesheet:

xmlns:xhtml="http://www.w3.org/1999/xhtml"

Declare to exclude namespace prefix xhtml from result:

exclude-result-prefixes="xhtml"

Finally, create your p element belonging to the xhtml namespace:

<element name="p" namespace="xhtml">
2
  • When applying this fix, the output is now <p xmlns="xhtml">Test</p>. Although not quite right, this has now led me to the solution. All you have to do is apply a blank namespace to the element: <element name="p" namespace="">. Thank you. Nov 15, 2013 at 16:27
  • I noticed that Tridion strips the namespace prefix declaration from the 'stylesheet' element when saving the Schema. This is why you end up with the xmlns attribute in your 'p' tag. Nov 15, 2013 at 17:39
0

My philosophy for XSLT transforms is to think about the problem from a different perspective. Don't think about what you want to remove, but rather what you want to allow.

https://tridionation.com/remove-unwanted-markup-with-xslt-filter-templates/

I developed this to allow users to copy-paste from Word.

In this approach, the filter removes all markup and only passes the text nodes.

We then add filters to add in only the Html elements and attributes we want.

Finally, we convert legacy Html elements by creating new elements and applying the templates to copy the contents.

This verbose style of templating is easier to understand and manage yet it does not impact the performance of the XSLT transform.

<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>

 <!-- 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 -->
 <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 -->
 <!--  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>

</xsl:stylesheet>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.