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

Xml 如何将逗号分隔列表中的元素与XSLT组合在一起?,xml,xslt,xpath,Xml,Xslt,Xpath,我有以下代码,如果目的地不存在,则不应显示终端或注意 <?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">

我有以下代码,如果目的地不存在,则不应显示终端或注意

<?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>

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

目的地1-目的地1,目的地2-目的地2,目的地3-目的地3-注意3

我得到以下结果:

目的地3,目的地1,目的地2-目的地2-目的地3-注意

如您所见,目的地出现故障,Terminal1丢失,所有其他Terminal和Attention元素都附加到Destination2

我不太清楚如何将目标终端注意元素组合在一起,并将逗号放在该集中最后一个元素之后。例如,如果Attention没有值,我希望逗号出现在终端之后,如果终端或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>

到/

Edit:我通过调用Destinations对Params模板进行了更改。现在没有显示终端字段或注意字段,因此可能是向后退了一步。

在XPath中,
|
实际上是一个集合并集操作,不保证结果的任何特定顺序。通过向for each循环中添加显式的
,可以确保文档顺序扫描。显示如何向后扫描结果集;将“降序”更改为“升序”应该可以完成您想要的操作

或者您可以去掉
xsl:for-each
,用
xsl:apply-templates
替换它,将for-each的主体移动到合适的模板中。应用操作


通常,如果您认为需要为每个使用
xsl:for-each
,您可能应该转而使用
xsl:apply-templates
(可能使用
模式
),除非您特别希望对结果顺序进行详细控制。XSLT是一种非过程性语言,如果您以这种方式使用它,它会工作得最好——“处理这些”,而不是“循环使用这些”。

我能够使用keshlam提供的一些建议来理解它。在我的例子中,我无法访问另一个用户询问的XML输入。我认为它是在应用程序中以编程方式生成的。我的解决方案可能是XSLT的一个讨厌的东西,但考虑到我的限制,它可以工作

我稍微修改了xsl:variable Destinations:

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


您可以发布一个输入示例吗?还要指出XSLT1.0或2.0。它是XSLT1.0。我是XSLT新手,所以我不确定输入示例的确切含义。它通过一种形式出现,其中每个目的地、终端、注意力都是一个字段。目标是4个字符长度的字母数字值(例如1UPD)。终端是3个字符长的字母数字值(例如US4),注意14个字符长的字母数字值。如果那不是你想要的,告诉我。谢谢XSLT的输入是一个XML文档。我们需要看到它(或者最好是一个最小化但仍然完整的例子),以便尝试和再现您的问题。当我这么做的时候:将XSLT代码最小化到只需要重现问题并使其完整的程度也是很有帮助的。(a) 在name=“Params”模板中,choose/test是不必要的,因为如果字符串长度为空,xsl:value不会输出任何内容。(b) “Params”和“Destinations”模板是相同的:为什么有两个相同的命名模板?但您的基本问题是union操作符按文档顺序对节点进行排序。值得一提的是,将元素命名为
DestinationCode1
DestinationCode2
等是非常糟糕的XML设计。这使得使用XPath或XSLT变得更加困难。如果您对此有任何控制权,我强烈建议您使用
等。例如,您的
xsl:for each
选择将立即下降到
/Params/DestinationCode/text()
。有关“/”的信息不正确。所有路径表达式(和联合表达式)都按文档顺序传递结果,这既适用于应用模板,也适用于每个模板。此外,规范的原因也不是“历史性的”:定义规则的工作组完全可以自由操作,他们选择这种设计是出于技术原因。@MichaelKay:如果我错了,请纠正我,但严格来说,我相信该规则也有例外:前面的兄弟姐妹::*,前面的::*,祖先::*和祖先或自身::*按相反顺序返回节点,即前面的同级::*[1]将返回紧靠前面的同级,而不是文档顺序中的第一个同级。(前面的兄弟姐妹::*)[1]将按照文档顺序返回第一个,但是。@MichaelKay:我将在进行完整性检查之前划掉该段落;我已经退出XSLT实现两年了。。。但我从来没有听说过对//的额外复杂性的可靠辩护,我希望能有一个指向它的指针。@Flynn1179反向轴上的数值谓词按反向文档顺序计算节点,以便过滤特定的位置步骤,对,但这并不能改变这样一个事实,即
for each
apply templates
以文档顺序提供处理所选节点集的最终结果,除非您指定
xsl:sort
@Keshlam:我没有声明我喜欢de