Discussion:
[xquery-talk] Accessing empty namespaced elements in non-empty contexts
Joe Wicentowski
2018-04-02 19:00:45 UTC
Permalink
Hi all,

A common question for beginners is how to access empty namespaced elements
in non-empty contexts. The easiest answer is to use a wildcard. For
example, we use one here inside the curly braces:

let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/*:y }</z>

As expected, this query returns:

<z xmlns="foo"><y xmlns=""/></z>

The other method I know of is to use the URI-qualified name:

let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/Q{}y }</z>

A third method occurred to me, but it does not work, and I haven't been
able to pin down the reason despite reading the spec. The idea is to bind
the empty namespace URI to a namespace prefix, e.g., "my":

declare namespace my="";

let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/my:y }</z>

In BaseX, eXist, and Saxon, this returns err:XPST0081 (
https://www.w3.org/TR/xquery-31/#ERRXPST0081). The location of the error
points to the step, "my:y" on the final line.

Can anyone enlighten me on the reason this 3rd method is invalid? Bonus
points for an explanation that includes why I cannot bind a namespace
prefix to the empty namespace, but I can access it via *: and Q{}?

Thanks,
Joe
Michael Kay
2018-04-02 19:19:04 UTC
Permalink
XML doesn't allow you to bind a prefix to the thing-that-is-not-a-namespace.

With XML namespaces 1.1, the declaration xmlns:x="" doesn't bind x to anything, it unbinds x. Within the scope of this (un)declaratiion, the prefix x cannot be used.

It makes sense for XQuery to do the same thing. The rules are in §3.9.1.2:

If the namespace URI is a zero-length string and the implementation supports [XML Names 1.1] <https://www.w3.org/TR/xquery-31/#XMLNAMES11>, any existing namespace binding for the given prefix is removed from the in-scope namespaces <https://www.w3.org/TR/xquery-31/#dt-in-scope-namespaces> of the constructed element and from thestatically known namespaces <https://www.w3.org/TR/xquery-31/#dt-static-namespaces> of the constructor expression. If the namespace URI is a zero-length string and the implementation does not support [XML Names 1.1] <https://www.w3.org/TR/xquery-31/#XMLNAMES11>, a static error is raised [err:XQST0085 <https://www.w3.org/TR/xquery-31/#ERRXQST0085>]. It isimplementation-defined <https://www.w3.org/TR/xquery-31/#dt-implementation-defined> whether an implementation supports [XML Names] <https://www.w3.org/TR/xquery-31/#XMLNAMES> or [XML Names 1.1] <https://www.w3.org/TR/xquery-31/#XMLNAMES11>.

Michael Kay
Saxonica
Post by Joe Wicentowski
Hi all,
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/*:y }</z>
<z xmlns="foo"><y xmlns=""/></z>
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/Q{}y }</z>
declare namespace my="";
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/my:y }</z>
In BaseX, eXist, and Saxon, this returns err:XPST0081 (https://www.w3.org/TR/xquery-31/#ERRXPST0081 <https://www.w3.org/TR/xquery-31/#ERRXPST0081>). The location of the error points to the step, "my:y" on the final line.
Can anyone enlighten me on the reason this 3rd method is invalid? Bonus points for an explanation that includes why I cannot bind a namespace prefix to the empty namespace, but I can access it via *: and Q{}?
Thanks,
Joe
_______________________________________________
http://x-query.com/mailman/listinfo/talk
Joe Wicentowski
2018-04-03 12:20:28 UTC
Permalink
Hi Michael,

Thank you for your reply. It's interesting that until XPath 3.0, we could
*construct* empty-namespace elements inside non-empty namespace elements
(via the xmlns="" declaration), but we couldn't *query* them without
resorting to the somewhat means of indirect wildcards (e.g., `/*:elem`) or
use of the local-name function (e.g., `/*[local-name() eq 'elem']`). Is
that right? If so, this drives home the importance to me of the
URI-qualified names feature (e.g., `/Q{}elem`) released with XPath 3.0.

I'd be interested to know more about the history of the development of
namespaces and efforts to bridge the world of namespaces (namespace
axis-land) with the world of documents without this axis (namespace
flat-land). Is there any good published account of this?

Joe
Post by Michael Kay
XML doesn't allow you to bind a prefix to the
thing-that-is-not-a-namespace.
With XML namespaces 1.1, the declaration xmlns:x="" doesn't bind x to
anything, it unbinds x. Within the scope of this (un)declaratiion, the
prefix x cannot be used.
If the namespace URI is a zero-length string and the implementation
supports [XML Names 1.1] <https://www.w3.org/TR/xquery-31/#XMLNAMES11>,
any existing namespace binding for the given prefix is removed from the in-scope
namespaces <https://www.w3.org/TR/xquery-31/#dt-in-scope-namespaces> of
the constructed element and from thestatically known namespaces
<https://www.w3.org/TR/xquery-31/#dt-static-namespaces> of the
constructor expression. If the namespace URI is a zero-length string and
the implementation does not support [XML Names 1.1]
<https://www.w3.org/TR/xquery-31/#XMLNAMES11>, a static error is raised [
err:XQST0085 <https://www.w3.org/TR/xquery-31/#ERRXQST0085>]. It is
implementation-defined
<https://www.w3.org/TR/xquery-31/#dt-implementation-defined> whether an
implementation supports [XML Names]
<https://www.w3.org/TR/xquery-31/#XMLNAMES> or [XML Names 1.1]
<https://www.w3.org/TR/xquery-31/#XMLNAMES11>.
Michael Kay
Saxonica
Hi all,
A common question for beginners is how to access empty namespaced elements
in non-empty contexts. The easiest answer is to use a wildcard. For
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/*:y }</z>
<z xmlns="foo"><y xmlns=""/></z>
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/Q{}y }</z>
A third method occurred to me, but it does not work, and I haven't been
able to pin down the reason despite reading the spec. The idea is to bind
declare namespace my="";
let $x := <x><y/></x>
return
<z xmlns="foo">{ $x/my:y }</z>
In BaseX, eXist, and Saxon, this returns err:XPST0081 (
https://www.w3.org/TR/xquery-31/#ERRXPST0081). The location of the error
points to the step, "my:y" on the final line.
Can anyone enlighten me on the reason this 3rd method is invalid? Bonus
points for an explanation that includes why I cannot bind a namespace
prefix to the empty namespace, but I can access it via *: and Q{}?
Thanks,
Joe
_______________________________________________
http://x-query.com/mailman/listinfo/talk
Michael Kay
2018-04-03 15:50:30 UTC
Permalink
Thank you for your reply. It's interesting that until XPath 3.0, we could *construct* empty-namespace elements inside non-empty namespace elements (via the xmlns="" declaration), but we couldn't *query* them without resorting to the somewhat means of indirect wildcards (e.g., `/*:elem`) or use of the local-name function (e.g., `/*[local-name() eq 'elem']`). Is that right?
Yes, that's correct.

XSLT 1.0 had similar problems and the xpath-default-namespace attribute was introduced in 2.0, but I remember failing to persuade the XQuery WG that XQ needed something similar. The WG as a whole was quite resentful of the amount of complexity that namespaces brought to the language, and wanted to avoid adding more and more complications. I had shared some of that frustration when first developing Saxon: I recall complaining on one occasion that the product would be about 30% smaller if it weren't for namespaces.

I remain convinced that namespaces, in the form that XML defined them, were a major design mistake. (I'm sure I posted to xml-dev, though I have failed to find the post subsequently, that it didn't really matter, because the design of namespaces was so bad that no-one would ever use them.)

What exactly are the problems with the design?

* A compound name (uri+local) adds complexity to every API that involves passing names, when compared with using a single string.

* The use of namespace prefixes creates ambiguity as to whether the choice of prefix is significant or not. (If it weren't for QNames-in-content, we could say that prefixes aren't significant and can be dropped; but even then, as with CDATA sections etc, some people would want the parser to preserve them).

* The use of prefixes makes APIs for constructing XML a lot more complex.

* Declaring namespaces using attributes, rather than through some separate syntactic construct, creates messiness in the data model and conceptual confusion.

I think all the goals of XML namespaces could have been achieved with a much simpler design. For example:

* Element and attribute names are simple strings, typically in the form <org.w3.xslt:transform> (let's call the "org.w3.xslt" part a qualifier)

* Using an explicit qualifier in an element name establishes a default qualifier for child elements.

* Omitting a qualifier is a simple input abbreviation and doesn't affect the element name notified to applications by the parser

* Attribute names, if they need a qualifier, are always written in full, e.g. org.w3.xml:base.

XSLT is one of very few vocabularies where elements in different namespaces are freely mixed; it's also one of very few that uses namespace prefixes in content (i.e. not in element or attribute names). The design of XML namespaces was possibly over-influenced by this unusual use case. XSLT could have handled it differently, e.g. with a rule that elements starting X: are XSLT instructions, where X defaults to "xsl" but can be user-declared. In nearly all other cases where multiple namespaces are used, there is an element (such as svg:svg or soap:body) that signals a namespace switch which applies to the entire subtree of that element, and a design that optimized for that use case would have been better.
I'd be interested to know more about the history of the development of namespaces and efforts to bridge the world of namespaces (namespace axis-land) with the world of documents without this axis (namespace flat-land). Is there any good published account of this?
No, millions of words have been written on the subject on xml-dev, but there is no succinct summary of the history.

What is undoubtedly true is that the design was rushed through without enough thought or consensus.

I found myself in the odd position in the XQuery WG of being the person who was always pushing the James Clark model of namespaces, e.g. the way namespace nodes work, and this probably meant people thought I was an enthusiast for namespaces whereas I actually thought simply that the Clark model was the best way of limiting the damage. XQuery 3.0 got itself into the strange position of finding that it needed namespace nodes to achieve completeness on the document construction side of the language, but still rejected use of namespace nodes and the namespace axis on the retrieval side. I always found that pretty weird.

Michael Kay
Saxonica

Loading...