[xquery-talk] creating tree from sequence (from tree)

G. Ken Holman gkholman at CraneSoftwrights.com
Sat May 7 05:16:17 PDT 2011


At 2011-05-06 16:29 -0700, trubliphone wrote:
>I have an algorithmic problem I haven't been able to solve.  I was
>hoping somebody on this list could offer me some advice.
>
>Suppose I have some arbitrary XML file:

Given the nested in this file, I was immediately drawn to using XSLT 
and not XQuery.  After solving the problem very succinctly in XSLT, 
that guided me in the writing of an XQuery solution.

>Now, suppose there is a user-provided XPath expression to find
>particular nodes in that file:
>
>$query := "//foo/bar"

My solution is not so parameterized because neither XSLT nor XQuery 
have an eval() that would allow such an XPath expression to be 
dynamically evaluated as either a select expression or a match 
expression.  Plus, I think starting at the bar elements presupposes 
an inefficient pull-style solution rather than a push-style solution.

So you can ignore my answer if you wish, but for a push-style 
solution, please see the code below.

>My question is how to turn that into a tree that recreates the
>original hierarchical structure?

I think it is more efficient to work from the original hierarchical 
structure and create the tree that you need.

I hope you find the solutions below helpful.

. . . . . . . . .  Ken

T:\ftemp>type t.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
     <foo>
         <bar>one</bar>
         <foo>
             <bar>two</bar>
         </foo>
         <foo>
             <bar>three</bar>
         </foo>
     </foo>
     <foo>
         <bar>four</bar>
         <foo>
             <foo>
                 <bar>five</bar>
             </foo>
         </foo>
     </foo>
</root>
T:\ftemp>xquery t.xq
<?xml version="1.0" encoding="UTF-8"?>
<bar>one<bar>two</bar>
    <bar>three</bar>
</bar>
<bar>four<bar>five</bar>
</bar>
T:\ftemp>type t.xq
declare function local:match( $nodes as node()* ) as node()*
  {
   for $node in $nodes return
     typeswitch( $node )
       case element(foo) return if( $node/bar )
                                then <bar>
                                     {local:match(($node/bar/node(),$node/foo))}
                                     </bar>
                                   else local:match( $node/foo )
       default return if( $node/self::text()/parent::bar ) then $node else ()
  };

local:match( doc('t.xml')/root/* )
T:\ftemp>xslt t.xml t.xsl
<?xml version="1.0" 
encoding="utf-8"?><bar>one<bar>two</bar><bar>three</bar></bar><bar>four<bar>five</bar></bar>
T:\ftemp>type t.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 version="1.0">

<xsl:template match="root/text() | foo/text()"/>

<xsl:template match="foo[bar]">
   <bar>
     <xsl:apply-templates select="bar/node()"/>
     <xsl:apply-templates select="foo"/>
   </bar>
</xsl:template>

</xsl:stylesheet>
T:\ftemp>



--
Contact us for world-wide XML consulting & instructor-led training
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/q/
G. Ken Holman                 mailto:gkholman at CraneSoftwrights.com
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal



More information about the talk mailing list