1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
<html>
<head>
<title>Optimizing Stylesheets</title>
<style>
.comment {
font-style: italic;
}
</style>
</head>
<body>
<h1>Optimizing Stylesheets</h1>
<h2>Overview</h2>
<p>
This document outlines optimizations that we can perform on
stylesheets after a stylesheet is compiled, but before it is executed.
</p>
<h2>Create AVTs out of xsl:attributes</h2>
<p>
People often write stylesheets like
<pre>
<LRE>
<xsl:attribute name="foo">
text here
<xsl:value-of select="@bar"/>
</xsl:attribute>
</pre>
This could be optimized into an AVT like
<pre>
<LRE foo="text here{@foo}">
</pre>
This can be done both in templates and in attribute-sets
</p>
<h2>Investigate how RTFs are being used</h2>
<p>
When only the string-value or double-value of an RTF is being used it
is unneccesary to create an entire RTF. Instead we could set up a
string-handler and use the resulting string.
</p>
<p>
Once we have a node-set() function we could also have a special
handler that creates that resulting nodeset rather then
whatever-we-create-once-we-have-real-RTFs. That handler would be set
up when we can determain that a RTF is used only as argument to the
node-set() function.
</p>
<p>
In cases where an RTF is used as parameter in a call to another
template we could do further analysis to see how that parameter is
used in that template. Either by first analyzing how all template
parameters are used in all templates, or by recursivly searching
the called template when we find that a RTF is used as an argument.
</p>
<p>
We will still need a catch-all RTF implementation that is used when
we can't determin how a variable is used, or when it is used in
multiple different ways.
</p>
<h2>Inline/calculate constant variables</h2>
<p>
Variables that does not have a value that depends on the source
document can be inlined into the stylesheet. The value of these
variables could also be calculated before the transformation is
started.
</p>
<p>
This can be combined with the previous optimization of RTFs so that
stylesheets like
<pre>
<xsl:variable name="v">_</xsl:variable>
...
<xsl:value-of select="concat(@id, $v, foo)"/>
</pre>
is executed like
<pre>
<xsl:value-of select="concat(@id, '_', foo)"/>
</pre>
<p>
<p>
This can be done for both global and local variables.
</p>
<h2>Resolve cross-references</h2>
<p>
Cross-references to named templates, attribute-sets and template-modes
can be resolved before the stylesheet is executed. That way we don't
have to search for the template/attribute-set with a certain name, or
the group of templates for a certain mode.
</p>
<p>
Note that for apply-imports we won't always know at compile-time which
mode to seach for templates in.
</p>
<h2>Resolve variables by index rather then expanded name</h2>
<p>
Rather then seaching for variables with a certain name at runtime
we could remove names for variables/parameters entierly and put all
variables in an array (possibly a separate array for global variables)
and then let variable-references in expressions just point to an index
in that array.
</p>
<h2>Calculate and use constant AVTs</h2>
<p>
A lot of instruction-elements uses AVTs that often are constants in
stylesheets, such as the data-type parameter to xsl:sort. For xsl:sort
we could pre-create a finished nodesorter if all AVTs in all
xsl:sort-elements are constant.
</p>
<p>
Another example is xsl:element and xsl:attribute where we could use
LRE-instructions if the AVTs are constant. For xsl:number we could
create prepare the list of <code>txFormattedCounter</code>s.
</p>
<h2>Reuse parameter-map if exact same parameters are used</h2>
<p>
If a template calls another template and uses the exact same
parameters we can reuse the same parameter-map.
<pre>
<xsl:template name="hsbc_html_body">
<xsl:param name="appName"/>
<xsl:param name="title"/>
<body>
<xsl:call-template name="hsbc_form">
<xsl:with-param name="appName" select="$appName"/>
<xsl:with-param name="title" select="$title"/>
</xsl:call-template>
</body>
</xsl:template>
</pre>
</p>
<p>
We have to watch out for default parameter-values as well as
parameters being specified by the caller of this template but not used
by this template. I.e. if the parameter "hello" is specified when
calling the above template.
</p>
<p class="comment">
All this might make this optimization useless.
</p>
<h2>Combind consecutive LRE items into a txResultBuffer</h2>
<p>
When a template contains several consecutive "LRE instructions" such
as LRE-elements, LRE-attributes and textnodes we can replace their
instructions with a special instruction that contains a
<code>txResultBuffer</code>. This buffer would then be flushed when
the instruction is executed. This can of course not be done for
LRE-attributes that contains AVTs. Even PI and comment-instructions
can be included in this buffer if their contents is strictly literal.
</p>
<p>
The result is that a template like
<pre>
<xsl:template match="/">
<html>
<body bgcolor="green">
Here goes pagecontent
<xsl:apply-templates />
</body>
</html>
</xsl:template>
</pre>
Would result in the first <code>txResultBuffer</code> to contain the
following transactions: eStartElementTransaction,
eStartElementTransaction, eAttributeTransaction, eCharacterTransaction.
</p>
<p class="comment">
There is probably a lower limit to when it's worth the effort to
replace the normal instructions with the buffer-instruction. A single
"LRE instruction" is probobably better kept as a normal instruction.
</p>
</body>
</html>
|