Documentation Center

How to hide content using XSL parameters

You can hide parts of the content in large documents to speed up your editor.

When working with large documents Content Editor may become slow. One option is to hide part of the content through the use of an XSL parameter.

Dealing with a slow editor

Content Editor transforms the loaded XML file to HTML for display in the browser using XSL. Content Editor adds events and id's to the HTML to be able to 'listen' to editing actions. Content Editor translates these actions to the XML and whenever an action occurs Content Editor will trigger the XSL again.

Content Editor will then compare the old HTML to the new HTML and update the differences. This is a bottleneck in Content Editor . A large XML file will cause a lot of HTML and comparing all that HTML will slow the XML editor down.

Defining a "large document"

An XML document of around 250 kb will render as about 750 kb of HTML on average. We find 250 kb to be the size at which Content Editor will start to slow down. Browser JavaScript execution speed can mitigate this slowness a lot. Browsers like Firefox 9 and Chrome perform very well with larger documents. Internet Explorer has comparatively slow JavaScript execution time but a faster XSL engine.

Using XSL to speed up the rendering

Content Editor will be faster when the HTML output of the XSL is smaller. There are two ways to make the HTML output of the XSL smaller:

  • Load a smaller XML file
  • Output less from the XSL, despite the large input

Option one is obvious. Most large documents have chapters, parts or sections and therefore can be rendered as a table of contents. Using this table of contents you can load smaller sections of a document into Content Editor . Because you are no longer transforming the whole XML to HTML in Content Editor , it will be much easier to work with for Content Editor .

Option two is a little sneakier. You can still let Content Editor load the whole XML file, but use the XSL to render both the table of contents and the smaller section that you want to edit. This way the HTML output is much smaller and therefore more manageable.

Using a parameter

As an example we will look at the following XML document:

<document>
  <chapter id="A"/>
  <chapter id="B"/>
  <chapter id="C"/>
  <chapter id="D"/>
  <chapter id="E"/>
</document>

Let's assume that this document's chapters are very big and that we only want to render one chapter at a time. We can do this with a parameter in the XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:param name="showChapter" select="'A'"/>

  <xsl:template match="chapter">
    <xsl:choose>
      <xsl:when test="@id = $showChapter">
        <!-- render chapter -->
        <div>
          <xsl:apply-templates select="node()"/>
        </div>
      </xsl:when>
      <xsl:otherwise>
        <!-- don't render chapter -->
      </xsl:otherwise>     
    </xsl:choose>
  </xsl:choose> 
...

As you can see from the above XSL, only when the chapter/id attribute matches the value of the showChapter parameter will the chapter be rendered. A nice way to allow the other chapters to be 'selectable', is to do the following:

...
<xsl:otherwise>
  <!-- don't render chapter, but render the title, and make it clickable -->
  <a href="#"
     onclick="Editor.getActiveCanvas().setViewParam('showChapter', '{@id}');">
     <xsl:apply-templates select="title"/>
  </a>
</xsl:otherwise>
...

Now the rendering will show one complete chapter, and the titles of the other chapter. These titles will be clickable as links, and when clicked will set the value of the parameter to the id attribute of the current chapter.

This is the main idea for using a parameter to render only a part of a document. It involves making the XSL 'smarter' and more interactive. Please note that this does make the XSL less usable outside Content Editor .

Other XML and more browser differences

Not all XML will have id attributes. This is why for a long time we simple passed the node itself to the parameter and used the XSL generate-id() function to test the node as the active one:

<xsl:param name="showChapter" select="//chapter[1]"/>

<xsl:template match="chapter">
  <xsl:choose>
    <xsl:when test="generate-id(.) = generate-id($showChapter)">
      ...

The example compares the current node "." to the showChapter parameter through the use of the generate-id() function. It is also possible to set the node as the parameter in the onclick:

<a href="#" onclick="Editor.getActiveCanvas().setViewParam('showChapter', node);">
  ...

The node argument that you can see being passed to the parameter will always refer to the node from the xsl:template match statement. This node can be used to access the API: it is an XopusNode. The above functionality works fine in Internet Explorer as well as Firefox. Chrome however does not support the passing of nodes as parameter values. To create an XSL that works in all three browsers, we fall back to comparing a id value, but this time we use the ids as assigned by Content Editor .

<xsl:template name="getId">
  <xsl:variable name="id" select="substring-before(following::processing-instruction('xopus-node')[1], '*')" />
  <xsl:choose>
    <xsl:when test="starts-with($id, '+')">
      <xsl:value-of select="substring-after($id, '+')" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$id" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The above template returns an id that can be used for our tests. It should be added to your XSL. It is used in the following:

<xsl:param name="showChapter" select="''"/>

<xsl:template match="chapter">
  <xsl:variable name="id"><xsl:call-template name="getId" /></xsl:variable>
  <xsl:choose>
    <xsl:when test="$id = $showChapter">
      ...
<a href="#" onclick="Editor.getActiveCanvas().setViewParam('showChapter', '{$id}');">
  ...