Xslt 将条目合并到页码
我有如下索引条目:Xslt 将条目合并到页码,xslt,xslt-2.0,Xslt,Xslt 2.0,我有如下索引条目: <entry name="a" page="1" /> <entry name="b" page="3" /> <entry name="b" page="4" /> <entry name="b" page="6" /> <entry name="c" page="7" /> 现在我想买点像 <index name="a" pages="1 /> <index name="b" pages=
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
现在我想买点像
<index name="a" pages="1 />
<index name="b" pages="3-4, 6" />
<index name="c" pages="7" />
然后把“346”变成“346”。第一步很简单:
<xsl:for-each-group select="index" group-adjacent="@name">
<xsl:element name="index">
<xsl:attribute name="name" select="@name"/>
<xsl:attribute name="pages" select="current-group()/@page"/>
</xsl:element>
</xsl:for-each-group>
(当然,此处的“页面”属性可能有所不同)
现在是困难的一步,我应该如何迭代列表?必须有一些聪明的解决方案来检查下一个同级/@页面(我可以将页面按顺序排列)是否是当前的@page+1。以下是一个示例:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="entries">
<xsl:for-each-group select="entry" group-by="@name">
<index name="{current-grouping-key()}">
<xsl:attribute name="pages">
<xsl:for-each-group select="current-group()/xs:integer(@page)" group-by="position() - .">
<xsl:if test="position() gt 1">
<xsl:text>, </xsl:text>
</xsl:if>
<xsl:value-of select="if (current-group()[2])
then (current-group()[1], current-group()[last()])
else ."
separator="-"/>
</xsl:for-each-group>
</xsl:attribute>
</index>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
,
输入为
<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>
我得到了结果
<index name="a" pages="1"/>
<index name="b" pages="3-4, 6"/>
<index name="c" pages="7"/>
这里是另一个解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="entries">
<xsl:for-each-group select="entry" group-by="@name">
<index name="{current-grouping-key()}">
<xsl:attribute name="pages">
<xsl:variable name="vAtribVals" as="xs:integer*">
<xsl:perform-sort select="current-group()/@page/xs:integer(.)">
<xsl:sort data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:sequence select=
"$vAtribVals[1],
for $k in 2 to count($vAtribVals)
return
if($vAtribVals[$k] - $vAtribVals[$k -1] ne 1)
then concat(',', $vAtribVals[$k])
else
if($vAtribVals[$k+1] - $vAtribVals[$k] ne 1)
then concat('-', $vAtribVals[$k])
else()
"/>
</xsl:attribute>
</index>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>
<index name="a" pages="1"/>
<index name="b" pages="3-4,6"/>
<index name="c" pages="7"/>
当此转换应用于以下XML文档时:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="entries">
<xsl:for-each-group select="entry" group-by="@name">
<index name="{current-grouping-key()}">
<xsl:attribute name="pages">
<xsl:variable name="vAtribVals" as="xs:integer*">
<xsl:perform-sort select="current-group()/@page/xs:integer(.)">
<xsl:sort data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:sequence select=
"$vAtribVals[1],
for $k in 2 to count($vAtribVals)
return
if($vAtribVals[$k] - $vAtribVals[$k -1] ne 1)
then concat(',', $vAtribVals[$k])
else
if($vAtribVals[$k+1] - $vAtribVals[$k] ne 1)
then concat('-', $vAtribVals[$k])
else()
"/>
</xsl:attribute>
</index>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>
<index name="a" pages="1"/>
<index name="b" pages="3-4,6"/>
<index name="c" pages="7"/>
生成所需的正确结果:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="entries">
<xsl:for-each-group select="entry" group-by="@name">
<index name="{current-grouping-key()}">
<xsl:attribute name="pages">
<xsl:variable name="vAtribVals" as="xs:integer*">
<xsl:perform-sort select="current-group()/@page/xs:integer(.)">
<xsl:sort data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:sequence select=
"$vAtribVals[1],
for $k in 2 to count($vAtribVals)
return
if($vAtribVals[$k] - $vAtribVals[$k -1] ne 1)
then concat(',', $vAtribVals[$k])
else
if($vAtribVals[$k+1] - $vAtribVals[$k] ne 1)
then concat('-', $vAtribVals[$k])
else()
"/>
</xsl:attribute>
</index>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>
<index name="a" pages="1"/>
<index name="b" pages="3-4,6"/>
<index name="c" pages="7"/>
注意事项:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="entries">
<xsl:for-each-group select="entry" group-by="@name">
<index name="{current-grouping-key()}">
<xsl:attribute name="pages">
<xsl:variable name="vAtribVals" as="xs:integer*">
<xsl:perform-sort select="current-group()/@page/xs:integer(.)">
<xsl:sort data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:sequence select=
"$vAtribVals[1],
for $k in 2 to count($vAtribVals)
return
if($vAtribVals[$k] - $vAtribVals[$k -1] ne 1)
then concat(',', $vAtribVals[$k])
else
if($vAtribVals[$k+1] - $vAtribVals[$k] ne 1)
then concat('-', $vAtribVals[$k])
else()
"/>
</xsl:attribute>
</index>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>
<index name="a" pages="1"/>
<index name="b" pages="3-4,6"/>
<index name="c" pages="7"/>
页面
属性在进一步处理之前进行排序,这样即使条目
元素在源XML文档中没有按排序顺序出现,也可以进行正确的处理我可以请你帮我理解这一点吗?我不明白的第一件事是每个组的最内层
循环中的groupby=“position()-.”
。position()
指的是什么?最里面的环?而且
来自外部组(没有意义)?
是组中的第一个元素吗?-我应该用另一个问题来解释吗?group by的总体可以在select
属性中找到,它是current-group()/xs:integer(@page)
因此它是页面
属性的整数值序列。序列中每个整数的groupby=“position()-1”
计算position()
减去该整数的表达式,这允许我们找到连续的整数序列,例如,组的总体为3,4,6
,groupby计算1-3=-2
,2-4=-2
,3-6=-3
因此对于整数3
和4
我们将它们分组。真令人印象深刻。我猜中的表达式是的,对,如果有多个项目,如果组中至少有第二个项目,那么我们输出firstItem-lastItem
,否则我们输出单个项目。