1
votes

I want to use XQuery in order to map between two XML documents. Whereas the source document does not contain any namespace declaration, the target document requires a target namespace (must be the default namespace according to the system processing it). I understand that XQuery always requires a namespace (and everything within XQuery is in a namespace). However I would like so simplify my XQuery's XPath expressions and especially would like to omit namespaces wherever possible.

The following example illustrates the situation:

Source document

<?xml version="1.0" encoding="UTF-8"?>
<!-- note that this documents does not declare any namespace -->
<a>
    <b>
        <c>ABC</c>
    </b>
</a>

XQuery file

xquery version "1.0";

declare variable $doc := .;

let $abc := $doc/a/b/c
return
<foo xmlns="http://www.example.org">    
    <bar1>{$doc/a/b/c/text()}</bar1>    
    <bar2>{$doc/*:a/*:b/*:c/text()}</bar2>
    <bar3>{$abc/text()}</bar3>    
</foo>

This generates the following (Saxon-HE 9.5.1.3):

<?xml version="1.0" encoding="UTF-8"?>
<foo xmlns="http://www.example.org">
   <bar1/>
   <bar2>ABC</bar2>
   <bar3>ABC</bar3>
</foo>

Basically I would like to be able to construct elements as in the first rule (bar1), i. e. without using namespaces in XPath expressions. Unfortunately that does not seem to work. Instead I have to use a more laborious syntax as in the 2nd rule (bar2).

A workaround (well, rather a hack) would be to have variables declared before introducing the namespaces (see bar3), but I am sceptical if this is a good idea as a) it probably wouldn't scale for larger documents and b) it prevents from declaring the default element namespace "properly", i. e. as intended by XQuery via a separate declaration in the document header.

Does anyone have an idea how to achieve the desired behaviour? Thank you very much in advance!

1

1 Answers

2
votes

Unfortunately in XQuery the default namespace for names in XPath expressions is always the same as the default namespace for constructed elements.

One workaround is to use computed element constructors:

element Q{http://www.example.org}foo {    
    element Q{http://www.example.org}bar1 {$doc/a/b/c/text()}
}

I agree, it's not pretty.

XSLT 2.0 got this one right with separate default namespaces for input and output. I remember trying to convince the XQuery WG that this was needed, and failing.