我想使用XSL 2.0(saxon9he.jar)按位置将数据拆分成组 . 在这个样本中,我尝试将市场产品分成每个袋子中有4个物品的袋子 . 我的测试表明position()在父级的范围内 . 马铃薯在蔬菜部门的孩子中排名第2,而不是在我选择的产品中排名第5 . 我想基于选区内的位置,而不是父级中的位置 .
XML数据集:
<market>
<department name="fruit">
<product>apple</product>
<product>banana</product>
<product>grape</product>
</department>
<department name="vegetable">
<product>carrot</product>
<product>potato</product>
<product>squash</product>
</department>
<department name="paper">
<product>plates</product>
<product>napkins</product>
<product>cups</product>
</department>
<department name="cloths">
<product>shirts</product>
<product>shorts</product>
<product>socks</product>
</department>
</market>
XSL模板:
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn">
<xsl:output indent="no" method="text"/>
<!-- place 4 items in each bag -->
<xsl:template match="/">
<xsl:for-each-group select="/market/department/product"
group-ending-with="/market/department/product[position() mod 4 = 0]">
<xsl:variable name="file"
select="concat('bags/bag',position(),'.txt')"/>
<xsl:result-document href="{$file}">
<xsl:value-of select="position()"/>
<xsl:for-each select="current-group()">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
结果是bag1.txt
1applebananagrapecarrotpotatosquashplatesnapkinscupsshirtsshortssocks
结果是bag2.txt
file does not exist!
Expected bag1.txt
1applebananagrapecarrot
Expected bag2.txt
2potatosquashplatesnapkins
我的调试结论:似乎position()从不4(每个部门只有3个项目)如果我将 mod 4
改为 mod 2
我得到多个包,而包1包含2个项目 . 但除了最后一个之外的所有其他包含3个项目 . 每个包都在一个部门的第二个项目结束,除第一个包之外的所有包都包括前一个部门的最后一个项目 .
结果是bag1.txt
1applebanana
结果是bag1.txt
2grapecarrotpotato
Expected bag1.txt
1applebanana
Expected bag2.txt
2grapecarrot
这告诉我,position()与父项相关,而不是与选择相关 . 我希望position()与选择相关 . 根据我的研究,position()应该与选择有关 . 这里的答案中描述的是:
最终提示:position()不会告诉您父节点中节点的位置 . 它告诉您当前节点相对于您正在处理的节点列表的位置 .
Find the position of an element within its parent with XSLT / XPath
这里提到模式表达式与select表达式相比,它们对范围的解释不同 . 阅读之后,我不知道如何改变我对模式表达式的使用来实现我期待的行为 .
Using for-each-group for high performance XSLT
根据我目前观察到的行为:如果我有9种水果,4种蔬菜和20种纸制品,并且使用 mod 5
bag1将包含前5种水果产品,则bag2将包含最后4种水果4种蔬菜的前5种纸制品 .
目前的行为不是我正在寻找的行为 .
2 回答
尝试在这里使用
group-adjacent
,而不是group-ending-with
或这个...
因此,根据整数除以4的位置对项目进行分组 .
Tim C已经解释了如何获得理想的行为;这只是一个帮助您了解错误的注释 .
The position() function and the dynamic context
position()
函数返回给定序列中项目的位置,该序列的标识由上下文给出 . 该函数通常会返回元素在其父元素之间的位置,但这是因为在实践中,确定用于评估XPath表达式的动态上下文的规则通常指定相关序列是元素子节点的序列 .position()
函数不是'scoped'作为其定义的一部分的父元素 .position()
函数的值是上下文位置,定义为"the position of the context item within the sequence of items currently being processed" . 与上下文项一样,上下文位置(以及last()
返回的上下文大小)是评估XPath表达式的动态上下文的一部分 . 在评估任何非原子XPath表达式时,动态上下文对于不同的子表达式可能是不同的 .特别是,XPath specification规定“当评估表达式
E1/E2
或E1[E2]
时,通过评估E1
获得的序列中的每个项目都成为内部焦点中的上下文项目,用于评估E2
. ”The expression in your group-ending-with attribute
在表达式
/market/department/product[position() mod 4 = 0]
中,刚引用的规则意味着表达式product[position() mod 4 = 0]
将针对序列中的每个项目单独计算/market/department'. That is, for each
departmentelement in that sequence, the expression
product [...]is evaluated. That right-hand expression in turn is equivalent to
child :: product [...], so for each evaluation of the right-hand expression the sequence in question is the sequence of elements named
productwhich are children of the current
departmentelement. Within the expression
product [position ()mod 4 = 0], the same basic rule applies: the filter expression within square brackets is evaluated in the context given by the expression
product. As a consequence, the context position (the value returned by
position()) is the position of the current
productelement among its sibling elements. Since no
departmentelement in the input has as many as four children, the value of
position()`永远不会大于3,并且每个过滤器表达式的计算结果为false,因此表达式作为一个整体求值为空序列 .A similar expression with a different value
相反,在表达式
(/market/department/product)[position() mod 4 = 0]
中,过滤器表达式在文档中所有product
元素序列的上下文中进行评估(严格地说,那些具有指定路径的元素,在这种情况下是所有产品元素)文献) . 作为不同部门元素的子元素的产品元素被集中到相同的序列中,然后对每个元素应用谓词一次 .position()
的值范围为1到12,整个表达式选择值为carrot,napkins和socks的产品 .您不能简单地在
group-ending-with
属性中使用第二个表达式,因为它不被允许(属性值必须是模式,而不是一般的XPath表达式) . 即使你可以,模板中还有其他问题需要修复 .但是你应该清楚自己的想法是
position()
始终只表示一个节点在其父节点之间的位置 .A simple arithmetic example
考虑一些根本不涉及节点的表达式可能会有所帮助 .
表达方式
表示从1到100的自然数序列,包括1和100 . 我会称之为S1 . 表达方式
除了上下文位置可被4整除的那些之外,从S1中过滤掉所有内容,因此它表示序列(4,8,...,96,100) . 我会称之为S2 . 如果我们附加另一个过滤器表达式,则其上下文由序列S2给出,而不是由S1给出 . 所以
返回由序列S2中的第24和第25个条目组成的序列,即(96,100) .