XML Editor
Sign up for a WebBoard account Sign Up Keyword Search Search More Options... Options
Chat Rooms Chat Help Help News News Log in to WebBoard Log in Not Logged in
Show tree view Topic
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Postnext
Richard PottsSubject: Filtering XML Elements
Author: Richard Potts
Date: 29 Nov 2006 06:32 AM
Hi. I've got an XML document that contains a set of nodes and elements that may contain child elements <ECUApplicability>

e.g.
<Element_1>
<Bla>…</Bla>
<Bla>…</Bla>
< ECUApplicability>
<ECUVariant>1</ECUVariant>
<ECUVariant>2</ECUVariant>
<ECUVariant>3</ECUVariant>
</ ECUApplicability>
</Element_1>

<Element_2>
<Bla>…</Bla>
<Bla>…</Bla>
</Element_2>

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"



Source XML format:

<Doc>
<Element_1>
<Bla>…</Bla>
<Bla>…</Bla>
<ECUApplicability>
<ECUVariant>1</ECUVariant>
<ECUVariant>2</ECUVariant>
<ECUVariant>3</ECUVariant>
</ ECUApplicability>
</Element_1>

<Element_2>
<Bla>…</Bla>
<Bla>…</Bla>
< ECUApplicability>
<ECUVariant>1</ECUVariant>
<ECUVariant>3</ECUVariant>
</ ECUApplicability>
</Element_2>

<Element_3>
<Bla>…</Bla>
<Bla>…</Bla>
<ECUApplicability>
<ECUVariant>2</ECUVariant>
</ECUApplicability>
</Element_3>

<Element_4>
<Bla>…</Bla>
<Bla>…</Bla>
</Element_4>

</Doc>

Given I pass a "SelectedECUNumber" of 2 to the XSLT

Required Resultant XML file:

<Doc>

<Element_1>
<Bla>…</Bla>
<Bla>…</Bla>
<ECUApplicability>
<ECUVariant>1</ECUVariant>
<ECUVariant>2</ECUVariant>
<ECUVariant>3</ECUVariant>
</ ECUApplicability>
</Element_1>

<Element_3>
<Bla>…</Bla>
<Bla>…</Bla>
< ECUApplicability>
<ECUVariant>2</ECUVariant>
</ ECUApplicability>
</Element_3>

<Element_4>
<Bla>…</Bla>
<Bla>…</Bla>
</Element_4>

</Doc>

Hope that makes sense.
I'm struggling to come up with the solution … any help/clues would be appreciated. Thanks

Postnext
James DurningSubject: Filtering XML Elements
Author: James Durning
Date: 30 Nov 2006 01:39 PM
<xsl:param name="SelectedECUNumber" select="2"/>
<xsl:template match="/Doc">
<xsl:copy>
<xsl:copy-of select="/Doc/*[(not (ECUApplicability/ECUVariant)) or ECUApplicability/ECUVariant[. = $SelectedECUNumber]]"/>
</xsl:copy>
</xsl:template>

Postnext
Richard PottsSubject: 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>


<xsl:template name="FilterNode">
<xsl:param name="Node"></xsl:param>
<xsl:param name="Filter"></xsl:param>

<xsl:for-each select="./*">
<xsl:choose>

<!--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) &gt; 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>

<!--Contains ECU Applicablity so Filter -->
<xsl:when test=".//ECUApplicability[ECUVariant = $Filter]">
<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>
</xsl:template>
</xsl:stylesheet>

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

Postnext
James DurningSubject: 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:

<xsl:template match="/Generic_Part_II">
<xsl:copy>
<xsl:copy-of select="*[(not (.//ECUApplicability)) or .//ECUApplicability/ECUVariant[. = $SelectedECUNumber]]"/>
</xsl:copy>
</xsl:template>


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="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="*[contains(name(), 'Element']">
<xsl:if test="(not (.//ECUApplicability)) or .//ECUApplicability/ECUVariant[. = $SelectedECUNumber]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>

3. A third option, is that you want to eliminate nodes only if they contain a ECUApplicability child which doesn't meet criteria. You then have:

<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

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

Hopefully one of these works for you.

Posttop
Richard PottsSubject: Filtering XML Elements
Author: Richard Potts
Date: 13 Dec 2006 10:19 AM
Thanks very much James. Your 'option 3' was the one I was looking for. :-)

 
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Download A Free Trial of Stylus Studio 6 XML Professional Edition Today! Powered by Stylus Studio, the world's leading XML IDE for XML, XSLT, XQuery, XML Schema, DTD, XPath, WSDL, XHTML, SQL/XML, and XML Mapping!  
go

Log In Options

Site Map | Privacy Policy | Terms of Use | Trademarks
Stylus Scoop XML Newsletter:
W3C Member
Stylus Studio® and DataDirect XQuery ™are from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2016 All Rights Reserved.