Xml 相对于前一个兄弟姐妹的位置
我试图将XML文档转换为一个列表,其中的值基于前面同级的属性 示例XML:Xml 相对于前一个兄弟姐妹的位置,xml,xslt,Xml,Xslt,我试图将XML文档转换为一个列表,其中的值基于前面同级的属性 示例XML: <myRoot> <Person>Craig</Person> <Person rank="10">Woody</Person> <Person>Brian</Person> <Person>Michael</Person> <Person rank="20"&
<myRoot>
<Person>Craig</Person>
<Person rank="10">Woody</Person>
<Person>Brian</Person>
<Person>Michael</Person>
<Person rank="20">Emily</Person>
<Person>Chris</Person>
</myRoot>
克雷格
伍迪
布瑞恩
迈克尔
艾米丽
克里斯
我想要的是:
<myNewRoot>
<Index>1: Craig</Index>
<Index>10: Woody</Index>
<Index>11: Brian</Index>
<Index>12: Michael</Index>
<Index>20: Emily</Index>
<Index>21: Chris</Index>
</myNewRoot>
1:克雷格
10:伍迪
11:Brian
12:Michael
20:Emily
21:克里斯
我被卡住了,无法确定最后一个带有@rank属性的前一个sibling与当前节点之间的距离
这是我当前的样式表
<xsl:template match="Person">
<xsl:element name="Index">
<xsl:choose>
<xsl:when test="./@rank">
<xsl:value-of select="./@rank"/>
</xsl:when>
<xsl:when test="preceding-sibling::Person[@rank]">
<xsl:value-of select="count(.|preceding-sibling::*[. > current()/preceding-sibling::Person[@rank][1]]) + preceding-sibling::Person[@rank][1]/@rank"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="position()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text>: </xsl:text>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
:
我就是无法让count()功能正常工作,结果总是
<myNewRoot>
<Index>1: Craig</Index>
<Index>10: Woody</Index>
<Index>11: Brian</Index>
<Index>11: Michael</Index>
<Index>20: Emily</Index>
<Index>21: Chris</Index>
</myNewRoot>
1:克雷格
10:伍迪
11:Brian
11:Michael
20:Emily
21:克里斯
解决方案是使用递归模板根据先前打印的值获取当前值,该值作为参数传递给模板
<xsl:output method="xml" indent="yes" />
<xsl:template match="myRoot">
<myNewRoot>
<xsl:call-template name="make-index" />
</myNewRoot>
</xsl:template>
<xsl:template name="make-index">
<xsl:param name="element" select="Person" />
<xsl:param name="count" select="'0'" />
<!-- Continue if there is some element left -->
<xsl:if test="$element">
<!-- Obtain number to be printed next -->
<xsl:variable name="next-rank">
<xsl:choose>
<!-- If the rank attribute is present, output its value -->
<xsl:when test="$element[1]/@rank">
<xsl:value-of select="$element[1]/@rank" />
</xsl:when>
<!-- If the rank attribute is not present, increase the previous
printed value by one -->
<xsl:otherwise>
<xsl:value-of select="$count + 1" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Output the index along with the value of the current index -->
<Index>
<xsl:value-of select="concat($next-rank, ': ', $element[1])" />
</Index>
<!-- Recurse until we do not have any element left -->
<xsl:call-template name="make-index">
<xsl:with-param name="element" select="$element[position() > 1]" />
<xsl:with-param name="count" select="$next-rank" />
</xsl:call-template>
</xsl:if>
</xsl:template>
更新。下面的解决方案不依赖于递归,可能不如前一个解决方案有效(在这个解决方案中有更复杂的XPath操作),但较短,并且依赖于对同级进行分组,这与前一个解决方案不同
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="myRoot">
<myNewRoot>
<!-- Print all the elements before the first element with a rank
attribute defined -->
<xsl:apply-templates select="Person[(preceding-sibling::Person[@rank])][not(@rank)]" mode="print" />
<!-- Match all the elements with a rank attribute defined -->
<xsl:apply-templates select="Person[@rank]" />
</myNewRoot>
</xsl:template>
<!-- Match the set of Person elements with @rank defined -->
<xsl:template match="Person[@rank]">
<!-- Obtain id of current node before losing the context -->
<xsl:variable name="id" select="generate-id()" />
<!-- Match the current node along all the following siblings without @rank such
as their nearest preceding-sibling with @rank defined is the current
element, i.e all the elements between the current element and the next
element with @rank defined -->
<xsl:apply-templates select=".|following-sibling::Person[not(@rank)][generate-id(preceding-sibling::Person[@rank][1]) = $id]" mode="print">
<xsl:with-param name="rank" select="@rank" />
</xsl:apply-templates>
</xsl:template>
<!-- Print the information from a Person node, using rank to determine
the position -->
<xsl:template match="Person" mode="print">
<xsl:param name="rank" select="'1'" />
<Index>
<xsl:value-of select="concat($rank + position() - 1, ': ', .)" />
</Index>
</xsl:template>
注意:我假设这两种解决方案都使用XSLT1.0。如果您使用的是XSLT2.0,那么解决方案将比以前的解决方案更简单。很高兴我提供了帮助。为了完整起见,我添加了一个不同的解决方案,采用了稍微不同的方法。