Which means that 'Element_1' is valid for ECU Variants 1, 2, and 3 and Element_2 is valid for all ECU types as it does not have an ECUApplicablity child.
I'm trying to write an XSLT that will 'filter' my XML file to produce an new XML file that contains all element that do not have a child element <ECUApplicability> (as these are applicable to all variants) AND all those elements that have a child element <ECUApplicability> that are applicable to a particular ECU type.
I'm passing a parameter to the XSL file. "SelectedECUNumber"
Subject:Filtering XML Elements Author:Richard Potts Date:01 Dec 2006 07:25 AM
Thanks James. I've ran your solution doesn't work on my real data set . But I figured out that's because my problem was not defined well enough. - Sorry.
i.e.
The <ECUApplicablity> is not always at the same level in the tree stucture. it can be at any level of the tree structure.
e.g.
<Doc>
<Element1>
<Bla1>
<Bla2>
<Bla3>
<ECUApplicablity>
or
<Element2>
<Bla5>
<ECUApplicablity>
or
<Element3>
<Bla1>
<Bla2>
<Bla3>
<Bla4>
<ECUApplicablity>
I've been working on this problem for a couple of days now and the solution I've got so far is:
************************
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="ECUFilterValue"></xsl:param>
<xsl:template match="/Generic_Part_II">
<Generic_Part_II>
<xsl:for-each select="./*">
<xsl:choose>
<!--Top level node does not have any ECU Applicablity so echo to output-->
<xsl:when test="not(.//ECUApplicability)">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:when>
<!--Contains ECU Applicablity so Filter -->
<xsl:when test=".//ECUApplicability[ECUVariant = $ECUFilterValue]">
<xsl:element name="{name(.)}">
<xsl:call-template name="FilterNode">
<xsl:with-param name="Node" select="."></xsl:with-param>
<xsl:with-param name="Filter" select="$ECUFilterValue"></xsl:with-param>
</xsl:call-template>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</Generic_Part_II>
</xsl:template>
<!--If ECUApplicablity at node and is applicable then echo -->
<xsl:when test="./ECUApplicability[ECUVariant = $Filter]">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:when>
<!--If ECUApplicablity is empty then echo -->
<xsl:when test="(count(./ECUApplicability) > 0) and (count(./ECUApplicability/ECUVariant) = 0)">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:when>
<!--If ECUApplicablity at node and not applicable then do nothing-->
<!-- <xsl:when test="not(./ECUApplicability[ECUVariant = $Filter])">
</xsl:when>-->
<!--Copy all nodes and sub-nodes inf no ECU applicability-->
<xsl:when test="not(.//ECUApplicability)">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:when>
***********
I'm in the process of tying to prove that it has worked. I not sure I've created a general solution. And I'm sure there is a more elegant solution out there (similar to your 'one liner') - can your one -liner be cleverly adapted to work at any level where ECUApplicability occurs.
Subject:Filtering XML Elements Author:James Durning Date:01 Dec 2006 02:05 PM Originally Posted: 01 Dec 2006 02:00 PM
1. Changing the xpath to .// (meaning descendants of the current node), this copies the root node, and all children of the root node that have the ECU applicability meeting the requirements. We get:
2. Perhaps however, you wish to seperate the copied parts by Elements. Copy the surrounding structure around the Elements, if they are not the immediate children of the root node.
<xsl:template match="*[ECUApplicability]"><!-- match all nodes with an ECUApplicability child -->
<xsl:if test="ECUApplicability/ECUVariant[. = $SelectedECUNumber]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>