## 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: "Simon Shutter" Date: Sun, 24 Jun 2007 22:16:07 -0700
```This post refers to a question I posed back on April 19th and the suggested
transformations that Michael Kay and Ken Holman generously provided.

Michael provided two slightly different solutions to cover some ambiguity in
my
question.  When I run his solutions, however, I get different results than I
expected and wonder if I am implementing them incorrectly or if my statement
of the problem was unclear.  I have since revised the summary of the problem
for hopefully better clarity and also edited the data file to remove what I
believe are redundant attributes.

I'm hoping to try and resolve why I can't get Michael's solutions to work.

Simon

**************************************************************************
Summary of Problem
**************************************************************************
(thanks to Trevor Nicholls and Ragulf Pickaxe back in April for their help)

There is a structure tree (in.xml) and a data tree (data.xml) - see examples
below.  The structure tree is fixed and complete.  The data tree is variable
and may contain any element which corresponds to a descendant-less node
(leaf node) in the structure tree (at most one of each element).

The desired output is a merge of the structure tree and the data tree,
where:
a) for any specific leaf node in the structure tree:
(i) if the data tree contains a matching node with @result=true
then @complete=true and @result=true,
(ii) if the data tree contains a matching node with @result=false
then @complete=true and @result=false, and
(iii) if the data tree does not contain a matching node
then @complete=false and @result=true (because I do not want
to affect the logical AND value of ancestor nodes' @result value
when they include leaf nodes with @complete=false - see b) (iii) below

b) for every other internal node in the structure tree:
(i) if the data tree contains a matching node for every leaf node in the
structure tree (that is descendent of this internal node) and each
matching node has @result=true then for this internal node
@complete=true and @result=true,
(ii) similarly, if the data tree contains a matching node for every leaf
node in the structure tree but not all results are true then for this
internal node @complete=true and @result=false,
(iii) if the data tree does not contain a matching node for every leaf
node in the structure tree but the value of each matching node that it
does contain has @result=true then for the internal node
@complete=false and @result=true,
(iv) if the data tree does not contain a matching node for every leaf
node in the structure tree and the value of any matching node that it
does contain has @result=false then @complete=false and @result=false

**************************************************************************
Example structure tree (in.xml)
**************************************************************************
<a>
<b>
<c/>
<d/>
</b>
<e>
<f/>
<g>
<h/>
<i/>
</g>
</e>
</a>

**************************************************************************
Example data tree (data.xml)
**************************************************************************
<data>
<c result="true"/>
<d result="false"/>
<h result="true"/>
<i result="true"/>
</data>

**************************************************************************
Example desired result
**************************************************************************

<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="true"/>
<g complete="true" result="true"/>
<h complete="true" result="true"/>
<i complete="true" result="true"/>
</g>
</e>
</a>

**************************************************************************
Michael's first stylesheet (mkay1.xsl)

- non-leaf nodes look at all descendants
**************************************************************************

<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>

**************************************************************************
Output I get from Michael's first stylesheet (mkay1.xml)

- node e should have result="true" because none of its descendent
nodes have result="false"
- not sure how \$tree is used
**************************************************************************

<?xml version="1.0" encoding="UTF-8"?>
<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="false"> <!-- @result should be true -->
<f complete="false" result=""/>
<g complete="true" result="true">
<h complete="true" result="true"/>
<i complete="true" result="true"/>
</g>
</e>
</a>

**************************************************************************
Michael's second stylesheet (mkay2.xsl)

- non-leaf nodes should only look at leaf node descendants
**************************************************************************

<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
(* 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>

<!-- 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>

**************************************************************************
Output from Michael's second stylesheet (mkay2.xml)

- nodes a and b should have @result=false because node d has
@result=false
- node e should have @complete=false because node f is missing from
data.xml
- not sure how \$tree is used
**************************************************************************

<?xml version="1.0" encoding="UTF-8"?>
<a complete="true" result="true"> <!-- @result should be false -->
<b complete="true" result="true"> <!-- @result should be false -->
<c complete="true" result="true"/>
<d complete="true" result="false"/>
</b>
<e complete="true" result="true"> <!-- @complete should be false -->
<f complete="false" result=""/>
<g complete="true" result="true">
<h complete="true" result="true"/>
<i complete="true" result="true"/>
</g>
</e>
</a>

```