<?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0"
  xmlns:ent="http://www.purl.org/NET/ENT/1.0/"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
  <title>Saxon diaries</title>
  <link>http://saxonica.blogharbor.com/blog</link>
  <description></description>
  <language>en-us</language>
  <lastBuildDate>Fri, 25 Apr 2008 23:24:49 +0100</lastBuildDate>
  <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
  <generator>Blogware</generator>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>XQuery Update and Node Identity</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2008/2/14/3523047.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2008/2/14/3523047.html</guid>
    <pubDate>Thu, 14 Feb 2008 10:36:45 +0000</pubDate>
    <description>An interesting little spat on the XQuery internal mailing list over the last couple of days on the question of whether or not XQuery Update guarantees to preserve node identity. The spec says that it does. Someone remarked during a telcon that there were difficulties meeting this requirement in a SQL/XML environment. After the meeting I sent an email claiming that the assertion in the spec that updates preserve node identity is untestable and therefore ought to be removed.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Further progress on XQuery Update</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2008/1/2/3442989.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2008/1/2/3442989.html</guid>
    <pubDate>Wed, 02 Jan 2008 14:15:13 +0000</pubDate>
    <description>I&#39;ve no got to the point where my XQuery Update implementation is passing almost all the published tests. That doesn&#39;t mean its complete, because the test suite doesn&#39;t cover certain areas, such as revalidation of updated documents. But it&#39;s looking good.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Progress on XQuery Update</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/12/19/3419605.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/12/19/3419605.html</guid>
    <pubDate>Wed, 19 Dec 2007 19:03:48 +0000</pubDate>
    <description>A progress report on the state of the XQuery Update implementation in Saxon, in particular, a list of things still to be done and some thoughts on how they might be tackled.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Implementing XQuery Update</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/12/11/3403913.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/12/11/3403913.html</guid>
    <pubDate>Tue, 11 Dec 2007 18:00:30 +0000</pubDate>
    <description>I&#39;ve been asked a number of times whether I planned to implement XQuery Updates, and my answer has always been that I would do it when the time was right (i.e. when the spec seemed to be stable enough and when I had a suitable gap in my hectic schedule)...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Final Draft of XQJ</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/11/21/3367880.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/11/21/3367880.html</guid>
    <pubDate>Wed, 21 Nov 2007 16:29:45 +0000</pubDate>
    <description>A &quot;Final Draft&quot; of XQJ has been published (http://jcp.org/en/jsr/detail?id=225). There aren&#39;t many changes, but this time the specification is accompanied by actual interface definitions, and by a test suite.

Swapping in the published interface definitions for my previous handmade versions proved no trouble - one or two discrepancies as regards which methods throw exceptions, and one or two methods that have had an extra argument added.

Running the test suite is likely to be a bit more effort....</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Transforming 20 Gigabytes</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/9/25/3252121.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/9/25/3252121.html</guid>
    <pubDate>Tue, 25 Sep 2007 13:20:28 +0100</pubDate>
    <description>My heart sank when I received an email yesterday from a Saxonica customer reporting a failure when running a transformation on a 20Gb source file (using the &quot;streaming&quot; capabilities described at http://www.saxonica.com/documentation/sourcedocs/serial.html.) It was apparently failing half way through with no error message of any kind. How do you go about debugging such a problem, especially when you&#39;re in a different continent from the client?</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Document Projection</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/8/25/3183053.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/8/25/3183053.html</guid>
    <pubDate>Sat, 25 Aug 2007 10:34:13 +0100</pubDate>
    <description>Document Projection [1] is a technique invented by Amélie Marian and Jérôme Siméon designed to reduce the amount of memory occupied by a source document used by a query or transformation. The idea is to analyze the query and determine what nodes it is capable of accessing, and then while parsing and building the document, to filter out all those nodes that the query can never access. I decided to have a go at implementing this in Saxon...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>A new XQJ draft</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/6/13/3019935.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/6/13/3019935.html</guid>
    <pubDate>Wed, 13 Jun 2007 22:54:32 +0100</pubDate>
    <description>XQJ is the proposed XQuery API for Java. A new draft of the XQJ specifications came out yesterday, with the psychologically significant version number of 0.9, and I spent today updating Saxon&#39;s implementation to conform. The spec can be downloaded from http://jcp.org/en/jsr/detail?id=225 ....</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Path Expressions Revisited</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/4/27/2908908.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/4/27/2908908.html</guid>
    <pubDate>Fri, 27 Apr 2007 15:01:39 +0100</pubDate>
    <description>The core of XSLT and XQuery performance is the ability to evaluate simple path expressions efficiently. This area of Saxon has been untouched for some time, and I tend to assume it has been tuned to death. But I&#39;ve always had a nagging feeling that the machinery created for evaluating a multi-step path expression might have room for improvement....</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Saxon vs Xalan Performance; and DOM</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/3/31/2848654.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/3/31/2848654.html</guid>
    <pubDate>Sat, 31 Mar 2007 17:15:42 +0100</pubDate>
    <description>I had an email from a customer the other day that started &quot;It is quite unusual for Saxon&#39;s performance to be worse than Xalan&#39;s&quot;. It turned out to be an XSLT stylesheet that was taking around 3950ms under Saxon, and just 1370ms under Xalan. A quick look at the application showed that it was using a DOMSource and a DOMResult. I changed that to use a Saxon TinyTree for both the source and result (which only involved changing a couple of lines of code) and the Saxon timings came down to about 400ms. Pride restored...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Assertions in XML Schema</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/3/6/2784345.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/3/6/2784345.html</guid>
    <pubDate>Tue, 06 Mar 2007 13:09:13 +0000</pubDate>
    <description>I&#39;ve been implementing the new facility in XML Schema 1.1 for defining assertions, in terms of XPath expressions. It&#39;s a great feature. You could do something similar before, of course, using Schematron - but no-one really wants to do to separate validations using very different technologies. The new xs:assert clause makes it all much more seamless. As one might expect in a first draft though, there are glitches in the spec.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Unexpected flattery</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/2/3/2706238.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/2/3/2706238.html</guid>
    <pubDate>Sat, 03 Feb 2007 17:46:26 +0000</pubDate>
    <description>There was an unexpected compliment for Saxon on Thursday in an announcement of a new release of Per Bothner&#39;s Qexo implementation of XQuery. He slipped in the remark: &quot;some tests are significantly faster than Saxon&quot;. More evidence that our competitors regard Saxon as the product they need to beat, and at the same time an admission that for most tests, Saxon runs faster than this particular engine...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>How not to fold constants</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/1/20/2665644.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/1/20/2665644.html</guid>
    <pubDate>Sat, 20 Jan 2007 00:04:03 +0000</pubDate>
    <description>I&#39;m back to work on the Java code-generation for XQuery. The challenge is to improve the test coverage. With 14000 tests in the W3C test suite, one would think the coverage would be pretty good; but the problem is that many of the tests use literal constants, which means the whole query can be evaluated statically by the XQuery analyzer, before the code generator gets a look in. Early evaluation of expressions at compile time is known rather quaintly in the compiler literature as &quot;constant folding&quot;. We should be able to improve the coverage of the code generator testing simply by not doing constant folding....</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>XML Schema Tests: progress report</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2007/1/3/2617585.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2007/1/3/2617585.html</guid>
    <pubDate>Wed, 03 Jan 2007 18:19:51 +0000</pubDate>
    <description>As reported in my previous posting, I&#39;ve been working on the new XML Schema Test suite. Achieved a significant milestone today: all the tests in the Microsoft part of the test suite are now &quot;done&quot;. That&#39;s around 14600 tests. Of these I have queried the results of 858 tests (you can find the bug reports in the W3C public bugzilla). Most of these are illegal regular expressions in supposedly valid schemas. Of the remainder, Saxon fails on 22 tests for known reasons, and passes on the remainder. &lt;br&gt;&lt;br&gt;The failures are essentially for three reasons: (a) hitting resource limits on large minOccurs/maxOccurs values; (b) Saxon has a better algorithm for testing type subsumption than the one in the spec (it&#39;s essentially anticipating the XML Schema 1.1 spec here), and (c) there are three tests in which a user-defined type is derived directly from xs:anySimpleType, and although the spec appears to allow this, it&#39;s not at all clear what it&#39;s supposed to mean, so Saxon disallows it.&lt;br&gt;&lt;br&gt;I had to fix quite a large number of Saxon bugs to get to this point, but they were almost all very obscure corner cases.&lt;br&gt;&lt;br&gt;Next step is to tackle the Sun and NIST tests. On past experience these will be easier.&lt;br&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>New W3C XML Schema Test Suite</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/12/14/2573096.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/12/14/2573096.html</guid>
    <pubDate>Thu, 14 Dec 2006 16:02:34 +0000</pubDate>
    <description>A few weeks ago the W3C Schema working group published a new test suite, containing nearly 40,000 tests. Since then, I&#39;ve been putting a fair amount of effort into reconciling Saxon&#39;s results on these tests with the published results.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Compiling Q10</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/11/8/2482675.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/11/8/2482675.html</guid>
    <pubDate>Wed, 08 Nov 2006 11:05:24 +0000</pubDate>
    <description>The last remaining query in the XMark benchmark where the compiled code was running significantly slower than the interpreted code was Q10.... 

Inlining of variables eliminates the tree copy operation, which improves the performance from 301ms to 104ms.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>First compiled XMark results</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/11/6/2477675.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/11/6/2477675.html</guid>
    <pubDate>Mon, 06 Nov 2006 18:34:09 +0000</pubDate>
    <description>The code to compile XQuery into Java has now advanced sufficiently that I can run all the XMark benchmark queries, producing correct results, and reproducing the Saxon-SA join optimizations. First results are shown below: there&#39;s clearly room for further work in some areas, but overall it&#39;s an encouraging milestone. All timings in milliseconds...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Altova Mudslinging</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/10/28/2454935.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/10/28/2454935.html</guid>
    <pubDate>Sat, 28 Oct 2006 18:32:57 +0100</pubDate>
    <description>A number of users have written to me suggesting that I respond to Altova&#39;s latest customer newsletter in which they make the rather suprising claim that their XSLT processor is three times faster than Saxon. At least they had the decency to describe how they measured it - by running a thousand or so conformance tests from the W3C test suite using a batch script in which each transformation was run individually from the command line. Any reasonably competent user knows that that&#39;s a hopelessly inefficient way of running Java programs...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Progress on XQuery compilation</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/10/24/2442067.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/10/24/2442067.html</guid>
    <pubDate>Tue, 24 Oct 2006 08:26:52 +0100</pubDate>
    <description>A progress report: I&#39;m now within a whisker of being able to compile the whole of the XQuery Test Suite into Java code. One or two negative tests generate code that won&#39;t compile, but the problems are minor. So far, however, I&#39;ve only actually executed a very small sample of the tests. The next stages, which will overlap to some extent, are (a) to get the generated code working correctly, (b) to make sure it performs (which includes generating code for some of the optimizations currently done dynamically by the interpreter), (c) general clean-up: there&#39;s a lot of repetitive code that was generated by cut-and-paste, and therefore many opportunities for refactoring, and I don&#39;t want to be fixing the same bug in a dozen places, (d) removing restrictions in the current implementation, for example there&#39;s no support currently for extension functions, (e) diagnostics, especially the quality of run-time error reporting and tracing, and (f) packaging, for example defining the interfaces to control the compilation process. That&#39;s a fair bit of work still to do, even though the bulk of the code may now have been written.&lt;br&gt;&lt;br&gt;An interesting problem emerged in using the XQTS tests: a very large number of them contain expressions that are actually evaluated at compile time during the constant-folding process. To get reasonable coverage for the Java code geenrator I therefore had to suppress such constant-folding operations, which I basically achieved by wrapping string and numeric literals in an artificial function call. This in turn generated some very obscure expressions which in one or two cases broke the existing interpreter! It also turns out there are a few features missing from the test suite, some of which are quite tricky: not only things that are intrinsically non-portable like extension functions and dynamically-selected collation URIs, but also rarely-used but well-defined constructs like X/position() and X/last().&lt;br&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Choosing Java class names</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/10/6/2391810.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/10/6/2391810.html</guid>
    <pubDate>Fri, 06 Oct 2006 12:05:32 +0100</pubDate>
    <description>Years ago, I took some childish pleasure in naming the class that does whitespace-stripping in Saxon &quot;Stripper.java&quot;.&lt;br&gt;&lt;br&gt;Guess what? The second-most popular entry point to the Saxonica web site from Google is &lt;span id=&quot;lblViewedOnceSummary&quot;&gt;&lt;font class=&quot;SummaryItemText&quot;&gt;.../javadoc/net/sf/saxon/event/stripper.html&lt;br&gt;&lt;br&gt;The punters must be very disappointed. I wonder how much I&#39;m paying for the wasted bandwidth?&lt;br&gt;&lt;br&gt;It&#39;s one way to boost my google rankings, I suppose.&lt;br&gt;&lt;/font&gt;&lt;/span&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Still Compiling the Knight&#39;s Tour</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/10/3/2383818.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/10/3/2383818.html</guid>
    <pubDate>Tue, 03 Oct 2006 19:30:53 +0100</pubDate>
    <description>I wrote on 20 September that I was getting the compiled Knight&#39;s Tour stylesheet to run in 39.3 ms, compared with 45.9 ms for the interpreted code, and that I didn&#39;t think it would be hard to improve on this. Well, it&#39;s now down to 9.41 ms. (Thie compares with the figure of 900 ms given in my book, for an earlier version of Saxon and a previous laptop.) But a lot depends on what you mean by &quot;hard&quot;...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Compiling the Knight&#39;s Tour</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/9/20/2345702.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/9/20/2345702.html</guid>
    <pubDate>Wed, 20 Sep 2006 22:15:46 +0100</pubDate>
    <description>A progress report on query compilation: I&#39;ve now got to the point where I can compile the knight&#39;s tour query (tour.xq in the Saxon samples distribution) into Java code, and execute it with correct results. It&#39;s running in 39.3ms, compared with 45.9ms for the interpreted code, which isn&#39;t wildly exciting, but there&#39;s enormous scope for tuning the generated code and it shouldn&#39;t be hard to improve on this figure very significantly.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>More experiments with compilation</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/9/15/2329784.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/9/15/2329784.html</guid>
    <pubDate>Fri, 15 Sep 2006 16:25:34 +0100</pubDate>
    <description>A couple of months ago (see &lt;a href=&quot;http://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html&quot;&gt;http://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html&lt;/a&gt;), I reported on some experiments with compiling path expressions into Java code. The results were not enormously encouraging, but I&#39;ve been taking the idea forward, on a slighly different front.&lt;br&gt;&lt;br&gt;This time round, rather than compiling the low-level code for navigating a TinyTree, I&#39;m compiling the higher level logic for evaluating path expressions, FLOWR expressions, and the like. I&#39;ve done enough work to compile the whole of the XMark XQuery benchmark into Java code, with the exception of one query (Q18) that uses a user-defined function. The code generation is not particularly smart at the moment - in particular, it&#39;s always doing eager evaluation of expressions - but nevertheless, the speed of some of the queries has doubled. The bad news is that others are slower; but this is early days.&lt;br&gt;&lt;br&gt;This is a bigger pilot than the previous experiment I reported, in that I&#39;ve written code to compile about 50 of the expression classes generated by the Saxon parser and optimizer. That&#39;s about a fifth of the total, so there&#39;s a long way to go. The next stage is to put in some of the fundamentals like function calling and lazy evaluation, and convince myself that the performance gains make it worth doing. After that there&#39;s a long slog to get full coverage of the XSLT and XQuery languages, and to test everything. The testing won&#39;t be easy, because although there are now large XQuery and XSLT test suites around, many of the expressions they contain are compile-time constants.&lt;br&gt;&lt;br&gt;Compiling to Java seems a sensible choice at the moment. Going straight to bytecode would be a lot more effort, and would introduce a high risk of bugs; and the extra benefit seems marginal. One unexpected benefit is that the generated Java gives a very clear view of the execution strategy for the query, which makes it much easier to spot opportunities for improving the optimizer.&lt;br&gt;&lt;br&gt;There are some basic limitations in the approach. There&#39;s no saving in the time or memory used to build the source document. The generated Java code still calls the same iterators to navigate the axes over the source document, and the same serialization methods to produce the output. Together, those run-time routines account for a large part of the query cost, which isn&#39;t going to come down. But there&#39;s always scope for moving more code into the compiled part as opportunities show themselves. I&#39;ll set the target as a 50% improvement in execution time, but I think that&#39;s probably a stretch.&lt;br&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Zounds! I was never so bethump&#39;d with words</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/8/13/2226871.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/8/13/2226871.html</guid>
    <pubDate>Sun, 13 Aug 2006 16:41:36 +0100</pubDate>
    <description>Saxon is implementing Unicode codepoint collation simply by doing a Java string compare, and this is incorrect in the case of strings containing characters whose Unicode codepoint value is greater than 65535. This kind of bug is irritating, because hardly anyone is going to be affected by it, yet fixing it will impose a cost on everyone because string comparison will be slower.</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Tail recursive functions</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/8/1/2187040.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/8/1/2187040.html</guid>
    <pubDate>Tue, 01 Aug 2006 22:55:25 +0100</pubDate>
    <description>I made some minor changes to the details of expression evaluation a few days ago, and found that this broke the code for optimizing tail calls in recursive functions. Since that code has a nasty habit of breaking when I make small changes in this area, I decided that it was time for an overhaul...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Tuning the Chess-FO stylesheet</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/7/27/2167746.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/7/27/2167746.html</guid>
    <pubDate>Thu, 27 Jul 2006 13:22:48 +0100</pubDate>
    <description>In an interesting &lt;a href=&quot;https://blogs.msdn.com/antosha/archive/2006/07/24/677560.aspx#679926&quot;&gt;post&lt;/a&gt; (at least partly influenced by my &lt;a href=&quot;http://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html&quot;&gt;compilation experiments&lt;/a&gt;) Anton Lapounov has published some Saxon performance measurements for a number of 1.0 stylesheets. I&#39;m intrigued that I get faster performance for Saxon 8.7.3 than for 6.5.5, whereas he gets the opposite. I decided to look into the performance of one of these stylesheets a bit more closely and see how it can be improved. The one I chose is the &lt;a href=&quot;http://www.renderx.com/chess.html&quot;&gt;Chess-FO&lt;/a&gt; stylesheet which takes as input the record of moves in a chess game and produces as output an XSL-FO document showing the successive positions.&lt;br&gt;&lt;br&gt;Firstly, it&#39;s clear just from looking at the source code that evaluating path expressions doesn&#39;t play much of a role in this code. It&#39;s spending most of its time constructing output. There are a fair number of template calls, some of them tail-recursive. The ratio of output size to input size (377Kb from 3Kb) is unusually large, so we should expect that the cost of creating elements and serializing them will dominate.&lt;br&gt;&lt;br&gt;I started by seeing how far I could improve the performance simply by tuning the XSLT code as written. The baseline execution time was 301ms (in this, and all subsequent figures, I&#39;m reporting the second-best out of nine runs, running from the command line with the -9 option to run the transformation nine times, and the -t option to output the results. &lt;br&gt;&lt;br&gt;First I modified the stylesheet to say version=&quot;2.0&quot;, and put in a couple of explicit type conversions in places where the code had been implicitly converting between strings and numbers. Time now 280ms.&lt;br&gt;&lt;br&gt;My next move was to profile the stylesheet execution using the -TP option on the command line. This generates a trace file with timing information, which can be analyzed using the timing-profile.xsl stylesheet (in the samples/analysis directory of the Saxon distribution). This showed one template dominating the execution time: template &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;render-chessboard-cell&lt;/span&gt;&lt;/font&gt;. So I focused my efforts on this template, which reads:&lt;br&gt;&lt;br&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; &amp;lt;xsl:template name=&quot;render-chessboard-cell&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:param name=&quot;col-number&quot; select=&quot;1&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:param name=&quot;row-number&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:param name=&quot;row-content&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;cell-background&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:choose&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:when test=&quot;($col-number mod 2 = 0 and $row-number mod 2 = 0) or&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ($col-number mod 2 != 0 and $row-number mod 2 != 0)&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:value-of select=&quot;&#39;b&#39;&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:when&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:otherwise&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:value-of select=&quot;&#39;w&#39;&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:otherwise&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:choose&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:variable&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;cell-content&quot; select=&quot;substring($row-content, $col-number, 1)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$cell-background = &#39;b&#39;&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:attribute name=&quot;background-color&quot;&amp;gt;#C0C0C0&amp;lt;/xsl:attribute&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$cell-content != &#39;x&#39;&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:call-template name=&quot;piece-image&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;piece-name&quot; select=&quot;$cell-content&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;cell-background&quot; select=&quot;$cell-background&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:call-template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$col-number &amp;amp;lt; 8&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- recurse to the next cell --&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:call-template name=&quot;render-chessboard-cell&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;row-number&quot;&amp;nbsp; select=&quot;$row-number&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;col-number&quot;&amp;nbsp; select=&quot;$col-number + 1&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;row-content&quot; select=&quot;$row-content&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:call-template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 255); font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; &amp;lt;/xsl:template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;I started by declaring types on the parameters and variables, and changing xsl:value-of to xsl:sequence (no need to create a text node when you only want a string). Time now down to 210ms.&lt;br&gt;&lt;br&gt;Then I dealt with the recursion in this template, replacing it by an iteration. The call on this template, as written, was:&lt;br&gt;&lt;br&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;3&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&lt;font size=&quot;1&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-row height=&quot;24pt&quot;&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:call-template name=&quot;render-chessboard-cell&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;row-number&quot; select=&quot;$row-number&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;count&quot; select=&quot;1&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;row-content&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:value-of select=&quot;substring($chessboard, $row-number * 8 - 7, 8)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:with-param&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:call-template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;3&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;font size=&quot;1&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-row&amp;gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;The count parameter is noise (it isn&#39;t even declared as a parameter: XSLT 2.0 spots this error). The row-content parameter uses the horribly unnecessary RTF construction: it should simply be written as &lt;br&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;3&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;lt;xsl:with-param name=&quot;row-content&quot; &lt;br&gt;     select=&quot;substring($chessboard, $row-number * 8 - 7, 8)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;
And then we can change it to call the template 8 times using &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;lt;xsl:for-each select=&quot;1 to 8&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;, passing the column number as a parameter. This gave no further time savings, however. Using recursion to do simple iteration is a pain from the usability point of view, but it&#39;s not actually inefficient. But to tidy things up further, I removed the recursion to scan over the rows as well. This time the timing came down a little to 191ms. &lt;br&gt;&lt;br&gt;Then I collapsed the three templates into one, so that the board is printed using two nested for-each loops. Time now down to 130ms!&lt;br&gt;&lt;br&gt;The body of the template is still inefficient: the calculation of the colour of a cell can be simplified, and we don&#39;t need the variable &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;$row-content&lt;/span&gt;&lt;/font&gt;. It&#39;s also passing a parameter &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;cell-background&lt;/span&gt;&lt;/font&gt; to the template &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;piece-image&lt;/span&gt;&lt;/font&gt;, which the called template doesn&#39;t actually use. So the template now looks like this:&lt;br&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;pre&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: rgb(51, 51, 255);&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:for-each select=&quot;1 to 8&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;row-number&quot; as=&quot;xs:integer&quot; select=&quot;.&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;row-content&quot; select=&quot;substring($chessboard, $row-number * 8 - 7, 8)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-row height=&quot;24pt&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:for-each select=&quot;1 to 8&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;col-number&quot; as=&quot;xs:integer&quot; select=&quot;.&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;cell-number&quot; as=&quot;xs:integer&quot; &lt;br&gt;                                  select=&quot;($row-number - 1) * 8 + $col-number&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;cell-content&quot;&amp;nbsp; as=&quot;xs:string&quot; &lt;br&gt;                                      select=&quot;substring($chessboard, $cell-number, 1)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$cell-number mod 2 = 0&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:attribute name=&quot;background-color&quot;&amp;gt;#C0C0C0&amp;lt;/xsl:attribute&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$cell-content != &#39;x&#39;&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:call-template name=&quot;piece-image&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:with-param name=&quot;piece-name&quot; select=&quot;$cell-content&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:call-template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:for-each&amp;gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-row&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:for-each&amp;gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-body&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;No further improvement in performance, though (in fact, this time the second-best time is 140ms, but I&#39;ll put that down to random fluctuation).&lt;br&gt;&lt;br&gt;The next obvious target is the &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;piece-image&lt;/span&gt;&lt;/font&gt; template, which is using a 16-way xsl:choose statement to replace characters such as P, B, or K with a single Unicode character representing the chess piece. This can clearly be done in a single translate() call. &lt;br&gt;&lt;br&gt;I thought this would make a significant difference, but the time is stubbornly sticking at 130ms. Still, that&#39;s down below 40% of the starting figure.&lt;br&gt;&lt;br&gt;Rerunning the profiling, the &lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;render-chessboard&lt;/span&gt;&lt;/font&gt; template is still accounting for 80% of the execution time, so there&#39;s not much point looking anywhere else. There are still a couple of small tweaks we can make: removing variables that are only used once, and expanding them inline, for example. The best time is now down to 110ms: but I said I would use the second-best, and that&#39;s still 130ms. This is probably as good as we are going to get by tuning the stylesheet. The relevant template now looks like this:&lt;br&gt;&lt;br&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; &amp;lt;xsl:template name=&quot;render-chessboard&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:param name=&quot;chessboard&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table width=&quot;192pt&quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; height=&quot;192pt&quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; border=&quot;thin solid black&quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; start-indent=&quot;0.26in&quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end-indent=&quot;0.26in&quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; font=&quot;20pt/0pt Chess&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-column column-width=&quot;24pt&quot; number-columns-repeated=&quot;8&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-body&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:for-each select=&quot;0 to 7&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;row-offset&quot; as=&quot;xs:integer&quot; select=&quot;. * 8&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-row height=&quot;24pt&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:for-each select=&quot;1 to 8&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:variable name=&quot;cell-number&quot; as=&quot;xs:integer&quot; select=&quot;$row-offset + .&quot;/&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:if test=&quot;$cell-number mod 2 = 0&quot;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:attribute name=&quot;background-color&quot;&amp;gt;#C0C0C0&amp;lt;/xsl:attribute&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:if&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsl:value-of select=&quot;translate(substring($chessboard, $cell-number, 1), &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &#39;KQRBNPkqrbnpx&#39;, &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &#39;&amp;amp;#x2654;&amp;amp;#x2655;&amp;amp;#x2656;&amp;amp;#x2657;&amp;amp;#x2658;&amp;amp;#x2659;&amp;amp;#x265A;&amp;amp;#x265B;&amp;amp;#x265C;&amp;amp;#x265D;&amp;amp;#x265E;&amp;amp;#x265F;&#39;)&quot;/&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:block&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:for-each&amp;gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-row&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/xsl:for-each&amp;gt;&amp;nbsp; &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table-body&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fo:table&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(51, 51, 255);&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; &amp;lt;/xsl:template&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br&gt;I expect that the costs are now dominated by constructing and serializing the various FO elements and attributes, which we can&#39;t reduce any further. Let&#39;s run some profiling at the Java level, by adding -Xrunhprof:cpu=samples to the command line. The only sample points which occur more than once are these:&lt;br&gt;&lt;font size=&quot;1&quot;&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;/font&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;CPU SAMPLES BEGIN (total = 185) Thu Jul 27 11:58:26 2006&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;rank&amp;nbsp;&amp;nbsp; self&amp;nbsp; accum&amp;nbsp;&amp;nbsp; count trace method&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 1&amp;nbsp; 8.11%&amp;nbsp; 8.11%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 15 300106 java.lang.ClassLoader.defineClass1&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 2&amp;nbsp; 4.86% 12.97%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 9 300316 java.io.FileOutputStream.close0&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 3&amp;nbsp; 3.24% 16.22%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6 300001 java.lang.ClassLoader.findBootstrapClass&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 4&amp;nbsp; 2.16% 18.38%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4 300311 java.lang.Runtime.gc&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 5&amp;nbsp; 1.62% 20.00%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 300306 net.sf.saxon.functions.Substring.substring&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 6&amp;nbsp; 1.62% 21.62%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 300011 java.util.jar.JarFile.getManifest&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 7&amp;nbsp; 1.08% 22.70%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300214 com.sun.org.apache.xerces.internal.util.XMLChar.&amp;lt;clinit&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 8&amp;nbsp; 1.08% 23.78%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300112 java.lang.Class.forName0&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 9&amp;nbsp; 1.08% 24.86%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300052 sun.misc.FloatingDecimal.&amp;lt;clinit&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 10&amp;nbsp; 1.08% 25.95%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300227 net.sf.saxon.style.StyleElement.processVersionAttribute&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 11&amp;nbsp; 1.08% 27.03%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300257 java.util.AbstractList.iterator&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 12&amp;nbsp; 1.08% 28.11%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300256 net.sf.saxon.pattern.Pattern.make&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 13&amp;nbsp; 1.08% 29.19%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300041 sun.security.provider.Sun$1.run&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 14&amp;nbsp; 1.08% 30.27%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300207 com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 15&amp;nbsp; 1.08% 31.35%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2 300332 java.io.FileOutputStream.open&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;p&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;pre style=&quot;color: rgb(0, 153, 0);&quot;&gt;&lt;font size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;&lt;p&gt;This doesn&#39;t give us much to go on, unfortunately. There&#39;s a fair bit of system overhead loading classes, opening files, and running the garbage collector. The most-sampled bit of Saxon code is the substring function, and that&#39;s followed by the code for parsing XSLT patterns at compile time. With only a couple of hits on each sample point, this data is pretty random: we need a much longer run for the samples to be meaningful. &lt;br&gt;&lt;/p&gt;So I changed the command-line code in my IDE to run the transformation 1000 times, with these results:&lt;br&gt;&lt;br&gt;&lt;font style=&quot;color: rgb(0, 153, 0);&quot; size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 1 49.97% 49.97%&amp;nbsp;&amp;nbsp;&amp;nbsp; 7979 300137 java.net.PlainSocketImpl.socketAccept&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 2&amp;nbsp; 2.12% 52.09%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 339 300289 sun.nio.cs.UTF_8$Encoder.encodeArrayLoop&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 3&amp;nbsp; 1.79% 53.89%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 286 300293 net.sf.saxon.event.XMLEmitter.testCharacters&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 4&amp;nbsp; 1.70% 55.58%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 271 300312 net.sf.saxon.functions.Substring.substring&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 5&amp;nbsp; 1.61% 57.19%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 257 300314 java.io.FileOutputStream.writeBytes&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 6&amp;nbsp; 1.57% 58.76%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 250 300296 net.sf.saxon.value.StringValue.getStringLength&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 7&amp;nbsp; 1.42% 60.18%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 227 300297 net.sf.saxon.value.StringValue.getStringLength&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 8&amp;nbsp; 1.23% 61.41%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 196 300305 java.io.FileOutputStream.open&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp;&amp;nbsp; 9&amp;nbsp; 0.97% 62.38%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 155 300333 java.io.FileOutputStream.close0&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 10&amp;nbsp; 0.96% 63.34%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 154 300304 java.lang.AbstractStringBuilder.append&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 11&amp;nbsp; 0.86% 64.20%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 137 300345 net.sf.saxon.instruct.LocalParam.evaluateVariable&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 12&amp;nbsp; 0.85% 65.05%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 136 300327 net.sf.saxon.om.NamePool.getCodeForPrefix&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 13&amp;nbsp; 0.83% 65.89%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 133 300307 java.lang.StringBuffer.toString&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 14&amp;nbsp; 0.80% 66.68%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 127 300379 net.sf.saxon.expr.Assignation.evaluateVariable&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 15&amp;nbsp; 0.79% 67.47%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 126 300318 java.lang.AbstractStringBuilder.&amp;lt;init&amp;gt;&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 16&amp;nbsp; 0.75% 68.22%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 120 300366 java.io.FileInputStream.open&lt;/span&gt;&lt;br style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&amp;nbsp; 17&amp;nbsp; 0.75% 68.97%&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 120 300468 java.lang.String.&amp;lt;init&amp;gt;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;/font&gt;&lt;font style=&quot;color: rgb(0, 153, 0);&quot; size=&quot;1&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/font&gt;&lt;p&gt;&lt;font size=&quot;3&quot;&gt;I don&#39;t actually know what that dominant call on socketAccept is doing, but I&#39;ll assume it&#39;s an artefact of the CPU sampling and ignore it. Next to that in importance, we have a number of routines concerned with outputting of characters: UTF-8 encoding (I should have mentioned that I changed the output to UTF-8 to see what the effect would be, and there was none noticeable), Saxon&#39;s testCharacters which tests that characters are encodable, and various methods in FileOutputStream. Apart from that there are various methods for string manipulation, and routines for evaluating local variables and parameters.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;I see now why changing to UTF-8 encoding made no difference. The routine testCharacters is still called to test whether every character appearing in an element name is present in the chosen encoding. If the encoding is UTF-8, that&#39;s clearly unnecessary, so there&#39;s something I can fix.&lt;/p&gt;The call on Substring is evaluating the first argument of translate() in the expression&lt;br&gt;&lt;br&gt;&lt;font style=&quot;color: rgb(51, 51, 255);&quot; size=&quot;2&quot;&gt;&lt;span style=&quot;font-family: Courier New,Courier,mono;&quot;&gt;translate(substring($chessboard, $cell-number, 1), &lt;/span&gt;&lt;/font&gt;&lt;br&gt;&lt;br&gt;This is a more expensive call than you might imagine, because Saxon has to scan the string looking for Unicode surrogate pairs, which occupy four bytes rather than the usual two: it&#39;s not possible to simply index into the string. Similarly, translate() itself has to step through the various strings supplied as arguments, rather than indexing into them directly. This suggests an opportunity to mark strings as &quot;safe&quot; once they have been examined and found to contain no characters outside the 2-byte range. However, there&#39;s another clue here: another trace shows that Substring() is calling ItemChecker and CardinalityChecker to perform type checking on one of the arguments. That reminds me that I didn&#39;t declare the type of $chessboard (because I wasn&#39;t sure what type it actually was). Back to the stylesheet, declare the type as xs:string. Second-best time is now 120ms.&lt;br&gt;&lt;br&gt;There are quite a few calls on getDisplayName() in the NamePool, which does string concatenation to construct (prefix + &#39;:&#39; + localname). This is happening in the serializer when writing start tags. There&#39;s scope here to reduce the cost by caching, or by getting the components of the name separately, or perhaps even by storing the display name explicitly in the NamePool rather than reconstructing it on demand. But at user level, perhaps I could reduce the cost by making the FO namespace be the default namespace? Wow: second-best time is now 100ms.&lt;br&gt;&lt;br&gt;I&#39;ll leave it there for now: I&#39;ve cut the execution time to a third, by some pretty simple source-level changes to the stylesheet. It&#39;s encouraging to know that this can be achieved with a stylesheet even when there are no obvious gross inefficiencies in the coding. It does require some exploitation of XSLT 2.0 features, of course. I&#39;ve also identified one or two places where I think Saxon could be tweaked internally. And I hope I&#39;ve given you, dear reader, a demonstration of the methodology I use when tackling performance problems.&lt;br&gt;&lt;br&gt;Saxonica, of course, is always pleased to tackle performance-related consultancy work.&lt;br&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Experiments with Compilation</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html</guid>
    <pubDate>Mon, 24 Jul 2006 18:28:39 +0100</pubDate>
    <description>Some XSLT processors (XSLTC for example) compile stylesheets into Java bytecode (or equivalently, other intermediate codes such as CIL on .NET). I believe the technique is also used by some XQuery processors. Some users assume that a product that compiles to bytecode will be necessarily faster than an interpreter. I&#39;ve tended to argue that high-level optimizations are more important, and that compiling expressions to bytecode might reduce the scope for high-level optimizations, if only by making them more complex to implement and debug.

I set out today to do some experiments....</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Streaming Mode on large documents</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/7/4/2084120.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/7/4/2084120.html</guid>
    <pubDate>Tue, 04 Jul 2006 18:42:41 +0100</pubDate>
    <description>Coincidentally, the day after my successful efforts to get the XStream benchmark running using the Saxon-SA streaming mode for large documents, (see previous post) a Saxon-SA customer sent me a problem: they needed to transform a 450 Mb file and wanted to know whether this facility would crack the problem. The answer, sadly, was no...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>Push and Pull</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/7/3/2081659.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/7/3/2081659.html</guid>
    <pubDate>Mon, 03 Jul 2006 15:40:04 +0100</pubDate>
    <description>Alain Frisch of INRIA has been doing some work on streaming transformations, including the development of a &lt;a href=&quot;http://yquem.inria.fr/%7Efrisch/xstream/&quot;&gt;language called XStream...</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
  <item>
    <dc:creator>Michael Kay</dc:creator>
    <title>XIME-P in Chicago</title>
    <link>http://saxonica.blogharbor.com/blog/_archives/2006/7/1/2078016.html</link>
    <guid>http://saxonica.blogharbor.com/blog/_archives/2006/7/1/2078016.html</guid>
    <pubDate>Sat, 01 Jul 2006 06:23:01 +0100</pubDate>
    <description>It&#39;s been a heavy month for travelling: Grenoble, Dusseldorf, Prague, Paris, Edinburgh, and now Chicago for the one-day XIME-P XQuery workshop.&lt;br&gt;&lt;br&gt;I presented a paper describing a proposal for an XQuery extension to tackle positional grouping problems.&amp;nbsp; You can download both the &lt;a href=&quot;http://www.saxonica.com/papers/positionalgrouping.pdf&quot;&gt;paper&lt;/a&gt; (PDF) and the &lt;a href=&quot;http://www.saxonica.com/papers/XIME-P2006.ppt&quot;&gt;Powerpoint slides&lt;/a&gt;. This is essentially a conference of XQuery researchers and implementors, co-located with the SIGMOD database conference. The main reason I put this paper forward was that I was irritated at last year&#39;s workshop by the &quot;data&quot; orientation of most of the speakers, and felt there was a need to stress that XML, unlike relational data, is intrinsically ordered and that there are many practical tasks that need to take the ordering into account. As it happens, there was much more emphasis on narrative (&quot;document-oriented&quot;) XML at this year&#39;s event, including a couple of papers on&amp;nbsp; parallel markup - one of the speakers informing the audience, as if it was a new discovery, that XML was invented by markup people and not by database people.&lt;br&gt;&lt;br&gt;My paper on positional grouping got a reasonably good reception. Some people seemed to think that extensions to FLWOR expressions would be a better approach than a free-standing new construct. I&#39;m not convinced - I haven&#39;t seen the use cases that require it, and in any cases FLWOR expressions are already quite complicated enough. I think it was a bad mistake adding the &quot;O&quot; for &quot;order by&quot; rather than having a free-standing &quot;sort X by Y&quot; construct. Apart from anything else, it bends the data model by requiring the concept of tuples, which makes it hard to implement, hard to explain, and apparently has made it impossible to define the formal semantics.&lt;br&gt;&lt;br&gt;The XQuery people, by and large, still try to pretend that XSLT doesn&#39;t exist. Don Chamberlin proudly announced that the word &quot;XQuery&quot; gets 11,900,000 hits on Google, without mentioning that &quot;XSLT&quot; gets 90,200,000. He also mentioned evidence of lively traffic on internet XQuery forums, whereas my perception is that &lt;a href=&quot;http://www.mulberrytech.com/&quot;&gt;xsl-list&lt;/a&gt; still has ten times the traffic of all the XQuery sites put together (and it was much higher in the early days). Perhaps he didn&#39;t even think to look, I don&#39;t know. All the debate in the corridors and in the panel session seemed to make the assumption that the biggest competitor to XQuery was not XSLT but LinQ. For academics, this blind spot is understandable - they only think things are important if lots of academic papers are being written on the subject. It&#39;s harder to understand in the case of people working in the industry.&lt;br&gt;&lt;br&gt;Dana Florescu presented an important paper on XQueryP, a proposal for adding procedural extensions to XQuery - statements that define the order of execution, and allow assignment to variables. I have considerable doubts about whether this is the right way to go. There are use cases where such features are badly needed, but my fear, based on experience with saxon:assign, is that the facilities will be greatly abused by users who haven&#39;t taken the time it needs to learn about declarative programming. Also, Dana has a vision of XQuery being used to write entire applications. I prefer to think of XQuery being used to write small components, each of them functional in nature, which are then bound together to form a complete application using pipeline processing languages (which is where the sequential, stateful logic belongs).&lt;br&gt;&lt;br&gt;I&#39;ve now got a weekend to enjoy in Chicago, this being what happens when you pay your own air fares. Off to play croquet at 7.45 am - an unthinkable hour back home in England, but perhaps the idea is to avoid the heat and humidity. Even in free time, however, the diary is overloaded: I would have liked to watch the England v. Portugal match.&lt;br&gt;</description>
    
    <category domain="http://saxonica.blogharbor.com/blog">Main Page</category>
    
    
    
    
  </item>
  
</channel>
</rss>
