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 中找到名称为testnamelabel。在那里我想找到一个名为enlocale。但它不起作用。 当我用星号替换特定元素(标签和语言环境)的名称时,它会起作用:

<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']

查找不在命名空间中的&lt;label&gt; 元素,以及不在命名空间中的&lt;locale&gt; 元素。而在 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']

一切都会开始奏效。


就我个人而言,我不会使用&lt;xsl:param&gt; 来完成您的工作。我将设置一个没有命名空间的补充 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中如何通过一个元素去查找该元素的子元素节点

jquery查找元素

xpath按元素和属性查找节点,其中包含具有特定id的子元素

XSL 获取元素值并忽略嵌套元素

javascript中的子节点查找,childNodes和children