RE: [xsl] Saxon fails to exclude result prefixes?

Subject: RE: [xsl] Saxon fails to exclude result prefixes?
From: "Michael Kay" <mhk@xxxxxxxxx>
Date: Tue, 28 Oct 2003 00:04:54 -0000
Basically, what happens when you have two namespace declarations for the
same namespace URI is (a) your request to exclude a result prefix is
actually a request to exclude all namespace nodes for that namespace
URI; (b) the serializer (according to the XSLT 1.0 spec) is allowed to
add extra namespace nodes, and is required to add them where the
namespace URI is actually used. One would like the serializer to add the
minimum set of necessary namespace nodes at this stage, but Saxon is
using the rule that if the namespace URI is used in the result, then it
adds back all the namespace nodes for that URI, regardless of prefix.
This is inelegant, but not non-conformant. The serializer is actually
allowed to output any namespace declarations it chooses.

Michael Kay


> -----Original Message-----
> From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx 
> [mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of 
> Lars Huttar
> Sent: 27 October 2003 17:51
> To: XSL-List (E-mail)
> Subject: [xsl] Saxon fails to exclude result prefixes?
> 
> 
> Hi all,
> Maybe I'm missing something, but it sure seems like Saxon
> isn't doing what it's supposed to in this case.
> I'm using Saxon652. (But I have just now upgraded to 6.5.3
> and found the same behavior.)
> Can anybody confirm if this is a bug?
> 
> The situation:
> 
> I have a stylesheet that does an identity
> transform for the most part, but discards some elements
> and adds others. All elements in the input and the output
> are in the namespace whose URI is "http://www.sil.org/namespace/gem";.
> 
> In the input, the outermost element, <system-model>,
> has a namespace pseudo-attribute on it:
> 
>   <system-model xmlns="http://www.sil.org/namespace/gem";>
> 
> and no prefixes or other namespace declarations are used.
> I would like the output to be the same way.
> 
> The problem:
> 
> The nodes that are copied via <xsl:copy> appear the same in 
> the output as they do in the input, i.e. none of them have 
> namespace declarations except the outermost. However, the 
> nodes I create as literal result elements have a superfluous 
> namespace declaration, e.g.
> 
>      <access xmlns:gem="http://www.sil.org/namespace/gem";
> 		role="guest" update="no" read="yes"/>
> 
> This happens even though (and whether or not) I put
>    xsl:exclude-result-prefixes="gem"
> on the literal result element <access>.
> My reading of the spec leads me to believe that putting
>    xsl:exclude-result-prefixes="gem"
> here, or
>    exclude-result-prefixes="gem"
> on the <xsl:stylesheet> element, should prevent unnecessary 
> declarations of the "gem" prefix in the output. (I have tried both.)
> 
> When I try this stylesheet with this input in Xalan or MSXSL,
> I get what I wanted: <access> with no "gem" prefix declaration.
> 
> Is this indeed a bug in Saxon?
> I checked the list of changes 6.5.2 - 6.5.3, the
> list of known limitations of 6.5.3, and the Saxon bug tracker 
> pages on Sourceforge, and didn't see this mentioned as a bug.
> 
> 
> If this is not a bug and I'm just misunderstanding what 
> (xsl:)exclude-result-prefixes is supposed to do, I would 
> appreciate correction.
> 
> 
> The files in question will be available at
>   http://www.huttar.net/lars-kathy/test/Ethnologue.xml: the 
> input document;
>    .../role-extractor.xsl: the stylesheet;
>    .../system-model.dtd: DTD for the input document;
>    .../msxslout.xml: the output when processed by msxml;
>    .../saxonout.xml: the output when processed by Saxon 653;
> 
> but at the moment I can't get the server to let me upload them.
> 
> So here's the stylesheet:
> 
> <?xml version="1.0" encoding="UTF-8"?>
> 
> <!-- role-extractor.xsl
> 
>   Input: a system model conforming to system-model.dtd
>   Parameter: a role (e.g. 'guest' or 'admin')
> 
>   Output: the system model, filtered to include only items 
> accessible to the given role.
>   -->
> 
> <xsl:stylesheet version="1.0" 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>       xmlns:gem="http://www.sil.org/namespace/gem";
>       xmlns="http://www.sil.org/namespace/gem";>
>   <xsl:output method="xml" version="1.0" encoding="UTF-8" 
> indent="yes"/>
> 
>   <xsl:param name="role" select="'admin'" />
> 
>   <!-- global variables -->
>   <xsl:variable name="role-node" 
> select="/*/gem:columnFour/gem:roles/*[@id = $role]
>         | /*/gem:columnFour/gem:roles/gem:admin[$role = 'admin']" />
>   <xsl:variable name="default-read">
>     <xsl:choose>
>       <xsl:when test="$role-node/@read = 'all'">yes</xsl:when>
>       <xsl:otherwise>no</xsl:otherwise>
>     </xsl:choose>
>   </xsl:variable>
>   <xsl:variable name="default-update">
>     <xsl:choose>
>       <xsl:when test="$role-node/@update = 'all'">yes</xsl:when>
>       <xsl:otherwise>no</xsl:otherwise>
>     </xsl:choose>
>   </xsl:variable>
> 
>   <!-- Top-level template -->
>   <xsl:template match="/">
>     <xsl:if test="not($role-node)">
>       <xsl:message terminate="yes">Role "<xsl:value-of 
> select="$role" />" unknown.</xsl:message>
>     </xsl:if>
>     <xsl:copy>
>       <xsl:apply-templates select="node()"/>
>     </xsl:copy>
>   </xsl:template>
> 
>   <!-- Discard <attribute>s that the given role doesn't have 
> access to. Modify others. -->
>   <xsl:template match="gem:attribute">
>     <xsl:choose>
>       <!-- Discard <attribute>s that the given role 
> explicitly has no access to. -->
>       <xsl:when test="gem:access[@role = $role and @read = 'no']" />
>       <!-- Discard <attribute>s that the given role doesn't 
> have access to by default. -->
>       <xsl:when test="$default-read = 'no' and 
> not(gem:access[@role = $role and @read = 'yes'])" />
> 
>       <!-- The given role has read access to this attribute, 
> so process the attribute. -->
>       <xsl:otherwise>
>         <xsl:copy>
>           <!-- Copy everything except <access> elements -->
>           <xsl:apply-templates 
> select="@*|node()[not(self::gem:access)]" />
>           <!-- create an <access> element only if needed 
> (i.e. if this attribute is read-only) -->
>           <xsl:if test="($default-update = 'no' and 
> not(gem:access[@role = $role and @update =
> 'yes'])) or
>                              gem:access[@role = $role and 
> @update = 'no']">
>            <access xsl:exclude-result-prefixes="gem"
>                  role="{$role}" update='no' read='yes' /> 
> <!-- @read is redundant but is there to conform to DTD -->
>           </xsl:if>
>         </xsl:copy>
>       </xsl:otherwise>
>     </xsl:choose>
>   </xsl:template>
> 
>   <xsl:template match="gem:roles">
>     <!-- Discard all of <roles>' child elements except those 
> that are required by the DTD. -->
>     <xsl:apply-templates select="gem:guest | gem:admin" />
>   </xsl:template>
> 
>   <!-- Everything else is preserved as-is. -->
>   <!-- identity transform -->  <!-- Problem: namespace needs 
> to be preserved too. -->
>   <xsl:template match="@*|node()" priority="-1">
>     <xsl:copy>
> <!-- Debugging:
>       <xsl:message>Copying node <xsl:value-of select="name()" 
> /> with namespace-URI <xsl:value-of select="namespace-uri()" 
> /></xsl:message> -->
>       <xsl:apply-templates select="@*|node()"/>
>     </xsl:copy>
>   </xsl:template>
> 
> </xsl:stylesheet>
> 
> 
> And here's an excerpt from the input XML:
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE system-model SYSTEM "system-model.dtd">
> <system-model xmlns="http://www.sil.org/namespace/gem";>
>    <name>Ethnologue</name>
> ...
>    <columnOne>
>     <object id="d.ECoun" independent="yes" stage="phase1">
>       <name>Ethnologue Country</name>
>       <definition>The
>   Ethnologue description of a country of the world.</definition>
>       <attribute size="35" type="phrase">
>         <name>Print_Name</name>
>         <definition>LNAM -
>   &#34;Print:&#34; format Country Name</definition>
>       </attribute>
> ...
>     </object>
>    </columnOne>
>    <columnFour>
>       <roles>
>          <guest id="guest" read="all" update="none"/>
>          <admin read="all" update="all"/>
>       </roles>
>    </columnFour>
> </system-model>
> 
> 
> Expected output: the <attribute> whose <name> is Print_Name 
> should have an <access> element that looks like this:
> 
>      <access role="guest" update="no" read="yes"/>
> 
> but instead I get this with Saxon:
> 
>      <access xmlns:gem="http://www.sil.org/namespace/gem";
> 		role="guest" update="no" read="yes"/>
> 
> 
> Thanks,
> Lars
> 
> 
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread