private QilNode PlaceMarkerAny(QilNode countPattern, QilNode fromPattern)
{
/*
Quotation from XSLT 2.0 spec:
* If the context node is a document node, return the empty sequence, ()
* Let $A be the node sequence selected by the expression
(preceding::node()|ancestor-or-self::node())[matches-count(.)]
* Let $F be the node sequence selected by the expression
(preceding::node()|ancestor::node())[matches-from(.)][last()]
* Let $AF be the node sequence $A[. is $F or . >> $F].
* If $AF is empty, return the empty sequence, ()
* Otherwise return the value of the expression count($AF)
NOTE: There are some distinctions between XSLT 1.0 and XSLT 2.0 specs. In our 1.0 implementation we:
1) Assume that the 'matches-from()' function does not match root nodes by default.
2) Instead of '$A[. is $F or . >> $F]' we calculate
'$A' if the 'from' attribute is omitted,
'$A[. >> $F]' if the 'from' attribute is present.
*/
QilNode range, fromMatches, F, AF;
QilIterator i, j, k;
if (fromPattern == null)
{
// According to XSLT 2.0 spec, if the 'from' attribute is omitted, matches-from() returns true
// only for the root node. It means $F is a sequence of length one containing the root node,
// and $AF = $A. XSLT 1.0 spec rules lead to the same result $AF = $A, so two specs are compliant here.
range = _f.NodeRange(_f.Root(GetCurrentNode()), GetCurrentNode());
AF = _f.Filter(i = _f.For(range), MatchCountPattern(countPattern, i));
}
else
{
fromMatches = _f.Filter(i = _f.For(_f.Preceding(GetCurrentNode())), MatchPattern(fromPattern, i));
F = _f.Filter(i = _f.For(fromMatches), _f.Eq(_f.PositionOf(i), _f.Int32(1)));
AF = _f.Loop(i = _f.For(F),
_f.Filter(j = _f.For(_f.Filter(k = _f.For(_f.NodeRange(i, GetCurrentNode())), MatchCountPattern(countPattern, k))),
_f.Not(_f.Is(i, j))
)
);
}
return _f.Loop(k = _f.Let(_f.Length(AF)),
_f.Conditional(_f.Eq(k, _f.Int32(0)), _f.Sequence(),
k
));
}