tags:

views:

36

answers:

2

Given the following xml input:

<Sections>
 <Section number="1">    
  <Step number="1">
   <SubStep number="1" Pass="True">    
    <SubSubStep number="1" Pass="True"/>        
    <SubSubStep number="2" Pass="True"/>        
   </SubStep>
  </Step>
  <Step number="2">
   <SubStep number="1" Pass="False">       
    <SubSubStep number="1" Pass="True"/>        
    <SubSubStep number="2" Pass="False"/>       
   </SubStep>
  </Step>
 </Section>
</Sections>

How can I transform it to:

<Sections Pass="False">
 <Section number="1" Pass="False">   
  <Step number="1" Pass="True">
   <SubStep number="1" Pass="True">    
    <SubSubStep number="1" Pass="True"/>        
    <SubSubStep number="2" Pass="True"/>        
   </SubStep>
  </Step>
  <Step number="2" Pass="False">
   <SubStep number="1" Pass="False">       
    <SubSubStep number="1" Pass="True"/>        
    <SubSubStep number="2" Pass="False"/>       
   </SubStep>
  </Step>
 </Section>
</Sections>

I want to infer the result of the parent from the children. If any of the children have a Pass="False" result the parent result will be Pass="False". Backwards recursion?

A: 

You can use the ".//node()[ @Pass='True' ]" XPath expression to see if any children of the current node are "True".

David
A: 

You could do it as follows:

  1. Use the identity transform to copy everything from the input to the output, and

  2. for element nodes without a Pass attribute, add it. Set it to False if there is at least one Pass attribute with value False in the children, and to True otherwise.


<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output omit-xml-declaration="yes"/>

  <!-- identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- set missing Pass attribute -->
  <xsl:template match="*[not(@Pass)]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="Pass">
        <xsl:choose>
          <xsl:when test=".//*[@Pass = 'False']">False</xsl:when>
          <xsl:otherwise>True</xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
Jukka Matilainen
thank you. this was exactly what I was looking for
Wouter Roux