RE: [xsl] Trouble removing dup elements based on attributes

Subject: RE: [xsl] Trouble removing dup elements based on attributes
From: "Chris Loschen" <Chris.Loschen@xxxxxxxxxx>
Date: Sat, 25 Jun 2005 10:13:17 -0600
I'm not sure why your choice 1 isn't working (perhaps you need a
reference to context node?), but your two options are not logically
equivalent. Take the case when A is true and B is false. In that case,
"not(A and B)" returns true because A and B are not both true, but
"not(A) and not(B)" returns false because A is true.

Choice 1 looks like the way to achieve what you want logically. I'll let
someone else figure out why it isn't working for you.

Chris Loschen

-----Original Message-----
From: Al Bean [mailto:albean88@xxxxxxxxxxx]
Sent: Saturday, June 25, 2005 11:25 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Trouble removing dup elements based on attributes

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.

I've extended my problem now to include more than one attribute and I've
run into trouble, again.  I'm not sure if it is because I don't
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 don't 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: [xsl] 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/





_______________
Siebel
IT'S ALL ABOUT THE CUSTOMER
Visit www.siebel.com

This e-mail message is for the sole use of the intended recipient(s) and
contains confidential and/or privileged information belonging to Siebel
Systems, Inc. or its customers or partners. Any unauthorized review, use,
copying, disclosure or distribution of this message is strictly prohibited. If
you are not an intended recipient of this message, please contact the sender
by reply e-mail and destroy all soft and hard copies of the message and any
attachments. Thank you for your cooperation.

Current Thread