2009-11-05 128 views
2

我有类似以下的区间中的XML文档:用于根据当前节点的内容选择父节点的XPath?

<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语句正在从中调用。

我在这里失踪的任何东西?

回答

3

在XSLT中,一个好的方法是在外层使用变量,然后在选择路径中对它进行比较。所以,举个例子,像

<xsl:variable name="id" select="id" /> 
<xsl:apply-templates select="/release_list/release[not(file_list/file/id = $id)]" /> 

可能会帮助你。

+0

由于某种原因,我的印象是XSLT中的变量只写一次,因此它们的功用有限 - 但事实并非如此。非常感谢! – Chris 2009-11-05 19:00:47

+1

虽然只写是真的。 ;-) – Tomalak 2009-11-05 19:01:20

3

在谓词(方括号中的表达式)中,可以使用the current() function来获取当前节点(与由.返回的上下文节点相反)。

但是你应该改变你的方法,像Peter Cooper Jr's answer。在XSLT中,在最外层过滤几乎总是更好,以便只处理您所需的内容,而不是尝试处理所有内容,然后从内部强加排除。

这也值得了解,你根本没有使用循环;在XSLT中for-each是一个映射,而不是一个循环。换句话说,没有做第一个元素的概念,然后是第二个元素,然后是第三个元素......在概念意义上,所有匹配元素都是同时处理的。这就是为什么经常问的问题“我如何摆脱XSLT中的循环?”只能用矩阵启发的话来回答:“没有循环。”

+0

我希望我可以添加两个接受的答案,因为这与Peter Cooper Jr的答案一样有帮助。 current()函数确实做了我想要的代码,但是我可以看到你对使用该模板也是正确的。 – Chris 2009-11-05 19:03:30

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),而!=运算符仅与节点集的第一个节点进行比较。

相关问题