Reputation: 2849
I am attempting to understand how an answer to a previous question of mine works. Here is the old question: XSL Transform with three source documents to create report
I have two questions. One, why does the use of a variable cause the output to change between the nodes "staff-with-membership" and "staff-with-membership-using-variable" (under Center3). My expectation would be that using a variable would have no effect.
Second, how does the "filtering" work for the variable "staff" - I would expect the code "key('membership-by-staff', @StaffID)" to return either one node or none, but somehow it manages to seemingly return two for "Center2" (Charles Glover and Donald Hill).
Source xml:
<root>
<Staff>
<Items>
<Item StaffName="Charles Glover" StaffCenter="Center2" StaffID="CG1" />
<Item StaffName="Donald Hill" StaffCenter="Center2" StaffID="DH1" />
<Item StaffName="Evan Dolan" StaffCenter="Center3" StaffID="ED1" />
<Item StaffName="Frank Miller" StaffCenter="Center3" StaffID="FM1" />
</Items>
</Staff>
<Membership>
<Items>
<Item MembershipStaff_ID="CG1" />
<Item MembershipStaff_ID="DH1" />
<Item MembershipStaff_ID="ED1" />
</Items>
</Membership>
</root>
Xsl:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="staff-by-center" match="Staff/Items/Item" use="@StaffCenter"/>
<xsl:key name="membership-by-staff" match="Membership/Items/Item" use="@MembershipStaff_ID"/>
<xsl:template match="/root">
<root>
<!-- for each distinct center -->
<xsl:for-each select="Staff/Items/Item[count(.|key('staff-by-center', @StaffCenter)[1]) = 1]">
<xsl:variable name="center" select="@StaffCenter" />
<!-- staff at current center -->
<xsl:variable name="all-staff" select="key('staff-by-center', $center)" />
<!-- exclude staff with no memberships -->
<xsl:variable name="staff" select="$all-staff[key('membership-by-staff', @StaffID)]" />
<!-- staff using variable for StaffID instead of attribute -->
<xsl:variable name="myStaffId" select="@StaffID" />
<xsl:variable name="staff-using-variable" select="$all-staff[key('membership-by-staff', $myStaffId)]" />
<center>
<name>
<xsl:value-of select="$center" />
</name>
<all-staff-in-center>
<xsl:copy-of select="$all-staff" />
</all-staff-in-center>
<staff-with-membership>
<xsl:copy-of select="$staff" />
</staff-with-membership>
<membership>
<xsl:copy-of select="key('membership-by-staff', @StaffID)" />
</membership>
<staff-with-membership-using-variable>
<xsl:copy-of select="$staff-using-variable" />
</staff-with-membership-using-variable>
</center>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Output xml:
<root>
<center>
<name>Center2</name>
<all-staff-in-center>
<Item StaffName="Charles Glover" StaffCenter="Center2" StaffID="CG1"/>
<Item StaffName="Donald Hill" StaffCenter="Center2" StaffID="DH1"/>
</all-staff-in-center>
<staff-with-membership>
<Item StaffName="Charles Glover" StaffCenter="Center2" StaffID="CG1"/>
<Item StaffName="Donald Hill" StaffCenter="Center2" StaffID="DH1"/>
</staff-with-membership>
<membership>
<Item MembershipStaff_ID="CG1"/>
</membership>
<staff-with-membership-using-variable>
<Item StaffName="Charles Glover" StaffCenter="Center2" StaffID="CG1"/>
<Item StaffName="Donald Hill" StaffCenter="Center2" StaffID="DH1"/>
</staff-with-membership-using-variable>
</center>
<center>
<name>Center3</name>
<all-staff-in-center>
<Item StaffName="Evan Dolan" StaffCenter="Center3" StaffID="ED1"/>
<Item StaffName="Frank Miller" StaffCenter="Center3" StaffID="FM1"/>
</all-staff-in-center>
<staff-with-membership>
<Item StaffName="Evan Dolan" StaffCenter="Center3" StaffID="ED1"/>
</staff-with-membership>
<membership>
<Item MembershipStaff_ID="ED1"/>
</membership>
<staff-with-membership-using-variable>
<Item StaffName="Evan Dolan" StaffCenter="Center3" StaffID="ED1"/>
<Item StaffName="Frank Miller" StaffCenter="Center3" StaffID="FM1"/>
</staff-with-membership-using-variable>
</center>
</root>
Upvotes: 2
Views: 51
Reputation: 167506
With
<xsl:variable name="myStaffId" select="@StaffID" />
<xsl:variable name="staff-using-variable" select="$all-staff[key('membership-by-staff', $myStaffId)]" />
you select the @StaffID
attribute for the context node (of the outer for-each
) only.
In the expression <xsl:variable name="staff" select="$all-staff[key('membership-by-staff', @StaffID)]" />
the attribute @StaffID
is selected for each node in $all-staff
as the expression is inside the predicate in square brackets. You would need to use $all-staff[key('membership-by-staff', current()/@StaffID)]
to have the same result as with your use of the variable where you only select the StaffID
of the context node.
As for $all-staff
being filtered by the predicate [key('membership-by-staff', @StaffID)]
, the predicate expression is evaluated for each node in $all-staff
and tests whether there is a reference in Membership/Items/Item
. There is for both the persons of Center2
but only for one of Center3
.
Upvotes: 2