In this article, we present several best practice patterns that must be applied when working with XSLT in a censhare system. Several bad and good practices examples are illustrated, justifying how each example affects censhare’s performance.

Functions for asset queries

The listed XPath functions are used to execute basic asset queries:

  • cs:asset
  • cs:get-asset-versions
  • cs:parent-rel
  • cs:child-rel
  • cs:any-rel
  • cs:order-by
  • cs:feature-ref
  • cs:feature-ref-reverse

The result of an asset query is an iterator object. This is indicated in the “Expression Evaluator Test” window with a generic result as seen in the screenshot below.
evalExpression

Handling results

  • This transformation reads all asset XMLs of the query and stores them in the variable “result” (all asset XMLs are in memory):

    < xsl:variable name = "result" select = "cs:asset()[@censhare:asset.type='picture.']" />
       < xsl:for-each select = "result" >
        < xsl:value-of select = "@name" />
    </ xsl:for-each >

  • This transformation reads one asset XML after another:

    < xsl:for-each select = "cs:asset()[@censhare:asset.type='picture.']" >
       < xsl:value-of select = "@name" />
    </ xsl:for-each >

The second transformation is much faster and uses less memory because only the currently read asset XML is in memory.

Sorting

  • This transformation sorts the results of a query inside the XSLT:

    < xsl:for-each select = "cs:asset()[@censhare:asset.type='picture.']" >
       < xsl:sort select = "@name" />
       < xsl:value-of select = "@name" />
    </ xsl:for-each >

  • This transformation uses the sorting of the censhare database:

    < xsl:for-each select = "cs:asset()[@censhare:asset.type='picture.’]/cs:order-by()[@censhare:asset.name]" >
       < xsl:value-of select = "@name" />
    </ xsl:for-each >

The latter transformation performs much faster because the sorting can be done in the censhare database. Furthermore, it uses less memory because a sorting in XSLT requires the resulted asset XMLs to stay in memory.

Query in SQL database (Oracle or PostgreSQL)

The parameter “sql=true” specifies that the query must be executed in the SQL database instead of the censhare
database:

< xsl:for-each select = "cs:asset('sql=true')[@censhare:asset.type='picture.’]" >
  < xsl:value-of select = "@name" />
</ xsl:for-each >

Get the number of assets for asset queries

  • Get the number of assets with asset type ‘picture.’. (Not the recommended way)

    <xsl:variable name="count" select="count(cs:asset()[@censhare:asset.type='picture.'])"

    This statement is very expensive because “cs:asset” returns all XMLs of all found assets and “count” is counting the “asset” elements.

    Instead, use the following special count query functions. They calculate the number of assets directly from the censhare database. No asset XML is loaded. This results in a much faster performance.

  • Count for assets:

    <xsl:variable name="count" select="cs:count-assets()[@censhare:asset.type='picture.'])"

  • Count for resource assets:

    <xsl:variable name="count" select="cs:count-resource-assets()[@censhare:asset.type='module.config.'])"

Filtering the first result from a list of elements

  • XPath predicated are filters and evaluate all nodes. If $element is a list of 100,000 elements, then this statement scans all elements and returns the matching ones:

<xsl:variable name="test" select="$elements[@id='35']"

  • This is optimized in censhare 2019.2. The filter “1” stops scanning if a first result is found:

<xsl:variable name="test" select="$elements[@id='35'][1]"

Use “1” when you only require the first result. It is much faster because it does not scan the full list of elements.

  • No labels