RE: [xsl] Constructing a tree from leaf nodes (knowing the tree structure)?

Subject: RE: [xsl] Constructing a tree from leaf nodes (knowing the tree structure)?
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Fri, 20 Apr 2007 08:49:18 +0100
OK, so you have two rules, one for leaf nodes and one for non-leaf nodes.
Something like this:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:output indent="yes"/>

<xsl:variable name="tree" select="/"/>
<xsl:variable name="data" select="doc('data.xml')/data"/>

<!-- rule for non-leaf nodes -->

<xsl:template match="*[*]">
  <xsl:copy>
    <xsl:attribute name="complete" 
       select="every $n in descendant::* satisfies 
                 exists($data/*[name() = name($n)])"/>
    <xsl:attribute name="result"
           select="every $n in descendant::* satisfies 
                 exists($data/*[name() = name($n) and @result='true']) "/>
    <xsl:apply-templates/>             
  </xsl:copy>
</xsl:template>

<!-- rule for leaf nodes -->

<xsl:template match="*">
  <xsl:copy>
    <xsl:attribute name="complete" 
       select="exists($data/*[name() = name(current())])"/>
    <xsl:attribute name="result"
           select="$data/*[name() = name(current())]/@result"/>
    <xsl:apply-templates/>             
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

This actually gives the right answer, but it's possible that the rule for
non-leaf nodes should only look at leaf descendants, not at all descendants,
which would change it to:

<xsl:template match="*[*]">
  <xsl:copy>
    <xsl:attribute name="complete" 
       select="every $n in descendant::* satisfies 
                 (* or exists($data/*[name() = name($n)]))"/>
    <xsl:attribute name="result"
           select="every $n in descendant::* satisfies 
                 (* or exists($data/*[name() = name($n) and
@result='true']))"/>
    <xsl:apply-templates/>             
  </xsl:copy>
</xsl:template>

Michael Kay
http://www.saxonica.com/

> Thanks, Michael.
> 
> The "complete" attribute signifies whether all required 
> descendent nodes are present or not.  For a leaf node I 
> assume that if it is present complete="true" and if it is 
> absent complete="false".  Hence f has complete="false".  I 
> agree it is redundant for the data elements c,d,h and i to 
> have complete="true" but I need the attribute to be present 
> to that I can style the tree in HTML.
> 
> As far as the ancestors go, b is complete because all its 
> descendants are complete, while e and a are incomplete 
> because some of their descendants are incomplete.
> 
> Simon
> 
> 
> -----Original Message-----
> From: Michael Kay [mailto:mike@xxxxxxxxxxxx]
> Sent: April 19, 2007 4:14 PM
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: RE: [xsl] Constructing a tree from leaf nodes 
> (knowing the tree structure)?
> 
> XSLT is certainly suited to the problem. However, I can't 
> reverse engineer your requirements from your example. The 
> following stylesheet comes close, and there are various ways 
> I could refine it to produce your required output, but I'd be 
> using guesswork as to what the requirements are, so it would 
> be better if you do that yourself! In particular I can't see 
> why you consider b to be complete while f is incomplete, and 
> since all the data elements say complete="true", it's hard to 
> see what role that attribute plays in the calculation.
> 
> I used your tree as the principal input, and wrapped the 
> other nodes in a <data> element and called it data.xml. The 
> stylesheet is:
> 
> <xsl:stylesheet version="2.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> 
> <xsl:output indent="yes"/>
> 
> <xsl:variable name="tree" select="/"/>
> <xsl:variable name="data" select="doc('data.xml')/data"/>
> 
> <xsl:template match="*">
>   <xsl:copy>
>     <xsl:attribute name="complete" 
>        select="every $n in descendant::* satisfies 
>                  exists($data/*[name() = name($n)])"/>
>     <xsl:attribute name="result"
>            select="every $n in descendant::* satisfies 
>                  exists($data/*[name() = name($n) and 
> @result='true']) "/>
>     <xsl:apply-templates/>             
>   </xsl:copy>
> </xsl:template>
> 
> </xsl:stylesheet>         
> 
> Michael Kay
> http://www.saxonica.com/ 
> 
> > -----Original Message-----
> > From: Simon Shutter [mailto:simon@xxxxxxxxxxx]
> > Sent: 19 April 2007 21:02
> > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> > Subject: [xsl] Constructing a tree from leaf nodes (knowing 
> the tree 
> > structure)?
> > 
> > This is probably a poorly posed question but essentially I 
> am trying 
> > to determine if XSLT is suited to the following problem.
> > 
> > Say I have a node fragment that defines a tree structure in 
> which each 
> > element appears only once eg.
> > 
> > <a>
> >   <b>
> >     <c/>
> >     <d/>
> >   </b>
> >   <e>
> >     <f/>
> >     <g>
> >       <h/>
> > 	<i/>
> >     </g>
> >   </e>
> > </a>
> > 
> > I then have data for some of the leaf nodes ie.
> > 
> > <c complete="true" result="true"/>
> > <d complete="true" result="false"/>
> > <h complete="true" result="true"/>
> > <i complete="true" result="true"/>
> > 
> > In this example the leaf node </f> is missing.
> > 
> > Is it possible to create a node fragment that mimics the tree 
> > structure and sets ancestor attributes according to the presence or 
> > absence of leaf nodes and their attributes?
> > 
> > The desired output would be:
> > 
> > <a complete="false" result="false">
> >   <b complete="true" result="false">
> >     <c complete="true" result="true"/>
> >     <d complete="true" result="false"/>
> >   </b>
> >   <e complete="false" result="true"> 
> >     <f complete="false" result=""/>
> >     <g complete="true" result="true"/>
> >       <h complete="true" result="true"/>
> >       <i complete="true" result="true"/>
> >     </g>
> >   </e>
> > </a>

Current Thread