If you take the results of your query and serialize them as an XML document, you may be surprised by the way the namespace declarations appear. The number and location of namespace declarations in your results is not always intuitive. However, it can be controlled somewhat by how you declare namespaces in your query and by the use of settings in the prolog.
This section describes how you can control the appearance of namespace declarations in your results. None of these techniques affects the real meaning of the results; they are simply cosmetic. If you are unconcerned with the appearance of namespace declarations, you can skip this section.
This chapter describes how you can declare namespaces in the prolog or in direct element constructors. Which one you choose will not affect the actual namespaces of the elements and attributes in the results. However, it can affect the way the results will be serialized, in particular the number and location of the namespace declarations.
The difference has to do with statically known namespaces and in-scope namespaces.
Statically known namespaces are all the namespaces that are known at any given point in a query. This includes the predeclared namespaces, those that were declared in the prolog, and those that were declared using a namespace declaration attribute in an element constructor that is in scope.
In-scope namespaces, on the other hand, are namespaces that are currently in scope for a particular element. For an element from the input document, the in-scope namespaces are all the namespaces that are declared on that element or on any of its ancestors. Likewise, for an element being constructed in a query, they include the namespaces that are declared using a namespace declaration attribute on that element constructor or one of its ancestors. For a newly constructed element, the in-scope namespaces are a subset of the statically known namespaces. The in-scope namespaces may include predeclared namespaces, or ones that are declared in the prolog, but only if those namespaces are used in the name of that element, one of its ancestors, or one of its attributes.
Only in-scope namespaces, not all of the statically known namespaces become part of the results. Therefore, whether you declare a namespace in the prolog or in an element constructor can affect whether (and where) its declaration appears in your results. It can also affect which prefix is used, since although the prefix is not technically significant, the XQuery processor will keep track of prefixes used in input documents and queries and use them in the result documents.
Examples 10-12 and 10-13 illustrate this subtle difference. These examples use the input document shown in Example 10-11.
Example 10-12 shows a query where three different namespace declaration attributes appear in the report
element constructor. Namespaces that are declared in constructors are always part of the in-scope namespaces, so the report
element has three in-scope namespaces. As a result, all three namespace declarations appear in the report
element in the results. The namespace that is mapped to the cat
prefix is not used anywhere in the results, but its declaration nevertheless appears because it is one of the in-scope namespaces.
Example 10-12. Using XML namespace declarations
Query
<report xmlns="http://datypic.com/report" xmlns:cat="http://datypic.com/cat" xmlns:prod="http://datypic.com/prod"> { for $product in doc("prod_ns.xml")/prod:product return <lineItem> {$product/prod:number} {$product/prod:name} </lineItem> } </report>Results
<report xmlns:prod="http://datypic.com/prod" xmlns:cat="http://datypic.com/cat" xmlns="http://datypic.com/report"> <lineItem> <prod:number>563</prod:number> <prod:name language="en">Floppy Sun Hat</prod:name> </lineItem> </report>
Example 10-13, on the other hand, declares the three namespaces in the prolog. Prolog namespace declarations are not included in the in-scope namespaces unless they are specifically used by the element in question. Therefore, in this case, the report
element has only one in-scope namespace, the one that is used as part of its name, namely the default element namespace http://datypic.com/report. Consequently, in the results, you only see one namespace declaration on the report
element.
The prod:number
and prod:name
elements are in the prod
namespace, so the prod
declaration is added to the in-scope namespaces of each of these elements. The prod
namespace is declared on both the prod:number
and prod:name
elements, rather than on the report
element, because it is not one of the in-scope namespaces for the report
element.
The prod:number
and prod:name
elements also have the http://datypic.com/report namespace in scope, since it is used by an ancestor. However, the declaration for http://datypic.com/report does not need to be repeated on the prod:number
and prod:name
elements, since the declaration already appears on the report
element.
Example 10-13. Prolog namespace declarations
Query
declare default element namespace "http://datypic.com/report"; declare namespace cat = "http://datypic.com/cat"; declare namespace prod = "http://datypic.com/prod"; <report> { for $product in doc("prod_ns.xml")/prod:product return <lineItem> {$product/prod:number} {$product/prod:name} </lineItem> } </report>Results
<report xmlns="http://datypic.com/report"> <lineItem> <prod:number xmlns:prod="http://datypic.com/prod"> 563</prod:number> <prod:name xmlns:prod="http://datypic.com/prod" language="en">Floppy Sun Hat</prod:name> </lineItem> </report>
As you can see, your choice of how to declare the namespaces can affect their location in the result document. Example 10-14 shows a balance between the two approaches. The cat
namespace is declared in the prolog because it is not intended to appear in the results. (Perhaps it does need to be declared—for example, if it is used in a function or variable name.) The prod
namespace declaration is included in the report
constructor so that it only appears once in the results rather than being repeated for each of the prod:number
and prod:name
elements.
Example 10-14. A balanced approach
Query
declare namespace cat = "http://datypic.com/cat"; <report xmlns="http://datypic.com/report" xmlns:prod="http://datypic.com/prod"> { for $product in doc("prod_ns.xml")/prod:product return <lineItem> {$product/prod:number} {$product/prod:name} </lineItem> } </report>Results
<report xmlns:prod="http://datypic.com/prod" xmlns="http://datypic.com/report"> <lineItem> <prod:number>563</prod:number> <prod:name language="en">Floppy Sun Hat</prod:name> </lineItem> </report>
In addition to the considerations discussed in the previous section, there is another way to control the placement of namespace declarations in your results. A word of caution: the facilities described here interact in subtle ways, and not all products implement them correctly.
The copy-namespaces declaration, which appears in the query prolog, controls the appearance of namespace declarations. Specifically, it applies to the case where you construct a new element, and include elements from the input document as children of your new element. It controls whether namespace declarations are inherited from parent constructors, and/or preserved from input documents. Its syntax is shown in Figure 10-3.
It consists of two settings (both required), separated by a comma. For example:
declare copy-namespaces no-preserve, inherit;
If no copy-namespaces declaration is provided, the default values are determined by your implementation. They may have been specified by the user outside the scope of the query or set automatically by the processor.
The first setting, either preserve
or no-preserve
, controls whether unused namespace declarations are included from the input document. Unused here means "not used in the name of the element or its attributes." Namespace declarations that are being used are always included from the input document, regardless of the setting of preserve
or no-preserve
. Generally, no-preserve
is preferred, since there is not much point in copying unused namespace declarations.
One reason to choose preserve
is if your element content (or attribute values) contains namespace-sensitive values, such as qualified names. Namespaces used in content (as opposed to in element/attribute names) are not considered to be "used." If you choose no-preserve
, and the prefixes in the content are dependent on those nonpreserved declarations, an error may be raised when you try to validate or use the output document, because there may be an undeclared prefix.
The second setting, either inherit
or no-inherit
, controls whether the in-scope namespace declarations are copied from an outer constructor in the query to elements that are being copied (usually from the input document). Choosing inherit
usually results in a less cluttered result document. If this value is set to no-inherit
, unused namespaces declared on ancestor elements are explicitly undeclared on the copied element. The main reason for this is to stop namespaces from a content envelope (for example, a SOAP header) from bleeding into the content: if the namespaces are undeclared in the content, the recipient can extract the content without the envelope namespaces having polluted the message body.
Undeclaring prefixes is only allowed in Namespaces 1.1, so no-inherit
is essentially ignored if your implementation does not support Namespaces 1.1.
Note that these settings affect in-scope namespaces only, not statically known namespaces. They apply to both default namespace declarations and those that use prefixes.
Examples 10-16 and 10-17 exhibit the differences in these settings. They use the input document shown in Example 10-15, which has three different namespaces declared.
Example 10-15. Multinamespace input document (cat_ns2.xml)
<cat:catalog xmlns:cat="http://datypic.com/cat" xmlns:prod="http://datypic.com/prod" xmlns:ord="http://datypic.com/ord"> <prod:product> <prod:number>563</prod:number> <prod:name language="en">Floppy Sun Hat</prod:name> </prod:product> </cat:catalog>
Example 10-16 shows a query that uses the settings no-preserve
and inherit
. This combination of settings usually results in the fewest surprises. The query returns a report
element that contains a product
element copied from the input document. The report
element has three namespace declaration attributes, and therefore has three in-scope namespaces.
Example 10-16. Query with no-preserve, inherit
Query
declare copy-namespaces no-preserve, inherit; <report xmlns="http://datypic.com/report" xmlns:cat="http://datypic.com/cat" xmlns:prodnew="http://datypic.com/prod"> { doc("cat_ns2.xml")//prodnew:product } </report>Results
<report xmlns="http://datypic.com/report" xmlns:cat="http://datypic.com/cat" xmlns:prodnew="http://datypic.com/prod"> <prod:product xmlns:prod="http://datypic.com/prod"> <prod:number>563</prod:number> <prod:name language="en">Floppy Sun Hat</prod:name> </prod:product> </report>
In the results, the only namespace declaration preserved from the input document is the one that the product
element is actually using (because it is part of its name). This is because the no-preserve
setting meant that unused namespace declarations were not copied from the input document.
Because inherit
is chosen, the product
element has declarations for the default (report)
and cat
namespaces in scope, even though it doesn't use them.
Note that even though the http://datypic.com/prod namespace is declared (with the prefix prodnew
) in the report
start tag, it is redeclared in the product
start tag with a different prefix, and it is the prod
prefix that is used. This is because nodes that are included from the input document will always use the prefixes that come from the input document. No combination of copy-namespaces settings will allow the prodnew
prefix to be used for the product
element instead of the prod
prefix. To change any aspect of the element name, whether prefix, URI, or local name, you need to construct a new element rather than copying the original.
Example 10-17 shows the exact same query but with the opposite settings: preserve
and no-inherit
. In this case, all three namespace declarations from the input document are preserved (prod
, ord
, and cat
), even though the cat
and ord
namespaces are not used. The cat
namespace declaration is not written out in the product
start tag because it has the same prefix and namespace as the one in the report
start tag. The serialization process takes care of eliminating duplicate namespace declarations that are in the same scope.
Because no-inherit
is chosen, the product
element should not inherit the default (report
) and prodnew
namespace declarations from the report
element. Therefore, they are undeclared.
Example 10-17. Query with preserve, no-inherit
Query
declare copy-namespaces preserve, no-inherit; <report xmlns="http://datypic.com/report" xmlns:cat="http://datypic.com/cat" xmlns:prodnew="http://datypic.com/prod"> { doc("cat_ns2.xml")//prodnew:product } </report>Results
<report xmlns="http://datypic.com/report" xmlns:cat="http://datypic.com/cat" xmlns:prodnew"http://datypic.com/prod"> <prod:product xmlns:prod="http://datypic.com/prod" xmlns:ord="http://datypic.com/ord" xmlns="" xmlns:prodnew=""> <prod:number>563</prod:number> <prod:name language="en">Floppy Sun Hat</prod:name> </prod:product> </report>
3.144.30.62