Will my personal information be public if I post here?
Original Post
Is the use of the [1] predicate really required?
I'm finding when I remove it, I'm still getting same (correct?) results.
Seems like the 'select' attribute on a key() function's returned node-set is giving me the same thing whether I explicitly indicate I want the first one '[1]' or if I don't explictly do that. (It even seemed to return same results when I explicitly asked for [2] second node. Hmmm. (See final example below.))
Is that the nature of a 'select' attribute on a node-set, to get the first one in node-set anyway? (Hmmmm.)
I expect in the end I'm wrong about all this, and I want to believe my textbook(s)!, yet, I've not been able (yet?) to demonstrate to myself the difference.
[Please note: I do note the explanation worked through in Beginning XSLT on pages 384-385 (TVGuide8.xsl and TVGuide9.xsl), regarding getting "only one" of the elements (<Series> elements in her example). But that still doesn't address what I'm bringing up here (see "Third Example" below).]
Please somebody show me. :^)
Thanks!
(Details below.)
William Reilly
Jeni Tennison's Beginning XSLT book Code Download:
http://jenitennison.com/xslt/5946.zip
FIRST EXAMPLE (of 3)
"Apply-Templates"
Beginning XSLT, p. 386 ff.
=== TVGuide10.xsl ======
<xsl:template match="TVGuide">
<xsl:apply-templates
select="Channel/Program
[generate-id() =
generate-id(key('programsByHour',
substring(Start, 12, 2))[1])]" />
=== Same File, My Edit to Remove '[1]'======
<xsl:template match="TVGuide">
<xsl:apply-templates
select="Channel/Program
[generate-id() =
generate-id(key('programsByHour',
substring(Start, 12, 2)))]" />
=== FileCompare the Two Outputs ("no diff") ======
C:\XSLT-Beginning\Chapter10>fc XSLOutput_10.html XSLOutput_10_no1.html
Comparing files XSLOutput_10.html and XSLOUTPUT_10_NO1.HTML
FC: no differences encountered
=========
SECOND EXAMPLE (of 3)
"For-Each"
http://cscie153.dce.harvard.edu/lecture_notes/7/sl ide14.html
http://cscie153.dce.harvard.edu/lecture_notes/7/ex amples3/group3.xsl
=== group3.xsl ======
<xsl:template name="members_by_state">
<xsl:for-each select="/ushousemembers/member
[generate-id() = generate-id(
key('membersbystate',state)[1]
)
]">
=========
=== Same File, My Edit to Remove '[1]' ======
<xsl:template name="members_by_state">
<xsl:for-each select="/ushousemembers/member
[generate-id() = generate-id(
key('membersbystate',state)
)
]">
==========
=== Unix "diff" on the Two Outputs ("no diff") ===
======
$ diff out_group.html out_group_no1.html
$
=========
THIRD EXAMPLE (of 3)
"xsl:if"
Beginning XSLT, p. 385
=== TVGuide9.xsl ======
<xsl:key name="programsBySeries" match="Program" use="Series" />
<xsl:template match="Program/Series" mode="EpisodeList">
<xsl:variable name="episodes" select="key('programsBySeries', .)" />
<xsl:variable name="firstEpisode" select="$episodes[1]" />
<xsl:if test="generate-id() =
****************************************
generate-id($firstEpisode)">
****************************************
<div>
<h3><a name="{.}" id="{.}"><xsl:value-of select="." /></a></h3>
<h4>Episodes</h4>
<ul>
<xsl:for-each select="$episodes">
===============================
=== Same File, My Edit to Change $firstEpisode to $episodes ========
<xsl:key name="programsBySeries" match="Program" use="Series" />
<xsl:template match="Program/Series" mode="EpisodeList">
<xsl:variable name="episodes" select="key('programsBySeries', .)" />
<xsl:variable name="firstEpisode" select="$episodes[1]" />
<xsl:if test="generate-id() =
****************************************
generate-id($episodes)">
****************************************
<div>
<h3><a name="{.}" id="{.}"><xsl:value-of select="." /></a></h3>
<h4>Episodes</h4>
<ul>
<xsl:for-each select="$episodes">
===========================
=== FileCompare the Two Outputs ("no diff") ======
C:\XSLT-Beginning\5946\Chapter10>fc XSLOutput_09_firstepisode.html XSLOutput_09_
episodes.html
Comparing files XSLOutput_09_firstepisode.html and XSLOUTPUT_09_EPISODES.HTML
FC: no differences encountered
===================================
"Extra Credit" Example ;^)
Same as Third Example, but One Small Edit:
Tried _Second_ Episode '[2]' vs. First.
(Still No Diff!)
=== TVGuide9.xsl ======
<xsl:key name="programsBySeries" match="Program" use="Series" />
<xsl:template match="Program/Series" mode="EpisodeList">
<xsl:variable name="episodes" select="key('programsBySeries', .)" />
<xsl:variable name="secondEpisode" select="$episodes[2]" />
<xsl:if test="generate-id() =
****************************************
generate-id($secondEpisode)">
****************************************
<div>
<h3><a name="{.}" id="{.}"><xsl:value-of select="." /></a></h3>
<h4>Episodes</h4>
<ul>
<xsl:for-each select="$episodes">
===============================
=== FileCompare the Two Outputs ("no diff") ======
C:\XSLT-Beginning\5946\Chapter10>fc XSLOutput_09_secondepisode.html XSLOutput_09
_episodes.html
Comparing files XSLOutput_09_secondepisode.html and XSLOUTPUT_09_EPISODES.HTML
FC: no differences encountered
===================================</ul>< /div></ul></div></ul></div >
If you can stand any more...
Here's one more (4th example) that continues to confirm what I'd seen before,
and one new one (5th example) that takes a different tack (different predicate) which finally DOES show some difference, if you remove the infamous '[1]'.
Mostly just posting this additional info for completeness.
William R.
FOURTH EXAMPLE
http://www.oreilly.com/catalog/xslt/ Doug Tidwell, 2001, p. 144 ff.
=== Chapter 6 "Selecting and Traversing" =======
<!-- WR_ ORIG <xsl:for-each select="//address[generate-id(.)=
generate-id(key('zipcodes', zip)[1])]"> -->
==================
=== Same File, My Edit to Remove '[1]' ======
<xsl:for-each select="//address[generate-id(.)=
generate-id(key('zipcodes', zip))]">
================
====================
C:\XSLT-OReilly\Chapter6>fc XSLOutput_06.html XSLOutput_06_no1.html
Comparing files XSLOutput_06.html and XSLOUTPUT_06_NO1.HTML
FC: no differences encountered
====================
FIFTH (FINAL (!)) EXAMPLE
Note that this example uses a different predicate.
And it does finally yield a difference if you remove the '[1]' !
http://www.oreilly.com/catalog/xsltckbk/ Sal Mangano, 2003, p. 234, Recipe 6.9
=== Chapter 6 "XML to XML" ====
<xsl:for-each select="$products[count(.|key('product_key',@sku)[ 1]) = 1]">
====================
=== Same File, My Edit to Remove '[1]' ===
<!-- AH-HAH!!! A difference!
Hmm. Yields one only (sku 70000) -->
<xsl:for-each select="$products[count(.|key('product_key',@sku)) = 1]">
=================
=====================
C:\XSLT-Cookbook>fc XSLOutput_6.9Muench.xml XSLOutput_6.9Muench_no1.xml
Comparing files XSLOutput_6.9Muench.xml and XSLOUTPUT_6.9MUENCH_NO1.XML
***** XSLOutput_6.9Muench.xml
<salesByProduct>
<product sku="10000" totalSales="2110000">
<salesperson name="John Adams" seniority="1" sold="10000.00"/>
<salesperson name="Wendy Long" seniority="5" sold="990000.00"/>
<salesperson name="Willie B. Aggressive" seniority="10" sold="1110000.00"/
>
</product>
<product sku="20000" totalSales="350000">
<salesperson name="John Adams" seniority="1" sold="50000.00"/>
<salesperson name="Wendy Long" seniority="5" sold="150000.00"/>
<salesperson name="Willie B. Aggressive" seniority="10" sold="150000.00"/>
</product>
<product sku="25000" totalSales="3840000">
<salesperson name="John Adams" seniority="1" sold="920000.00"/>
<salesperson name="Willie B. Aggressive" seniority="10" sold="2920000.00"/
>
</product>
<product sku="30000" totalSales="121000">
<salesperson name="Wendy Long" seniority="5" sold="5500.00"/>
<salesperson name="Willie B. Aggressive" seniority="10" sold="115500.00"/>
</product>
<product sku="70000" totalSales="10000">
***** XSLOUTPUT_6.9MUENCH_NO1.XML
<salesByProduct>
<product sku="70000" totalSales="10000">
*****
====================
FINAL ("Extra Credit" #2) EXAMPLE ;^)
SAME FILE as above.
But, just as sanity check, I put back in our original predicate (i.e. [generate-id(.)=generate-id(key('product_key',@sku )[1])] )
Once again, removing the '[1]' does _not_ make any change. (O.K., I'm cool with this by now ;^))
=== Chapter 6 "XML to XML" =====
<xsl:for-each select="$products[generate-id(.)=generate-id(key(' product_key',@sku)[1])]">
========
=== Same File, My Edit to Remove '[1]' ======
<xsl:for-each select="$products[generate-id(.)=generate-id(key(' product_key',@sku))]">
========================
=====================
C:\XSLT-Cookbook>fc XSLOutput_6.9Muench_key_no-count.xml XSLOutput_6.9Muench_key
_no-count_no1.xml
Comparing files XSLOutput_6.9Muench_key_no-count.xml and XSLOUTPUT_6.9MUENCH_KEY
_NO-COUNT_NO1.XML
FC: no differences encountered
====================
FOUND THE ANSWER
(in last book I consulted, of course)
Jeni Tennison's OTHER book: XSLT and XPath On The Edge, 2001, p. 220
- Testing Node Identity -
generate-id() = generate-id(key('transactions', @type))
"...using generate-id() on a node set (such as that returned by the key) returns the generated ID for the first node in that node set, so there's no requirement to put in a [1] predicate to select this first node explicitly, although it doesn't hurt to do so if you find it clearer."
ARGHHHHH-ish.
Ah well.
There you go.
Good!
Over & Out
William Reilly