Controlling Namespace Declarations in Your Results

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.

In-Scope Versus Statically Known Namespaces

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>

Controlling the Copying of Namespace Declarations

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.

Syntax of a copy-namespaces declaration

Figure 10-3. Syntax of a copy-namespaces declaration

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.

Tip

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>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.30.62