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