RE: [xsl] XQuery to Report Template Parameters

Subject: RE: [xsl] XQuery to Report Template Parameters
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Sun, 17 Feb 2008 18:44:23 -0000
> I certainly claim no special XQuery expertise, so I would 
> also welcome any feedback on the coding of the query itself.

You asked for feedback, here are a few observations... Most of the comments
below would apply equally if you had written the corresponding code in XSLT
> 
> declare function local:getTemplateLabel($template as 
> element()) as xs:string {

You're expecting $template to be an xsl:template element, so why not say so:

   $template as element(xsl:template)

This assertion helps the reader of the code understand it, and it might
catch programming mistakes that would otherwise be hard to diagnose.

>   concat('Template',
>   if ($template/@name != '') then concat(' 
> name="',string($template/@name), '"') else ''

If an xsl:template element has a name attribute, then the name will never be
"". Also, concat converts its arguments to strings automatically. So you can
simplify this to

if ($template/@name) then concat(' name="', $template/@name, '"') else ''

It might not suit your taste but you could also write

replace($template/@name, '.+', ' name="$0"')

>   if ($template/@match != '') then concat(' match="', 
> string($template/@match), '"') else '') };

ditto.
> 
> declare function local:echoElement($elem as element()) as element() {
> 
>    if (namespace-uri($elem) = "http://www.w3.org/1999/XSL/Transform";)
>       then element{name($elem)}{$elem/@*, 
> local:echoNodes($elem/node())}
>       else element{name($elem)}{$elem/@*, 
> local:echoNodes($elem/node())} };

I'm a bit puzzled here - you seem to have the same expression in both
branches of the conditional.

The condition can be written more concisely as

if (self::xsl:*)

The construct element{name($elem)} will fail if the input stylesheet uses a
prefix other than "xsl" for the XSLT namespace. It would be better to write
element{node-name($elem)}.

There's another problem here which unfortunately cannot be solved except by
rewriting your code in XSLT. If your stylesheet declares namespaces that are
not used in any element or attribute names, but only in content, then they
will be lost from the output. This is very common in stylesheets, of course,
as namespaces are often used for the names of functions (and sometimes for
the names of variables). If you're only interested in producing a
human-readable report this might not matter, but in general, processing XSLT
stylesheets using XQuery suffers from this problem.


> 
> declare function local:reportWithParam($param as element()) 

At this stage it really would be more friendly to a reader (like me) to say
$param as element(xsl:with-param) - it avoids me having to read your code to
scan for all the calls to this function to see what kind of arguments you
are supplying.

> as node()* {
>        <parameter>
>          <name>{string($param/@name)}</name>

Again the call on string() is redundant.

>          <value>
>          {if ($param/@select != '')

Again, I can't see the reason for the " != '' ". Testing for the existence
of the attribute would seem adequate

> 
> let $templateParams := $doc/*/xsl:template/xsl:param let 
> $apply-templates := 
> $doc/*/xsl:template[descendant::xsl:apply-templates/xsl:with-param]
> let $call-templates :=
> $doc/*/xsl:template[descendant::xsl:call-template/xsl:with-param]

I can't see why you are restricting yourself to xsl:apply-templates and
xsl:call-template instructions that occur within a template. What about
those that occur within a function, a global variable, or a key definition?
And what about with-param elements that are children of xsl:apply-imports or
xsl:next-match?

Michael Kay
http://www.saxonica.com/

Current Thread