Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml 相对于前一个兄弟姐妹的位置_Xml_Xslt - Fatal编程技术网

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"&

我试图将XML文档转换为一个列表,其中的值基于前面同级的属性

示例XML:

<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::*[. &gt; 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,那么解决方案将比以前的解决方案更简单。

很高兴我提供了帮助。为了完整起见,我添加了一个不同的解决方案,采用了稍微不同的方法。