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

Subject: Re: [xsl] Trouble removing dup elements based on attributes
From: "Sam D. Chuparkoff" <sdc@xxxxxxxxxx>
Date: Sat, 25 Jun 2005 12:19:18 -0700
On Sat, 2005-06-25 at 15:25 +0000, Al Bean wrote:
> 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.

Chris points out these aren't logically equivalent. not(P) and not(Q) is
not(P or Q).

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

You don't want to search independently for a node that matches the
firstname of the current node and then a node that matches the lastname
of the current node. You want to know if there is one node that matches
both first and last names of the current node. You need something like:

not(preceding-sibling::row
    [@firstname=current()/@firstname]
    [@ln=current()/@ln])

sdc

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

Current Thread