RE: [xsl] XPath Problem.

Subject: RE: [xsl] XPath Problem.
From: Sandeep_Karandikar@xxxxxxxx
Date: Mon, 20 Jan 2003 14:07:02 -0600
Hi,

I think Wendell here did an excellent job of explaining me the steps that I
need to follow to get this going. So I wrote up a sample XML file and XSL
file and tried it using the XML editor and I don't think I am still doing it
right.

Here is the XML :

<?xml-stylesheet type="text/xsl" href="c:\Temp\test.xsl"?>
<RootNode>
	<DInfo name="D1">
		<TInfo name="t1"/>
		<TInfo name="t2"/>
	</DInfo>
	<DInfo name="D2">
		<DInfo name="D3">
			<TInfo name="t5"/>
			<TInfo name="t6"/>
		</DInfo>
		<DInfo name="D4">
			<DInfo name="D5">
				<TInfo name="t3"/>
				<TInfo name="t4"/>
			</DInfo>
			<DInfo name="D6">
				<TInfo name="t3"/>
				<TInfo name="t4"/>
			</DInfo>
		</DInfo>
	</DInfo>
</RootNode>

Here is the XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:fo="http://www.w3.org/1999/XSL/Format";>
	<xsl:template match="Root">
			<xsl:apply-templates select="DInfo[@name='D2']"/>
	</xsl:template>
	<xsl:template match="DInfo">
		<xsl:variable name="TInfo-descendants" select="//TInfo"/>
			<xsl:for-each select="$TInfo-descendants">
				<xsl:variable name="all-preceding-TInfos"
select="preceding::TInfo"/>
				<!-- this variable collects all TInfos in
the document preceding this one -->
				<xsl:variable name="preceding-TInfos"
select="$TInfo-descendants[count(.|$all-preceding-TInfos) =
count($all-preceding-TInfos)]"/>
				<xsl:if test="@name =
$preceding-TInfos/@name">
					<!-- the test will only allow a
TInfo through that has a name not on one of  the preceding TInfos -->
					<xsl:call-template
name="ShowTInfo"/>
				</xsl:if>
			</xsl:for-each>
	</xsl:template>
	<xsl:template name="ShowTInfo">
		<xsl:value-of select="./@name"/>
	</xsl:template>
</xsl:stylesheet>


The output that I am getting currently is : t3t4t3t4

The expected output is : t5t6t3t4 or more preferred t3t4t5t6

Can some one englighten me as to where am I am going wrong ?

Really Appreciate your help...

-Sandeep.



-----Original Message-----
From: Wendell Piez [mailto:wapiez@xxxxxxxxxxxxxxxx]
Sent: Wednesday, January 08, 2003 3:16 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] XPath Problem.


Hi Sandeep,

At 02:51 PM 1/8/2003, you wrote:
><RootNode>
><DInfo name="D1">
>         <TInfo name="t1"></T1>
>         <TInfo name="t2"></T2>
></DInfo>
><DInfo name="D2">
>         <DInfo name="D3">
>                 <TInfo name="t1"></T1>
>                 <TInfo name="t2"></T2>
>         </DInfo>
>         <DInfo name="D4">
>                 <DInfo name="D5">
>                         <TInfo name="t3"></T1>
>                         <TInfo name="t4"></T2>
>                 </DInfo>
>                 <DInfo name="D6">
>                         <TInfo name="t3"></T1>
>                         <TInfo name="t4"></T2>
>                 </DInfo>
>         </DInfo>
></DInfo>
></RootNode>
>
>Required Output:-
>         <xsl:key name="TInfo-Key-By-Name" match="TInfo" use="@name"/>
>
>         <xsl:for-each
>select="TInfo[count(.|key('TInfo-Key-By-Name',@name)[1]) = 1]">
>                 <xsl:call-template name="ShowTInfo">
>         </xsl:for-each>
>1. So when I have the RootNode Selected this works correctly and displays
me
>t1, t2, t3 , t4  only once.
>
>2. When I am on <DInfo name="D2"> I need to display t1, t2, t3, t4. However
>only t3 and t4 get displayed since it thinks that t1 and t2 have already
>been displayed.

Well, not exactly. Only t3 and t4 get displayed since it thinks (correctly) 
that those are its only descendants that pass the test you have given, 
which checks whether a TInfo is the first with its name value in the 
document. In your example, inside DInfo D2, this is the case only for the 
TInfo children of DInfo D5, not those of DInfo D3.

Keys are useful for deduplicating globally (i.e. within the entire 
document), but in order to do local de-duplication, you have to think 
harder. Your condition is apparently not to check a node's name value 
globally (assuring it's the first in the document), but rather only among 
the descendants of a particular node. This means comparing the value of its 
name not to all the TInfo elements, but only those inside a particular 
descendant ... which is a harder set to select.

Not impossible, however. Here's a template that matches a DInfo and gives 
back only those TInfo descendants that are first within it:

<xsl:template match="DInfo">
   <xsl:variable name="TInfo-descendants" select=".//TInfo"/>
     <!-- this variable holds all the TInfo elements in our scope:
          we'll need it later -->
   <xsl:for-each select="$TInfo-descendants">
     <!-- now we go process each of our TInfo descendants -->
     <xsl:variable name="all-preceding-TInfos"
        select="preceding::TInfo"/>
     <!-- this variable collects all TInfos in the document preceding this 
one -->
     <xsl:variable name="preceding-TInfos"
        select="$TInfo-descendants[count(.|$all-preceding-TInfos) =
                                   count($all-preceding-TInfos)]"/>
     <!-- this variable declaration uses an XPath idiom to get an 
intersection between
          the two sets of TInfos, resulting in all the TInfo elements in 
scope that
          precede this one -->
     <xsl:if test="@name = $preceding-TInfos/@name">
       <!-- the test will only allow a TInfo through that has a name not on 
one of
            the preceding TInfos -->
       <xsl:call-template name="ShowTInfo">
     </xsl:if>
   </xsl:for-each>
</xsl:template>

Note this approach is liable to be fairly costly over large documents, 
since it has to use the preceding:: axis to find nodes to check against.

Cheers,
Wendell


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
   Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread