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: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Thu, 19 Apr 2007 16:43:41 -0400
At 2007-04-19 13:01 -0700, Simon Shutter wrote:
This is probably a poorly posed question but essentially I am trying to
determine if XSLT is suited to the following problem.

Giving all inputs and expected output is a great start. All I had to guess was what the value of result= is supposed to be ... I've assumed it is a logical and of descendent result= attributes.


Say I have a node fragment that defines a tree structure in which each
element appears only once eg.
...
I then have data for some of the leaf nodes ie.
...
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>

The example below appears to do what you want ... what was it about XSLT processing that you wanted to know to measure suitability? What is nice about XSLT is its node orientation and use of the descendant axis, which I took advantage of. I haven't tried the answer with XSLT 1, the answer below uses XSLT 2.


Someone else on the list might have a more compact solution than mine.

I hope this helps.

. . . . . . . . . . . Ken


T:\ftemp>call xslt2 shutter.xml shutter.xsl shutter.out


T:\ftemp>type shutter.out
<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>
T:\ftemp>type leaves.xml
<leaves>
<c complete="true" result="true"/>
<d complete="true" result="false"/>
<h complete="true" result="true"/>
<i complete="true" result="true"/>
</leaves>

T:\ftemp>type shutter.xml
<a>
  <b>
    <c/>
    <d/>
  </b>
  <e>
    <f/>
    <g>
      <h/>
      <i/>
    </g>
  </e>
</a>

T:\ftemp>type shutter.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="2.0">

<xsl:output omit-xml-declaration="yes"/>

<xsl:key name="leaves" match="*[not(*)]" use="name(.)"/>

<xsl:variable name="leaves" select="document('leaves.xml')"/>

<xsl:template match="*">
  <xsl:copy>
    <xsl:attribute name="complete">
      <xsl:choose>
        <!--at a leaf use the value from leaves, or 'false' if not there-->
        <xsl:when test="not(*)">
          <xsl:value-of select="( key('leaves',name(.),$leaves)/@complete,
                                  'false' )[1]"/>
        </xsl:when>
        <!--at a branch, check all leaves for any not being in leaf file-->
        <xsl:when test=".//*[not(*)][not(key('leaves',name(.),$leaves))]"
                      >false</xsl:when>
        <!--there are no absent leaves, so this is complete-->
        <xsl:otherwise>true</xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:attribute name="result">
      <xsl:choose>
        <!--at a leaf, use the value from leaves, or '' if not there-->
        <xsl:when test="not(*)">
          <xsl:value-of select="key('leaves',name(.),$leaves)/@result"/>
        </xsl:when>
        <!--at a branch, check all leaves for any being false-->
        <xsl:when test=".//*[not(*)]/key('leaves',name(.),$leaves)/@result =
                        'false'">false</xsl:when>
        <!--there are none that are false, so then all must be true-->
        <xsl:otherwise>true</xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
T:\ftemp>rem Done!

--
World-wide corporate, govt. & user group XML, XSL and UBL training
RSS feeds:     publicly-available developer resources and training
G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
Box 266, Kars, Ontario CANADA K0A-2E0    +1(613)489-0999 (F:-0995)
Male Cancer Awareness Aug'05  http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

Current Thread