- From: Andre Cusson <ac@hyperbase.com>
- Date: Wed, 26 Mar 2003 16:32:32 -0500
- To: saxon-help@lists.sourceforge.net, public-qt-comments@w3.org
- Cc: michael.h.kay@ntlworld.com
At 01:39 PM 3/10/2003 +0000, you wrote:
I had a word with my colleagues on the WG about this (though not on the
official agenda) and could find little support for relaxing the current
rule. There was a general feeling that outputting a result document
while producing a temporary tree is a side-effect and should not be
allowed; also that it should be possible to achieve the required effect
without doing this.
If you could construct an example, preferably simplified, that shows why
you need to do this, it would be most helpful. I know you have sent me
code in the past, but I don't think it was a complete stylesheet that I
could work with.
Michael Kay
Hi,
The way I see this, it is a very simple case of recursive traversal of a
nodeset.
I believe that the example that I sent already had everything required to
reproduce the situation.
As for the use-cases, I tried to give you a few examples of where/how we
use it.
To do more, I would have to show you the real code where we use it.
I would be happy to do that if I new that I wasn't throwing proprietary
code out in the open.
Is there a way of doing this securely ?
Of course I could also rework the code, build another application so that
it does not need to be protected but I feel that it probably is not worth
the effort since if you cannot see the simplicity, basicness and straight
forwardness of the case from a simple example I doubt that a more elaborate
one would help. And if it would, a set of real world applications would
probably be best. But I need to protect the IP and source for the people here.
As for getting the same results some other way, it is surely possible, I
could even do it in Java or any other language that supports
recursion. Alternatively, I could also completely redesign the application
and try to do something that is inherently simple and natural in a more
complex way but the price to pay in redesign and performance does not
attract me at this point (although some day I may not have any other
choice. At that point, I will also have to take a look at up coming
alternatives to XSLT, like STX).
Still, I am puzzled that something so basic and fundamental does not
register with the WG and others.
Does everybody agree that "XSLT 2.0 does not support output of multiple
pages (files) in recursive traversal of node sets, in pull processing" ?
For me, it is a very powerful design tool, in pull processing. Some
problems are better resolved by push processing, but others by pull.
I like and use both ..., up to XSLT 2.0 !
Nevertheless, I will try again here with a simplified example/use-case that
works ok in XSLT1.1 but not anymore in XSLT2.0 :
The node set being traversed contains information to be processed and
mapped to html pages (can't output everything to just one page/file). As
the application traverses the information in the node set, it builds a page
and that page links to sub-pages generated from further traversing and
processing the node set, and so on, recursively, until the node set has
been completely traversed and no more pages need to be generated.
So, for example, let's say we have a template called 'makepage' that
renders one page to html, using result-document. We are going to call it
every time that we have gathered the data for a page, as we are traversing
the node set. For our example here, we will try to do invoicing, that is
to produce outstanding invoices for many customers (let's say, at the end
of the month, for example). Here, we want one html page with links to each
of the invoices (and envelopes) produced, as a table of content and one (or
more) html page per invoice produced. For every customer for which we are
generating an invoice, we also need to generate another html page with the
corresponding mailing label/envelope, also providing a link to this page on
our TOC page. Also, because we want to stream data as much as possible, we
want to avoid reprocessing the nodeset multiple times. So,
we define a template called makepage to render a page data to html,
something like :
<xsl:output name="output-format" .../>
<xsl:template name="makepage">
<xsl:param name="content"/>
<xsl:param name="filename"/>
<xsl:result-document href="{concat($filename, 'html')}"
format="output-format">
<html>
<head>
<title>
<xsl:value-of select="$filename"/>
</title>
<body>
<xsl:copy-of select="$content"/>
</body>
</html>
<xsl:/result-document>
</xsl:template>
then, assuming that we have a template called 'get-client-address' that
simply outputs the address for a given client, we define a template to
build a mailing label like :
<xsl:template name="envelope">
<xsl:param name="client-id"/>
<xsl:call-template name="makepage">
<xsl:with-param name="filename" select="concat('mail-',
$client-id)"/>
<xsl:with-param name="content">
<table>
<tr>
<td align="top">
<xsl:copy-of select="$logo"/>
</td>
<td align="bottom">
<xsl:call-template
name="get-client-address">
<xsl:with-param
name="client" select="$client-id"/>
</xsl:call-template>
</td>
</tr>
</table>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
then, we need a template to generate the body for an invoice, like :
<xsl:template name="invoice">
<xsl:param name="invoice-id"/>
...
<xsl:call-template name="makepage">
<xsl:with-param name="filename" select="$invoice-id"/>
<xsl:with-param name="content">
<table>
...
</table>
</xsl:with-param>
</xsl:call-template>
...
</xsl:template>
and finally, the invoicing template that traverses the source node set, like :
<xsl:template name="invoicing">
<xsl:param name="source"/>
<xsl:for-each select="$source/*">
<xsl:call-template name="makepage"><!-- TOC (ex: invoicing
report page-->
<xsl:with-param name="content">
<xsl:for-each select="$clients">
<p style="font-weight: bold;"><!--
TOC link to mailing -->
<a href="{concat($path,
@id, 'html')}"><xsl:value-of select="@id"/></a>
</p>
<xsl:call-template
name="envelope"><!--mailing page-->
<xsl:with-param
name="client-id" select="@id"/>
</xsl:call-template>
<xsl:for-each
select="$outstanding-invoice-for-this-client">
<xsl:call-template
name="invoice"><!--invoice page-->
<xsl:wiith-param
name="invoice-id" select="@id"/>
</xsl:call-template>
<p><!-- TOC link to
invoice -->
<a
href="{concat($path, @id, 'html')}"><xsl:value-of select="@id"/></a>
</p>
</xsl:for-each>
</xsl:for-each>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
Of course, this is a simplified use-case and example but if processed in
XSLT2.0, an error will be generated on the result-document line of the
'makepage' template, every time an invoice is requested and every time an
envelope is requested.
I hope that this example is useful and that I am not alone in thinking that
recursion, whether in push or pull processing is fundamental to node set
traversal, and not a side-effect.
Whether the output is to a single file or multiple file should not change
anything and is in fact imposed by standards like HTML (and by the physical
world in which applications operate).
In our application, we have many cases for this as I have already pointed
out, including invoicing, OR-mapping, compound document processing, etc.
The basic issue is always the same.
Again, I hope that this helps.
Thank you for your time and consideration.
Regards,
Andre Cusson
ac@hyperbase.com
01 Communications Inc.
PS: come to think of it, simply building a table of contents as one is pull
processing the pages of a document is a typical use of result-document from
a temporary tree.
PSS: the same issue could come up in push processing also, especially when
required to pass parameters in apply-templates. It just seems natural in
pull though.
Received on Wednesday, 26 March 2003 16:10:45 UTC