Grouping Across Multiple Documents
page 130
This certainly isnt efficient; for each unique state, well have to call the
document
function once for every
filename
attribute. In other words, if we had 500 purchase orders from 50 unique states, we would have to open each of those 500 documents 51 times, invoking the
document
25,500 times Its not pretty, but it works. Retrieving the values of all
state
elements is relatively straightforward. Well use the technique of creating a variable whose value contains output from an
xsl:for-each
element:
xsl:variable name=list-of-states xsl:for-each
select=documentreportpofilenamepurchase-ordercustomeraddressstate xsl:sort select=documentstates:name[abbrev=current]
xsl:value-of select=.xsl:text xsl:text xsl:for-each
xsl:variable
This code produces the string ME MA MA WI for our current set of purchase orders. Our next step will remove any duplicate values from the list. Well do this with recursion, using
the following algorithm:
•
Call our recursive template with two arguments: the list of states and the name of the last state we found. the first time we invoke this template, the name of the last state
will be blank.
•
Break the list of states into two parts: The first state in the list, followed by the remaining states in the list.
•
If the list of states is empty, exit. If the first state in the list is different from the last state we found, output the first state
and invoke the template on the remaining states on the list. If the first state in the list is the same as the last state we found, simply invoke the
template on the remaining states on the list. Again, we use our technique of calling this template inside an
xsl:variable
element to save the list of unique states for later. Here is the
xsl:variable
element, along with the recursive template that removes duplicate state names from the string:
xsl:variable name=list-of-unique-states xsl:call-template name=remove-duplicates
xsl:with-param name=list-of-states select=list-of-states xsl:with-param name=last-state select=
xsl:call-template xsl:variable
xsl:template name=remove-duplicates xsl:param name=list-of-states
xsl:param name=last-state select= xsl:variable name=next-state
xsl:value-of select=substring-beforelist-of-states, xsl:variable
xsl:variable name=remaining-states xsl:value-of select=substring-afterlist-of-states,
xsl:variable xsl:choose
xsl:when test=notstring-lengthnormalize-spacelist-of-states -- If the list of states is empty, do nothing --
xsl:when xsl:when test=notlast-state=next-state
xsl:value-of select=next-state xsl:text xsl:text
xsl:call-template name=remove-duplicates
page 131 xsl:with-param name=list-of-states select=remaining-states
xsl:with-param name=last-state select=next-state xsl:call-template
xsl:when xsl:when test=last-state=next-state
xsl:call-template name=remove-duplicates xsl:with-param name=list-of-states select=remaining-states
xsl:with-param name=last-state select=next-state xsl:call-template
xsl:when xsl:choose
xsl:template
At this point, we have a variable named
list-of-unique-states
that contains the value
ME MA WI
. Now all we have to do is get each value and output all the purchase orders from each state. Well use recursion yet again to make this happen. Well pass our list of unique states to
our recursive template, which does the following:
•
Breaks the string into two parts: the first state in the list and the remaining states.
•
Outputs a heading for the first state in the list.
•
Invokes the
document
function against each purchase order. If a given purchase order is from the first state in the list, use
xsl:apply-templates
to transform it.
•
Invokes the template again for the remaining states. If no states remain the value of
normalize-spaceremaining-states
is an empty string, were done. Here is the root template and the recursive template we use to group our data. The result of
our hard work looks like Figure 7-4
.
Figure 7-4. Document featuring grouped items from multiple input files
xsl:template match= html
head titlexsl:value-of select=reporttitletitle
head body
h3Selected Purchase Orders - ibGroupedb by stateih3
page 132 xsl:call-template name=group-by-state
xsl:with-param name=list-of-unique-states select=list-of-unique-states
xsl:call-template body
html xsl:template
xsl:template name=group-by-state xsl:param name=list-of-unique-states
xsl:variable name=next-state xsl:value-of select=substring-beforelist-of-unique-states,
xsl:variable xsl:variable name=remaining-states
xsl:value-of select=substring-afterlist-of-unique-states, xsl:variable
hr h1Purchase Orders from
xsl:value-of select=documentstates:name[abbrev=next-state] h1
xsl:for-each select=documentreportpofilenamepurchase-ordercustomeraddress
xsl:if test=state=next-state xsl:apply-templates select=ancestor::purchase-order
xsl:if xsl:for-each
xsl:if test=normalize-spaceremaining-states xsl:call-template name=group-by-state
xsl:with-param name=list-of-unique-states select=remaining-states
xsl:call-template xsl:if
xsl:template