Andy Bisson
Andy Bisson

Reputation: 580

Flattening XML with XQuery

I am trying to flatten an XML hierarchy to the text nodes where the output tag names are the hyphen concatenated tags on the path of each text node. I amusing the sample XML provided at http://www.chilkatsoft.com/xml-samples/bookstore.xml as input.

So far I have created this XQuery:

declare function local:flatten($prefix as xs:string*, $nodes as node()*) as node()*
{
    for $node in $nodes
    return
        typeswitch($node)
            case element() return
                local:flatten(insert-before($prefix, 1, $node/name()), $node/node())
            case text() return
                element {string-join(fn:reverse($prefix), '-')} {string($node)}
            default return
                'oops'      
}; 

for $b in //bookstore/book return 
    local:flatten((), $b)

This mostly works but the output looks like:

<?xml version="1.0" encoding="UTF-8"?>
<book>
</book>
<book-title>The Iliad and The Odyssey</book-title>
<book>
</book>
<book-price>12.95</book-price>
<book>
</book>
<book-comments>
</book-comments>
<book-comments-userComment> Best translation I've read. </book-comments-userComment>
<book-comments>
</book-comments>
<book-comments-userComment> I like other versions better. </book-comments-userComment>
<book-comments>
</book-comments>
<book>
</book>
...

I don't care about the lack of a root element at this time (one step at a time) but I don't want the spurious empty parent tags between the correctly rendered text nodes. What am I doing wrong? I am very new to XQuery and may have made a silly error.

Upvotes: 3

Views: 423

Answers (1)

Joe Wicentowski
Joe Wicentowski

Reputation: 5294

Your XQuery processor is treating the boundary whitespace between elements like <book> and <title> as text nodes. To discard these in your query, you would need to modify the element case in your typeswitch as follows:

case text() return
    if (normalize-space($node) eq "") then 
        ()
    else 
        element {string-join(fn:reverse($prefix), '-')} {string($node)}

Upvotes: 4

Related Questions