This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Summarizing sibling nodes


Hi Wayne,

The problems here are in your XPath expressions. They're not doing quite 
what you expect.

Let's look at that for-each select first:
The XPath:
     Truck[not(VINModelYearName/preceding::Truck/VINModelYearName)]
   | Truck[not(VINModelName/preceding::Truck/VINModelName)]

translates into (sort-of) English as

"All Truck element children that do not have a VINModelYearName child that 
are preceded (somewhere in the document) by a Truck element with a 
VINModelYearName child, ALONG WITH
all Truck element children that do not have a VINModelName child that are 
preceded (somewhere in the document) by a Truck element with a VINModelName 
child"

I don't think you want this. Something like (let's just look at the first half)
     Truck[not(VINModelYearName = preceding::Truck/VINModelYearName)]
is closer, it says

"All Truck element children that do not have a VINModelYearName child 
(whose string value is) equal to the VINModelYearName child of a preceding 
Truck element"

But even that's not right. Putting this together with a similar second 
term, you'd in effect be getting all Truck children with a new 
VINModelYearName along with all Truck children with a new VINModelName -- 
but this isn't the list you want. (What if you encountered a new Truck, but 
you'd had both its model name and its model year before, just not together 
-- you'd miss it.)

Similarly, the XPath in the count expression will be wrong.

I think what you're missing is that XPath expressions are evaluated with 
respect to a context node. This is making your logic hard to construct.

>I know the count part is wrong. I think I would put whatever pattern I use
>in my for-each in my count to return the same set of results to count.

Nope: the context node has changed, so the expression won't return the same 
thing.

>  I'm
>not sure though, because basically what I'm trying to do is create nodes on
>the fly matching a particular pattern. The pattern can change, because I
>want it for all the years, and for any Model (Which I could make a list of,
>but it would be quite long).

Well, sort of. Basically, yours is a grouping problem. (Hint: look up 
"grouping" in the XSL FAQ.) And it admits of a nice elegant solution if you 
use the XSLT idiom known as "Muenchian grouping", using a key expression. 
In fact, your analysis hints at this solution, in stipulating that you want 
to find nodes based on "a particular pattern": that's what the key will let 
you do.

So, a key declaration such as

<xsl:key name="TruckModelYear" match="Truck" use="concat(VINModelName, 
VINModelYearName)"/>

Creates a key you can use to retrieve your trucks. Each Truck is assigned a 
"TruckModelYear" key whose value is the combination of its VINModelName AND 
VINModelYearName children.

Then, the instruction

<xsl:for-each select="Truck[generate-id() =
   generate-id(key('TruckModelYear', concat(VINModelName, 
VinModelYearName)))[1]]">

[nb: untested] iterates over your Truck element children -- except it skips 
those that are not the first that match any given key. [Explanation: it 
keeps only those whose generated ID matches a generated ID for the first 
node (in document order) in the set of nodes (Trucks) with the same key 
value, i.e. same VINModelName and VINModelYearName.]

Then inside the for-each, the expression

   count(key('TruckModelYear', concat(VINModelName, VinModelYearName)))

will count the number of nodes matched by the key of the current Truck, 
that is, the number of Trucks that have the same key as the present Truck 
(the context node).

This is an advanced answer, I know ... but it's neater and cleaner than 
writing the (fancy and cumbersome) XPath to do it by brute force.

Hope that helps! (and folks, please check my logic),
Wendell

At 07:42 PM 3/14/01, you wrote:
>I'm rather new to XSL (Few months) and am running across a little problem,
>hoping someone here can help me. Thanks for your time.
>
>I have the following XML. . .
>
><Truck-list>
>     <Truck>
>       <VINModelName>
>         T600
>       </VINModelName>
>       <VINModelYearName>
>         1999
>       </VINModelYearName>
>     </Truck>
>     <Truck>
>       <VINModelName>
>         T100
>       </VINModelName>
>       <VINModelYearName>
>         1999
>       </VINModelYearName>
>     </Truck>
>    <Truck>
>       <VINModelName>
>         T600
>       </VINModelName>
>       <VINModelYearName>
>         2000
>       </VINModelYearName>
>     </Truck>
>    <Truck>
>       <VINModelName>
>         T600
>       </VINModelName>
>       <VINModelYearName>
>         1999
>       </VINModelYearName>
>     </Truck>
></Truck-list>
>
>What I am trying to accomplish is a summary of the truck somewhat like this
>(Except in HTML and prettier):
>
>Build Year: 1999
>Model: T100
>Count: 1
>
>Build Year: 1999
>Model: T600
>Count: 2
>
>Build Year: 2000
>Model: T100
>Count: 1
>
>Build Year: 2000
>Model: T600
>Count: 1
>
>The XSL chunk I have currently is as follows (I think this is the closest
>I've been, but I've tried lots of things here):
>
><xsl:template match="Truck-list">
>    [HTML table build]
>      <xsl:for-each
>select="Truck[not(VINModelYearName/preceding::Truck/VINModelYearName)]
>              |Truck[not(VINModelName/preceding::Truck/VINModelName)]">
>            <tr>
>                   <td class="lensBody" bgcolor="#FFFFFF" nowrap="true">
>                   <xsl:value-of select="VINModelYearName"/>&#160;
>                   </td>
>                   <td class="lensBody" bgcolor="#FFFFFF" nowrap="true">
>                   <xsl:value-of select="VINModelName"/>&#160;
>                   </td>
>               <td class="lensBody" bgcolor="#FFFFFF" nowrap="true">
>                   <xsl:value-of select="count(VINModelName)"/>&#160;
>                   </td>
>          </tr>
>      </xsl:for-each>
>    </table>
></xsl:template>

======================================================================
Wendell Piez                            mailto:wapiez@mulberrytech.com
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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]