如何将逗号分隔列表中的元素与XSLT组合?

时间:2014-12-02 22:29:14

标签: xml xslt xpath

我有以下代码,如果Destination不存在,则不应显示Terminal或Attention。

<?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:import href="Request.xsl" />
    <xsl:template name="Params">
        <xsl:apply-templates select="/Params/Destinations"/>
    </xsl:template>
    <xsl:template name="Params">
        <xsl:choose>
            <xsl:when test="string-length($Destinations) &gt; 0">
                <xsl:value-of select="$Destinations"/>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

    <xsl:variable name="Desinations">
        <xsl:for-each select="/Params/Destination1/text() |
                          /Params/Destination2/text() |
                          /Params/Destination3/text() |
                          /Params/Destination4/text() |
                          /Params/Destination5/text()">
            <xsl:value-of select="."/>
            <xsl:if test="name(.) = 'Destination1'">
                <xsl:apply-templates select="/Params/Terminal1"/>
                <xsl:apply-templates select="/Params/Attention1"/>
            </xsl:if>
                <!-- This xsl:if is repeated 5 more times with Destination2, Destination3, etc. --> 
            <xsl:if test="not(position() = last())">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="Destination1">
        <!-- Covered in the Destinations template -->
    </xsl:template>

    <xsl:template match="Terminal1">
        <xsl:if test="(. != '')">
            <xsl:text>-</xsl:text>
            <xsl:copy-of select="." />
        </xsl:if>
    </xsl:template>

    <xsl:template match="Attention1">
        <xsl:if test="(. != '')">
            <xsl:text>-</xsl:text>
            <xsl:copy-of select="." />
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

我希望能够得到这样的结果:

  

Destination1-Terminal1,Destination2-Terminal2,Destination3-Terminal3-Attention3

我得到以下结果:

  

Destination3,Destination1,Destination2-Terminal2-Terminal3-Attention3

如您所见,目的地无序,Terminal1丢失,所有其他Terminal和Attention元素都附加到Destination2。

我不太确定如何将Destination-Terminal-Attention元素组合在一起,并将逗号放在该集合中的最后一个元素之后。例如,如果Attention没有值,我希望逗号到达终端后,如果Terminal或Attention都没有值,则逗号应该在Destination之后。

添加了XML源:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:include href="../base/Formatting.xsl" />

    <xsl:template match="/">
        <xsl:text>TO/</xsl:text>
        <xsl:call-template name="Destinations"/>
        <xsl:apply-templates select="Params"/>
    </xsl:template>

    <xsl:template name="Destinations" />

    <xsl:template name="Params"/>

    <xsl:template match="Params">
        <xsl:call-template name="Params"/>
    </xsl:template>
</xsl:stylesheet>

编辑:我只是通过调用Destinations对Params模板进行了更改。现在没有终端或关注字段出现,所以可能是倒退了一步。

2 个答案:

答案 0 :(得分:0)

在XPath中,|实际上是一个set-union操作,并不保证结果的任何特定顺序。您可以通过向for-each循环添加显式<xsl:sort>来确保文档顺序扫描。 How to do an XSL:for-each in reverse order显示了如何向后扫描结果集;将“降序”改为“升序”应该做你想做的事。

或者你可以摆脱xsl:for-each并将其替换为xsl:apply-templates,将for-each的主体移动到合适的模板中。申请操作processes the selected nodes in document order unless overridden by an <xsl:sort>

通常情况下,如果您认为自己需要xsl:for-each,那么您可能应该查看xsl:apply-templates(可能使用mode),除非您特别希望详细控制结果的顺序。 XSLT是一种非过程语言,如果你以这种方式使用它,效果最好 - “处理这些”而不是“循环这些”。

答案 1 :(得分:0)

我能够使用keshlam提供的一些建议来解决这个问题。在我的情况下,我无法访问另一个用户询问的XML输入。我认为它是在应用程序中以编程方式生成的。我的解决方案可能是XSLT的憎恶,但鉴于我的限制,它的工作原理。

我稍微修改了xsl:variable目的地:

<xsl:variable name="Destinations">
    <xsl:for-each select="/StatelinkQuery/Arguments/Destination1 |
                          /StatelinkQuery/Arguments/Destination2 |
                          /StatelinkQuery/Arguments/Destination3 |
                          /StatelinkQuery/Arguments/Destination4 |
                          /StatelinkQuery/Arguments/Destination5">
        <xsl:sort select="name()" order="ascending"/>
        <xsl:apply-templates select="."/>
        <xsl:if test="not(position() = last())">
            <xsl:text>,</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

每个目的地的模板已更改为:

<xsl:template match="Destination1">
    <xsl:value-of select="." />
    <xsl:apply-templates select="/StatelinkQuery/Arguments/Terminal1"/>
    <xsl:apply-templates select="/StatelinkQuery/Arguments/Attention1"/>
</xsl:template>