[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Trouble removing dup elements based on attributes

Subject: Re: Trouble removing dup elements based on attributes
From: "Al Bean" <albean88@xxxxxxxxxxx>
Date: Sat, 25 Jun 2005 15:25:16 +0000
xpath transform removing duplicate elements
Thanks, Sam.

I now have a better understanding of the difference between preceding and preceding-sibling. And I see how that works whereas my attempt did not. Also, one of my big mistakes was using attrib[@name='Names']/rs/row/@firstname rather than just row/@firstname as you pointed out. Thanks.

Ive extended my problem now to include more than one attribute and Ive run into trouble, again. Im not sure if it is because I dont understand the specifics of logical operators in XPath or the specifics of preceding-sibling. (probably both :-) though)

Now I would like to test against firstname AND lastname.
(so I would like to have the second product node in my out to be:
Sam
Ron
Sam
Because each Sam has a different last name.)

These test fail:
<xsl:if test=" not(@firstname=preceding-sibling::row/@firstname) and not(@ln=preceding-sibling::row/@ln) ">


<xsl:if test=" not(@firstname=preceding-sibling::row/@firstname and @ln=preceding-sibling::row/@ln) ">

I dont see why these should fail. It makes sense that if one of these fails the other should since they are logically equivalent. But I do see why this logic fails, basically what I (think I) am saying is if the current row matches a previous siblings lastname AND first name then reject it. How do I check against two (or more) attributes?

-------------------------------------
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:ns="http://w.ns.c/ns/prod/">
    <xsl:template match="/">
        <Products>
            <xsl:apply-templates/>
        </Products>
    </xsl:template>

<xsl:template match="product">
<Product>
<Names>
<xsl:apply-templates mode="XXX" select="attrib[@name='Names']/rs/row"/>
</Names>
</Product>
</xsl:template>


<xsl:template mode="XXX" match="attrib[@name='Names']/rs/row">
<xsl:if test=" not(@firstname=preceding-sibling::row/@firstname) and not(@ln=preceding-sibling::row/@ln) ">
<name>
<xsl:value-of select="@firstname"/>
</name>
</xsl:if>
</xsl:template>
</xsl:transform>


-------------------------------------
<prods>
	<product>
		<attrib name="P">product 1</attrib>
		<attrib name="Names">
			<rs>
				<row ln="xxx" firstname="Bill"/>
				<row ln="xxx" firstname="Bill"/>
			</rs>
		</attrib>
	</product>
	<product>
		<attrib name="P">product 2</attrib>
		<attrib name="Names">
			<rs>
				<row ln="qqq" firstname="Sam"/>
				<row ln="xxx" firstname="Ron"/>
				<row ln="xxx" firstname="Sam"/>
				<row ln="xxx" firstname="Ron"/>
			</rs>
		</attrib>
	</product>
	<product>
		<attrib name="P">product 3</attrib>
		<attrib name="Names">
			<rs>
				<row ln="xxx" firstname="Ron"/>
				<row ln="xxx" firstname="Sam"/>
				<row ln="xxx" firstname="Joe"/>
				<row ln="xxx" firstname="Sam"/>

			</rs>
		</attrib>
	</product>
</prods>


From: "Sam D. Chuparkoff" <sdc@xxxxxxxxxx>
Reply-To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re:  Trouble removing dup elements based on attributes
Date: Fri, 24 Jun 2005 18:40:18 -0700

Hey, 'Sam', that's me.

On Fri, 2005-06-24 at 23:14 +0000, Al Bean wrote:
> Hi,
>
> I just started using XSLT today and I'm trying to figure out how to get rid
> of some duplicated elements. I know that I need to do something to the
> "XXX" template but I am not sure what to do.
>
> I've tried this for the XXX template but it does not work:
> <xsl:template mode="XXX" match="attrib[@name='Names']/rs/row">
> <xsl:if test="not(@firstname =
> preceding::attrib[@name='Names']/rs/row/@firstname)">
> <xsl:element name="ns:name">
> <xsl:value-of select="@firstname"/>
> </xsl:element>
> </xsl:if>
> </xsl:template>


You should include output using this template and explain why it
confuses you.

>From the xpath spec (1.0):

  the preceding axis contains all nodes in the same document as the
  context node that are before the context node in document order,
  excluding any ancestors and excluding attribute nodes and namespace
  nodes

So preceding::attrib[@name='Names'] won't match the ancestor attrib of
the current row. It will match all previous attrib[@name='Names'] in
the document. But this means matching attrib s from other products,
which clearly isn't what you want.

If all the rows you need to consider are really siblings (as in your
input), your test should be:

not(@firstname=preceding-sibling::row/@firstname)

Also, I don't know why you're using xsl:element most (but not all) of
the time. Don't use xsl:element unless you have to (which means: unless
you don't know the name of the element).

And you might like to look into trying:

 <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns="http://w.ns.c/ns/prod/">

And then just writing:

<Products/>

Just didn't want you to assume namespaces have to be so clunky.

There are some faqs about removing duplicates here:

http://www.dpawson.co.uk/xsl/sect2/N2696.html

sdc

>
> Thanks in advance for any help.
>
>
>
>
> ----------------------
> My XSL
> ----------------------
>
> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="1.0" xmlns:ns="http://w.ns.c/ns/prod/">
>     <xsl:template match="/">
>         <ns:Products>
>             <xsl:apply-templates/>
>         </ns:Products>
>     </xsl:template>
>
>     <xsl:template match="product">
>         <xsl:element name="ns:Product">
>             <xsl:element name="ns:Names">
>                 <xsl:apply-templates mode="XXX"
> select="attrib[@name='Names']/rs/row"/>
>             </xsl:element>
>         </xsl:element>
>     </xsl:template>
>
>     <xsl:template mode="XXX" match="attrib[@name='Names']/rs/row">
>         <xsl:element name="ns:name">
>             <xsl:value-of select="@firstname"/>
>         </xsl:element>
>     </xsl:template>
> </xsl:transform>
>
>
> ----------------------------------------------------
> Input XML :
> ----------------------------------------------------
>
> <prods>
>     <product>
>         <attrib name="P">product 1</attrib>
>         <attrib name="Names">
>             <rs>
>                 <row firstname="Bill"/>
>                 <row firstname="Bill"/>
>             </rs>
>         </attrib>
>     </product>
>     <product>
>         <attrib name="P">product 2</attrib>
>         <attrib name="Names">
>             <rs>
>                 <row firstname="Sam"/>
>                 <row firstname="Ron"/>
>                 <row firstname="Sam"/>
>                 <row firstname="Ron"/>
>             </rs>
>         </attrib>
>     </product>
>     <product>
>         <attrib name="P">product 3</attrib>
>         <attrib name="Names">
>             <rs>
>                 <row firstname="Ron"/>
>                 <row firstname="Sam"/>
>                 <row firstname="Joe"/>
>                 <row firstname="Sam"/>
>
>             </rs>
>         </attrib>
>     </product>
> </prods>
>
> ----------------------------------------------------
> This is the OUTPUT that I want (note no name dups):
> ----------------------------------------------------
>
> <ns:Products xmlns:ns="http://w.ns.c/ns/prod/">
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Bill</ns:name>
>         </ns:Names>
>     </ns:Product>
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Sam</ns:name>
>             <ns:name>Ron</ns:name>
>         </ns:Names>
>     </ns:Product>
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Ron</ns:name>
>             <ns:name>Joe</ns:name>
>             <ns:name>Sam</ns:name>
>         </ns:Names>
>     </ns:Product>
> </ns:Products>
>
>
> ----------------------------------------------------
> But this is the OUTPUT that I get (note the name dupes):
> ----------------------------------------------------
> <ns:Products xmlns:ns="http://w.ns.c/ns/prod/">
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Bill</ns:name>
>             <ns:name>Bill</ns:name>
>         </ns:Names>
>     </ns:Product>
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Sam</ns:name>
>             <ns:name>Ron</ns:name>
>             <ns:name>Sam</ns:name>
>             <ns:name>Ron</ns:name>
>         </ns:Names>
>     </ns:Product>
>     <ns:Product>
>         <ns:Names>
>             <ns:name>Ron</ns:name>
>             <ns:name>Sam</ns:name>
>             <ns:name>Joe</ns:name>
>             <ns:name>Sam</ns:name>
>         </ns:Names>
>     </ns:Product>
> </ns:Products>
>
> _________________________________________________________________
> FREE pop-up blocking with the new MSN Toolbar  get it now!
> http://toolbar.msn.click-url.com/go/onm00200415ave/direct/01/


_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today - it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.