我试图通过动态创建xpath来获取xml节点的属性值。但它一直在返回空值。如果我硬编码xpath,它工作正常。下面是一个示例xml文件:
<root>
<PR id="id6016" name="OUTER WORLD">
<ADS id="id6017" dsRef="#id15" role="form1">
</ADS>
<ADS id="id6018" dsRef="#id9" role="form1">
</ADS>
</PR>
<PR id="id1000" name="OUTER WORLD">
<ADS id="id1001" dsRef="#id16" role="form1">
</ADS>
<ADS id="id1002" dsRef="#id10" role="form1">
</ADS>
</PR>
<DS id="id9" name="form1" version="7" type="CAD">
</DS>
<DS id="id15" name="form1" version="1" type="MSWord">
</DS>
<DS id="id10" name="form1" version="1" type="CAD">
</DS>
<DS id="id16" name="form1" version="1" type="MSWord">
</DS>
</root>
我的样本xsl是:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="no" encoding="utf-8"/>
<xsl:template match="/root">
<result>
<xsl:apply-templates select="PR" mode="PR" />
</result>
</xsl:template>
<xsl:template match="PR" mode="PR">
<PR>
<xsl:attribute name="id">
<xsl:value-of select="@id" />
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="@name" />
</xsl:attribute>
<xsl:for-each select="ADS[@role='form1']">
<DS>
<xsl:attribute name="id">
<xsl:value-of select="string(substring-after(@dsRef, '#'))" />
</xsl:attribute>
<xsl:value-of select="../DS[@id=string(substring-after(@dsRef, '#'))]/@type" />
</DS>
</xsl:for-each>
<DS2>
<xsl:value-of select="../DS[@id='id9']/@type" />
</DS2>
<DS3>
<xsl:value-of select="../DS[@id=string(substring-after(@dsRef, '#'))]/@type" />
</DS3>
</PR>
</xsl:template>
</xsl:stylesheet>
正如您所看到的,我获得了DS2标签的任何内容,但没有DS或DS3。我还在DS标记中添加了id属性,以显示我获得的ID是好的。
最终我想过滤类型为&#34; CAD&#34;的DS标签。并将它的id存储在一个变量中,但是现在我无法使用xpath获取xml节点,所以我被卡住了。
答案 0 :(得分:0)
如果我已正确理解您对问题的描述,请说明
<xsl:value-of select="../DS[@id='id9']/@type" />
DS2元素中的产生预期值和期望值,但是指令
<xsl:value-of select="../DS[@id=string(substring-after(@dsRef, '#'))]/@type" />
DS3元素中的不是。类似地,在xsl:for-each中生成的DS元素的@id属性带有期望值,但元素内容不符合预期。 (专业提示:如果不能理解你得到的东西与你的期望和想要的不同,你会有更好的运气引出Stack Overflow问题的答案。)
这里有两个问题。
首先,对@dsRef
的引用在xsl:for-each的第一个xsl:value-of中成功,因为该属性引用的context元素是带有dsRef
元素的ADS元素。在xsl:for-each的第二个xsl:value-of中对@dsRef
的引用失败,因为它在谓词中,而context元素是在其上测试谓词的DS元素。 DS3调试元素中对@dsRef
的引用同样是对不存在的“dsRef”的引用。 DS元素的属性。
有两种方法可以解决这个问题。您可以阅读current()
,其中包括从谓词内部指向整个XPath表达式的上下文元素,并将属性引用重写为current()/@dsRef
之类的内容。很多人会推荐这条路。
或者您可以避免必须了解current()
以及它在任何给定点攀爬的上下文节点堆栈的确切步数,并将您想要的值绑定到您可以在其中引用的变量表达。 (我从经验中知道,可以花费数年时间编写XSLT程序,而且永远不需要理解current()
的所有细节。)在这种情况下,你的for-each会是这样的:
<xsl:for-each select="ADS[@role='form1']">
<xsl:variable name="targetDS" select="substring-after(@dsRef,'#')"/>
<DS>
<xsl:attribute name="id">
<xsl:value-of select="$targetDS" />
</xsl:attribute>
<xsl:value-of select="../DS[@id=$targetDS]/@type" />
</DS>
</xsl:for-each>
您可能会发现(正如我所知)在命名变量中使用目标ID可以更容易理解两个指令值的作用。
但是,在此更改之后,您的程序仍无效。
您的第二个问题是您正在寻找当前ADS元素的兄弟姐妹中的DS元素,但您输入中的ADS元素实际上没有DS兄弟;他们都是公关的兄弟姐妹。如果&#39; id&#39;元素上的属性表现为XML ID,然后元素的层次结构位置并不重要,而且表达式更简单,如
//DS[@id=$targetDS]
会更有弹性(更清晰)。如果你有一个DTD和&#39; id&#39;属性被声明为具有类型ID,写入
更简单id($targetDS)
表示ID为$ targetDS&#39;的元素。如果由于某种原因,您确实希望将表达式限制为输入文档的特定区域中的DS元素,则需要确保正确引用该区域。在我用..
替换../..
之后,样式表产生了我认为的预期结果。