Computed Constructors

Generally, if you know the element or attribute name that you want to use in your results, you can use XML-like syntax as described in the previous sections. However, sometimes you may want to compute the name dynamically, so you cannot include the literal names in the query. In this case, you use computed constructors. This can be useful when:

  • You want to simply copy elements from the input document (regardless of name) but make minor changes to their content. For example, to add an id attribute to every element, or to move all the elements to a different namespace.

  • You want to turn content from the input document into element or attribute names. For example, you want to create an element whose name is the value of the dept attribute in the input document, without a predefined list of elements.

  • You want to look up element names in a separate dictionary, e.g., for language translation purposes.

You can use computed constructors for elements, attributes, and other kinds of nodes.

Computed Element Constructors

A computed element constructor uses the keyword element, followed by a name and some content in curly braces. The syntax of a computed element constructor is shown in Figure 5-2.

Syntax of a computed element constructor

Figure 5-2. Syntax of a computed element constructor

Example 5-13 shows a query that is equivalent to Example 5-3, except that it uses computed element constructors instead of direct ones.

Example 5-13. Simple computed constructor

Query
element html {
  element h1 { "Product Catalog" },
  element ul {
    for $prod in doc("catalog.xml")/catalog/product
    return element li {"number:",data($prod/number),", name:",data($prod/name)}
  }
}
Results
<html>
  <h1>Product Catalog</h1>
  <ul>

    <li>number: 557 , name: Fleece Pullover</li>
    <li>number: 563 , name: Floppy Sun Hat</li>
    <li>number: 443 , name: Deluxe Travel Bag</li>
    <li>number: 784 , name: Cotton Dress Shirt</li>
  </ul>
</html>

Names of computed element constructors

The name in a computed element constructor is represented by either a qualified name or an expression (in curly braces) that evaluates to a qualified name. This is then followed by an enclosed expression (also in curly braces) that contains the content of the element. For example, the constructor:

element h1 { "Product Catalog" }

uses a literal name to construct the element <h1>Product Catalog</h1>, while:

element {concat("h",$level)}  { "Product Catalog" }

uses an expression, enclosed in curly braces, to dynamically generate the name by concatenating the literal h with a variable value.

You could also copy the name of the new node from an existing node, using the node-name function. For example:

element {node-name($myNode)}  { "contents" }

will give the new element the same name as the node that is bound to the $myNode variable.

The expression used for the name can be untyped, or it can be either an xs:QName (which is what node-name returns) or an xs:string value. It can even be a node, in which case it is atomized to extract its typed value (not its name).

Default namespace declarations apply to element constructors. If you do not prefix your names, and you declare a default element namespace (e.g., in an outer expression or in the query prolog), the new elements are considered to be in that namespace.

Content of computed element constructors

After the name, the next part of the computed element constructor is an enclosed expression that contains the contents of the element, including attributes, character data, and child elements. As with direct XML constructors, any elements returned by the enclosed expression become children of the new element, attributes become attributes, and atomic values become character data content. Computed constructors have the same rule that the attributes must appear before any elements or character data.

The syntax is slightly different for computed constructors in that there can only be one pair of curly braces, containing the attributes and contents of the element. If several expressions are needed for the attributes, child elements, and character data content, they are separated by commas. For example, when using a direct element constructor, you can construct the li element this way:

<li>number: {data($prod/number)} , name: {data($prod/name)}</li>

where you intersperse literal text and enclosed expressions. To create an identical li element using a computed constructor, you would use the syntax:

element li {"number:", data($prod/number), ", name:", data($prod/name)}

Note that the literal text is in quotes and is separated from the expressions by commas. Also, the expressions, such as data($prod/number), are not themselves enclosed in curly braces as they were with the direct constructor.

The values of each of the four expressions in the li constructor will be separated by spaces in the results. If you do not wish to have those spaces in the results, you can use the concat function to concatenate the values together, as in:

element li {concat("number:", data($prod/number), ", name:", data($prod/name))}

If you want the constructed element to be empty, you can put nothing between the curly braces (as in { }), but the braces are still required.

Computed Attribute Constructors

A computed attribute constructor has syntax identical to a computed element constructor, except that it uses the keyword attribute. Its syntax is shown in Figure 5-3.

Syntax of a computed attribute constructor

Figure 5-3. Syntax of a computed attribute constructor

For example, the constructors:

attribute myattr  { $prod/@dept }

and:

attribute {concat("my", "attr")}  { $prod/@dept }

both construct an attribute whose name is myattr and whose value is the same as the dept attribute of $prod. As with direct attribute constructors, any elements or attributes that are returned by the expression have their values extracted and converted to strings.

Computed attribute constructors are not just for use in computed element constructors. They can be used in direct element constructors as well, if they are included in an enclosed expression. For example, the expression:

<result>{attribute {concat("my", "attr")}  { "xyz" } }</result>

will return the result:

<result myattr="xyz"/>

You cannot construct namespace declarations using computed attribute constructors. If the name specified for an attribute constructor is xmlns, or a name whose prefix is xmlns, an error is raised. For example, the following constructor is invalid:

attribute xmlns:prod { "http://datypic.com/prod" }

Instead, you should declare the namespace in the query prolog or in an outer direct element constructor.

Use Case: Turning Content to Markup

One application of computed constructors is to transform content into markup. For example, suppose you want to create a product catalog that has the names of the departments as element names instead of attribute values. The query in Example 5-14 can be used for this purpose.

Example 5-14. Turning content into markup

Query
for $dept in distinct-values(doc("catalog.xml")/catalog/product/@dept)
return element {$dept}
               {doc("catalog.xml")/catalog/product[@dept = $dept]/name}
Results
<WMN>
  <name language="en">Fleece Pullover</name>
</WMN>
<ACC>
  <name language="en">Floppy Sun Hat</name>
  <name language="en">Deluxe Travel Bag</name>
</ACC>
<MEN>
  <name language="en">Cotton Dress Shirt</name>
</MEN>

In the results, the department names are now element names. The second expression in curly braces returns all the name elements for products in that department.

Computed constructors are also useful to recursively process elements regardless of their name. Example 5-10 showed how to add an id attribute to a product element. Suppose you wanted to add an id attribute to every element in a document, regardless of its name. It is necessary to use computed constructors for this, because you will not know the name of the constructed elements in advance. "Copying Input Elements with Modifications" in Chapter 9 shows some further examples of using computed constructors to generically handle elements with any name.

..................Content has been hidden....................

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