XSL 节点集:不按名称查找子元素
Posted
技术标签:
【中文标题】XSL 节点集:不按名称查找子元素【英文标题】:XSL nodeset: do not find child elements by name 【发布时间】:2019-01-18 03:42:18 【问题描述】:我是 xsl 的初学者,所以也许这是一个非常简单的问题。 我有一个 xsl 文件,我想在其中找到在 param-object 中定义的特定值:
<xsl:param name="locales">
<label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>
<xsl:template match="foo">
<topLevelElement xmlns="http://foo.bar.org">
<xsl:value-of select="ext:node-set($locales)/label[@name='testname']/locale[@name='en']"/>
</topLevelElement>
</xsl:template>
我希望得到值'english text',因为我想在参数locales
中找到名称为testname
的label
。在那里我想找到一个名为en
的locale
。但它不起作用。
当我用星号替换特定元素(标签和语言环境)的名称时,它会起作用:
<xsl:param name="locales">
<label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>
<xsl:template match="foo">
<topLevelElement xmlns="http://foo.bar.org">
<xsl:value-of select="ext:node-set($locales)/*[@name='testname']/*[@name='en']"/>
</topLevelElement>
</xsl:template>
谁能告诉我为什么我找不到孩子的名字? 非常感谢!
编辑: 该代码没有显示名称空间(我猜它是由浏览器解释的)。开头和结尾都没有括号:
xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://foo.bar.org" xmlns:ext="http://exslt.org/common" version="1.0" xsl:output method="xml" version="1.0" encoding="UTF-8"/
【问题讨论】:
让我猜猜:在您的 XSLT 文件中定义了一个xmlns="..."
默认命名空间。
是的,我有。我已经编辑了我的问题。那么它有什么问题呢?我的标签和语言环境现在是否有另一个命名空间,所以我找不到它们?
函数减速'ext:node-set(...)'在哪里?
【参考方案1】:
所以你有
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://foo.bar.org"
xmlns:ext="http://exslt.org/common"
>
这定义了一个默认命名空间。这意味着您的 XSLT 程序创建的每个 XML 元素(不是使用命名空间显式创建的)都将位于该命名空间中。这也适用于您不输出的任何元素。
这意味着您不能再使用“普通”XPath 选择这些元素,因为普通 XPath 假定元素不在命名空间中。
ext:node-set($locales)/label[@name='testname']/locale[@name='en']
查找不在命名空间中的<label>
元素,以及不在命名空间中的<locale>
元素。而在 XPath 中引用命名空间的方法是使用前缀。
所以你可以给这个命名空间一个前缀,只是为了内部处理。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://foo.bar.org"
xmlns:foo="http://foo.bar.org"
xmlns:ext="http://exslt.org/common"
>
这里"http://foo.bar.org"
命名空间被声明为默认,但也有前缀foo
。现在你可以这样做了:
ext:node-set($locales)/foo:label[@name='testname']/foo:locale[@name='en']
一切都会开始奏效。
就我个人而言,我不会使用<xsl:param>
来完成您的工作。我将设置一个没有命名空间的补充 XML 文档,将其命名为 locales.xml
,然后执行:
<!-- top-level -->
<xsl:variable name="locales" select="document('locales.xml')" />
<!-- ...later -->
<xsl:value-of select="$locales/*/label[@name='testname']/locale[@name='en']" />
这种方式既不需要辅助命名空间也不需要ext:node-set()
,并且增加了模块化。
【讨论】:
非常感谢您提供的所有信息!这对我帮助很大。我会考虑您使用补充 XML 文件的建议。【参考方案2】:在不更改 XPath 的情况下修复它的一种方法是更改
<xsl:param name="locales">
<label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>
到
<xsl:param name="locales" xmlns="">
<label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>
【讨论】:
谢谢!这是一个非常适合我的简单解决方案! @Markus 也考虑一下我答案的下半部分。命名空间和node-set()
甚至都不需要。
是的,非常感谢 tomalak。我会考虑你的解决方案。但是我是 xsl 的新手,所以需要一些时间才能完全理解您的解决方案;)但是您的回答对我有很大帮助。以上是关于XSL 节点集:不按名称查找子元素的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript中如何通过一个元素去查找该元素的子元素节点