Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old July 31st, 2012, 06:05 AM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default Getting rid of Duplicate nodes

Hello Everyone,

I have pretty similar looking problem which have got many solutions over the web but none of them have worked well for me so far. Here's the problem statement:

XML file version "1.0":
<enums>
<enum name="enumOne">
<val v="1"/>
</enum>
<enum name="enumTwo">
<val v="2"/>
</enum>
<enum name="enumThree">
<val v="3"/>
</enum>

<table>
<child name="child1">
<type t="enumOne"/>
..........
.........
</child>
<child name="child2">
<type t="enumTwo"/>
..........
.........
</child>
<child name="child3">
<type t="enumOne"/>
..........
.........
</child>
</table>

XSL version "1.0": It would traverse through child node and retrieve the enum type i.e. enumXXX from <type> tag. and find it's definition from <enums>

<xsl:for-each select="/child/type">
<xsl:call-template name="getenumdefs">
<xsl:with-param name="enumname">
<xsl:value-of select="@t"/>
</xsl:with-param>
</xsl:call-template>
<xsl:for-each>

<xsl:template name="getenumdefs">
<xsl:param name="enumname"/>
<xsl:for-each select="/enums/enum">
<xsl:if test="$enumname = '$name'">
<xsl:value-of select="val/@v"/>
</xsl:if>
</xsl:for-each>

Problem with this approach is, it would print the duplicate entries for "enumOne" as both child1 and child3 uses it. There are multiple solutions available in the form of preceding-sibling or checking generate-id(), but nothing had really worked well for this xml/xsl. Appreciate if anyone can provide any inputs/suggestions.

Last edited by sureshvadali; August 1st, 2012 at 04:44 AM..
 
Old July 31st, 2012, 06:32 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Are you constrained to use XSLT 1.0? Are you familiar with Muenchian grouping?
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old July 31st, 2012, 07:03 AM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default

The other alternative could be: create a flag variable for the first occurrence of enum and flag it. The subsequent calls to the template getenumdefs would check if the flag is set for the respective enum and skip it if flagged. But am not sure about the feasibility of such implementation in XSL.
 
Old July 31st, 2012, 07:25 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Flag variables? No, you are thinking much too procedurally.

Why didn't you answer my questions?
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old August 1st, 2012, 09:06 AM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Sorry Michael, I replied to my original thread instantly after posting it, but it seems there was a delay in capturing it into the thread. I just saw your responses, thanks for that. Right most of XSL's have been written in 1.0 and the source XML also adheres to 1.0 version moving to 2.0 might be tricky?

Though am not familiar about Muenchian grouping but I went through some examples and figured out the below approach:

<xsl:key name="attrenum" match="type" use="@t" />
<xsl:template match="/root/parent">
<xsl:for-each select="table">
<xsl:variable name="tab">
<xsl:value-of select="@name"/>
</xsl:variable>
<xsl:if test="$tab= 'two'"> <-- I added a name to the table with "one" "two" ..
<xsl:variable name="attribute">
<xsl:value-of select="@name"/>
</xsl:variable>
<xsl:for-each select="child">
<xsl:for-each select="type[count(. | key('attrenum', @t)[1]) = 1]">
<xsl:value-of select="@t" /> <br/>
</xsl:for-each>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>

But it fails if the table being searched is deep.
 
Old August 1st, 2012, 09:32 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

If your only reason for not moving to XSLT 2.0 is that you think it might be tricky, then make the move. Any time it takes will be repaid amply within a couple of weeks.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old August 2nd, 2012, 09:06 AM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default

I gave some thoughts to the challenges arriving out of XSLT 1.0 for this problem and eventually made up my mind to move on to XSLT 2.0. With some web search I found out that xsl:for-each-group or distinct-values() could be an alternative, do you have any other better options to suggest?

for-each-group:

<xsl:for-each-group select="//type" group-by="@t">
<xsl:copy-of select="current-group( )[1]"/>
</xsl:for-each-group>




distinct-values():

<xsl:for-each select="distinct-values(type/@t)">
<xsl:sort/>
<xsl:value-of select="."/> <xsl:call-template name="newline"/>
</xsl:for-each>

But I think both are flawed, anything needs to be corrected in the above statements?

Thanks
 
Old August 2nd, 2012, 09:13 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

As far as I can see you haven´t really explained what result you want. Your attempt with for-each-group looks fine to group "type" elements by the "t" attribute value and to extract the first item in each group, although doing
Code:
<xsl:copy-of select="."/>
suffices instead of the current-group()[1] you have.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
The Following User Says Thank You to Martin Honnen For This Useful Post:
sureshvadali (August 3rd, 2012)
 
Old August 2nd, 2012, 02:26 PM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Thanks Martin for the response, my intention is to identify first occurrence of @t attribute in the group, but it has given an empty output, the XML which I mentioned out here is little simple and is just a prototype. The XSL used here is applied on a complex XML file which has got ~250 "type" elements something similar to:
Code:
<root>
  <parent>
	<table>
	<attr ......>
	   <type t="enumone">
	   <info>
		<name .....>
	   </info>
	</attr>

	<attr>
	    <type t="int">
		<range min="1" max="255"/>
	     </type>
	     <info>
		<name .....>
	   </info>
	</attr>

	<attr>
	    <type t="string">
	     <info>
		<name .....>
	   </info>
	</attr> 
	<attr ......>
	   <type t="enumtwo">
	   <info>
		<name .....>
	   </info>
	</attr>

	<attr>
	    <type t="float">
		<range min="1.0" max="25.5"/>
	     </type>
	     <info>
		<name .....>
	   </info>
	</attr>

	<attr>
	    <type t="int">
	     <info>
		<name .....>
	   </info>
	</attr> 


	<attr>
	    <type t="enumone">
	     <info>
		<name .....>
	   </info>
	</attr> 
	<attr>
	    <type t="enumthree">
	     <info>
		<name .....>
	   </info>
	</attr> 
	<attr>
	    <type t="enumone">
	     <info>
		<name .....>
	   </info>
	</attr> 
    </parent>
 </root>
 
Old August 3rd, 2012, 04:59 AM
Registered User
 
Join Date: Jul 2012
Posts: 9
Thanks: 1
Thanked 0 Times in 0 Posts
Default

The expected output is:

enumone
int
string
enumtwo
float
enumthree





Similar Threads
Thread Thread Starter Forum Replies Last Post
removing duplicate elements and collecting all sub nodes together john007 XSLT 1 March 9th, 2012 05:09 PM
removing duplicate nodes nguna XSLT 6 February 16th, 2009 10:40 AM
How do you get Rid of quotes hewstone999 Access VBA 1 April 15th, 2008 10:42 AM
Removing duplicate nodes post-process QuickSilver002 XSLT 3 April 4th, 2007 03:47 PM
Duplicate nodes get the value from first node dev.user06 XSLT 6 August 8th, 2006 11:33 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.