I am struggling to find a compact way to use XSLT 3 streaming and an
accumulator to sum up the attribute values of certain elements,e.g.
xsl:accumulator name="attribute-sums" as="map(xs:QName, xs:decimal)"
initial-value="map{}" streamable="yes" to accumulate the sum of each
attribute by the name of the attribute.
One problem is that accumulators don't fire on attribute nodes, only on
element nodes, therefore I have to write the accumulator-rule to match
on the parent element of the attributes and compute all the sums in a
single rule;
fold-left(@*, $value, function($v, $a) { map:put($v, node-name($a),
(map:get($v, node-name($a)), 0)[1] + xs:decimal($a)) })
seemed like a compact and elegant use of XPath 3.1 but using a dynamic
inline function as the argument to fold-left doesn't seem to pass the
streamability analysis.
Then I tried to set up a user-defined function to be passed in as the
third argument to fold-left, but somehow that approach doesn't seem to
work either as a streamable stylesheet function needs to take the
streamable nodes as the first parameter while the signature of the
function $f of fold-left would make the attribute node the second parameter.
So the only options I could think of is not passing the attribute nodes
themselves to fold-left but rather an array or map of the name and value
I need to store in the accumulator e.g.
fold-left(@* ! [node-name(), xs:decimal(.)], $value, function($v, $anv)
{ map:put($v, $anv?1, (map:get($v, $anv?1), 0)[1] + $anv?2) })
or to abandon fold-left and use xsl:iterate in the accumulator rules
<xsl:accumulator name="attribute-sums" as="map(xs:QName,
xs:decimal)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="Book">
<xsl:iterate select="@*">
<xsl:param name="accumulator-map" select="$value"/>
<xsl:on-completion select="$accumulator-map"/>
<xsl:next-iteration>
<xsl:with-param name="accumulator-map"
select="map:put($accumulator-map, node-name(),
(map:get($accumulator-map, node-name()), 0)[1] + xs:decimal(.))"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:accumulator-rule>
</xsl:accumulator>
The xsl:iterate approach feels too verbose, I kind of think fold-left
should suffice to process the sequence of attributes (without that
escape hatch to map them first to an array or map).
Any ideas or opinions whether I have missed an approach to use fold-left?
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--