We will now use XQuery query (shown in Example 6.4) to produce the compact form of an XML file. The output of this transformation will only be a stream of plain characters without any tags. This shows that XQuery can be used to produce a text file.
The algorithm given in Example 6.4 follows the same pattern as the one
explained in Section 6.1.3. We recursively follow the structure of the
tree and output a corresponding stream of characters. Sequences of character elements are
always embedded within a concat
function so that spurious spaces are not added
between them. The element
function starting on line 29‑ is applied to all element nodes: we output the name
of the element and then output its attributes and children, with an indentation
corresponding to the number of characters in the name of the parent element. The root node
has an indentation of 0. Because we want an output with few blank lines, we only change line
after having written the first attribute or child element. This is implemented within the
loop on each child and attribute. Because XQuery explicitly pulls
the input tokens from the input, this test can be done at only one place in the program
contrarily to the XSLT program in Example 5.9 which uses a push
approach and thus must test its position in each case. We could also have used the pull
approach in XSLT, but the push approach is more natural in XSLT because
of the implicit application of templates according to the structure of the document.
For each child node and attribute returned in document order, we call the appropriate function depending on the type of node.
On line 21‑, we define the function to output the value of
an attribute, which is simply the name of the attribute preceded by an
@
and followed by its value in square brackets.
On line 25‑, we output the value of the current node with
all extraneous space removed using the
normalize-space
function. This removes
all whitespace at the start and at the end of the value and leaves only one space between
non-space characters. Because the strip-space
function
(line 5‑) will have been called on the input document before processing,
nodes containing only newlines and spaces will not appear in the source tree.
To output a given number of spaces, we have defined a function
called nl-and-indent
(line 17‑) taking one parameter
used to create a sequence of spaces, which are joined into one string preceded by a newline.
Example 6.4. [compact.xq
]: Stylesheet used to transform the cellar book
instance document (Example 2.2) into
Example 5.8. Compare this with Example 5.9.
1 declare option saxon:output "method=text";declare option saxon:output "omit-xml-declaration=yes"; (: remove all whitespace nodes from elements of the input tree :) 5 declare function local:strip-space($element){
element {local-name($element)} { $element/@*, for $child in $element/node() return if ($child instance of text() and normalize-space($child)='') 10 then () else if ($child instance of element()) then local:strip-space($child) else $child } 15 }; declare function local:nl-and-indent($nb){
concat('
',string-join(for $i in 1 to $nb return ' ','')) }; 20 declare function local:attribute($attribute){
concat('@',local-name($attribute),'[',data($attribute),']') }; 25 declare function local:text($text){
normalize-space($text) }; declare function local:element($elem,$indent){
30 let $newName := local-name($elem), $newIndent := $indent+string-length($newName)+1 return concat( $newName,"[", 35 string-join( for $child at $pos in $elem/(@*|*|text()) return ( if($pos>1) then local:nl-and-indent($newIndent) 40 else (), typeswitch ($child)
case attribute() return local:attribute($child) case text() return local:text($child) case element() return local:element($child,$newIndent) 45 default return () ),""), "]" ) }; 50 local:element(local:strip-space(/*),0)
![]()
|
Indicates that the output will be plain text, thus we do not want an XML declaration to be emitted. |
|
Function to remove all whitespace-only nodes in an element because we are only interested in the content of the input document, not its structure. |
|
Function for outputting a number of spaces given by the |
|
For an attribute, outputs the name of the attribute preceded by
an |
|
For a text node, outputs its normalized value, i.e. removes the surrounding spaces and line breaks. |
|
For an element, first outputs the element name followed by an opening bracket. It then recursively calls the compaction of attributes, children and text nodes. Finally a closing bracket is output. If there are any attributes and this element is not the first one, indent the following line. |
|
Depending on the type of the child node, calls the appropriate function.
in the case of an element node, does a recursive call to
|
|
At the root, starts to apply the compaction algorithm with an indentation of 0. |