我有一个XML文档,其部分类似于以下内容:
<release_list>
<release>
<id>100</id>
<file_list>
<file>
<id>20</id>
</file>
<file>
<id>21</id>
</file>
</file_list>
</release>
<release>
<id>101</id>
<file_list>
<file>
<id>22</id>
</file>
<file>
<id>21</id>
</file>
</file_list>
</release>
<release>
<id>102</id>
<file_list>
<file>
<id>22</id>
</file>
<file>
<id>23</id>
</file>
</file_list>
</release>
</release_list>
在某些时候,我有XSL for-each循环遍历每个版本,然后遍历每个文件列表。当我循环遍历每个文件时,我想获得有关哪些其他版本不包含相同文件ID的信息。 (例如,当我在版本100中迭代文件20时,我想获得指向发行版101和102的指针,但是当我在同一个包中迭代文件21时,我只想要一个指向发行版102的指针。)
有没有办法用XPath做到这一点?我最接近的是:
../../../release[ not( file_list/file/id = ./id ) ]
...当然失败了,因为在方括号内,'./'指的是括号前面的释放,而不是调用XPath语句的文件。
我在这里缺少什么?
答案 0 :(得分:3)
在XSLT中这样的事情的一个好方法是在外层使用变量,然后你可以在选择路径中与它进行比较。例如,像
这样的东西<xsl:variable name="id" select="id" />
<xsl:apply-templates select="/release_list/release[not(file_list/file/id = $id)]" />
可以帮到你。
答案 1 :(得分:3)
在谓词(方括号中的表达式)中,您可以使用the current()
function获取当前节点(而不是.
返回的上下文节点)。
但是,您应该将方法改为Peter Cooper Jr's answer。在XSLT中,最好在最外层进行过滤,以便只处理您需要的内容,而不是尝试处理所有内容,然后从内部强加排除。
同样值得理解的是,你根本没有使用循环; XSLT中的for-each
是映射,而不是循环。换句话说,没有做第一个元素的概念,然后是第二个元素,然后是第三个元素......在概念意义上,所有匹配的元素都是同时处理的。这就是常见问题“如何在XSLT中摆脱循环?”的原因。只能用Matrix启发的词语来回答:“没有循环。”
答案 2 :(得分:0)
这是一个完整的解决方案,可以满足您的需求。当应用于您的示例输入XML时,以下XSLT 1.0样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="release">
<xsl:copy>
<xsl:copy-of select="id" />
<xsl:apply-templates select="file_list/file" mode="show-other" />
</xsl:copy>
</xsl:template>
<xsl:template match="file" mode="show-other">
<xsl:copy>
<xsl:copy-of select="id" />
<!-- select all releases that do not contain any file with the same
id as the current file -->
<xsl:variable name="other" select="
/release_list/release[not(current()/id = file_list/file/id)]
" />
<releases-without-that-file>
<xsl:copy-of select="$other/id" />
</releases-without-that-file>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
产生
<release>
<id>100</id>
<file>
<id>20</id>
<releases-without-that-file>
<id>101</id>
<id>102</id>
</releases-without-that-file>
</file>
<file>
<id>21</id>
<releases-without-that-file>
<id>102</id>
</releases-without-that-file>
</file>
</release>
<release>
<id>101</id>
<file>
<id>22</id>
<releases-without-that-file>
<id>100</id>
</releases-without-that-file>
</file>
<file>
<id>21</id>
<releases-without-that-file>
<id>102</id>
</releases-without-that-file>
</file>
</release>
<release>
<id>102</id>
<file>
<id>22</id>
<releases-without-that-file>
<id>100</id>
</releases-without-that-file>
</file>
<file>
<id>23</id>
<releases-without-that-file>
<id>100</id>
<id>101</id>
</releases-without-that-file>
</file>
</release>
请注意
/release_list/release[not(current()/id = file_list/file/id)]
与
不同/release_list/release[current()/id != file_list/file/id]
因为=
与节点集中的任何节点进行比较(如果所有节点仅匹配,则返回true
),而!=
运算符与仅限节点集的第一个节点。