views:

413

answers:

2

.NET XSLT engine allows passing objects to the XSLT processing engine through the AddExtensionObject method.

Can someone comment on the performance of using this to retrieve localized strings to be used in the XSLT?

+2  A: 

To be honest, I wouldn't worry about it - it should be more than sufficient. I use an extension object to do things like regex-replace and other complex string manipulations (not always simple in xslt) and it works a treat.

If you are only doing a few global strings, then you could also use template-level parameters (rather than an extension); but if you have lots to look up (or they are dynamic), then an extension object makes pretty good sense.

If possible, use XslCompiledTransform, which will improve performance (and certainly, a C# method in an extension method will out-perform a <script> method in the xslt). Other than that, if you have a bottle-neck, it is most-likely things like not using xsl-indexes correctly, Muenchian-grouping, etc.

Marc Gravell
+2  A: 

Extension objects can be used to improve performance if a part of an XSLT transformation is deemed inefficient.

While the use of methods of an extension method would not decrease performance (excluding buggy and inefficient code), they will not improve performance significantly, if proper XSLT techniques are being used for accessing localized strings.

In case extension objects are not desperately needed, it is always good to create a pure XSLT solution. This provides the added benefit of portability to any platform, which provides a compliant XSLT processor.

One could place all localized strings for a given language in a separate XML file. This file will be accessed using the XSLT document() function. Each string will be indexed by its @msgId attribute using an index build by the <xsl:key> instruction. Within the transformation an individual message will be fetched with the XSLT key() function.

Below is a small code example, showing how to retrieve a message by msgId and Languge-code from an xml file, where messages for all languages are stored. For convenience we have put the messages inside the XSLT stylesheet itself. In practice, the messages can be in a separate XML file:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output method="text"/>
 <xsl:key name="kMsgByLangAndId" match="msg"
      use="concat(../@name, @msgId)"/>
 <xsl:param name="pLang" select="'De'"/>
 <xsl:param name="pTime" select="19"/>
 <xsl:variable name="vMsgEn">
  <msg msgId="MornGreet">Good morning.</msg>
  <msg msgId="AftnGreet">Good afternoon.</msg>
  <msg msgId="EvnGreet">Good evening.</msg>
 </xsl:variable>
 <xsl:variable name="vMsgDe">
  <msg msgId="MornGreet">Guten morgen.</msg>
  <msg msgId="AftnGreet">Guten tag.</msg>
  <msg msgId="EvnGreet">Guten abend.</msg>
 </xsl:variable>
    <xsl:template match="/">
      <xsl:variable name="vLangVarName"
           select="concat('vMsg', $pLang)"/>
    <xsl:variable name="vMsgId">
      <xsl:choose>
       <xsl:when test="not($pTime >= 12)">MornGreet</xsl:when>
       <xsl:when test="not($pTime >= 18)">AftnGreet</xsl:when>
       <xsl:otherwise>EvnGreet</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
   <xsl:for-each select="document('')">
    <xsl:value-of select=
      "key('kMsgByLangAndId',
            concat($vLangVarName,$vMsgId)
            )"/>
   </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

When this transformation is applied on any source XML document (ignored), the wanted result is produced:

Guten abend.

Dimitre Novatchev