如何在for-each循环中找到与xslt属性值匹配的元素

时间:2022-11-29 14:27:47

Suppose I have the following XML:

假设我有以下XML:

<data>
  <foos>
    <foo id="1" checked="yes" />
    <foo id="2" />
    <foo id="3" />
    <foo id="4" checked="yes" />
  </foos>
  <bars>
    <bar for="1" name="blub" />
    <bar for="2" name="bla" />
    <bar for="3" name="baz" />
    <bar for="4" name="plim" />
  </bars>
</data>

Now I want to print all the name attributes of those element bar which point to an element foo that has the attribute checked. So for the example above, my xslt would output blub and plim.

现在我想打印那些元素栏的所有名称属性,这些属性指向一个已检查属性的元素foo。所以对于上面的例子,我的xslt将输出blub和plim。

Here is what I have tried so far is to just check whether I can print the id attribute of the foo element that each bar belongs to:

到目前为止,我所尝试的只是检查是否可以打印每个条形所属的foo元素的id属性:

<xsl:template match="/">
  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="../../foos/foo[@id=./@for]/@id" />
  </xsl:for-each>
</xsl:template>

but to no avail. I think the problem is, that the check foo[@id=./@for] will select both @id and @for from the foo element. So how can I say that I want the @for attribute from my current element in the for loop but the @id from the other current element?

但无济于事。我认为问题是,check foo [@id =。/ @ for]将从foo元素中选择@id和@for。那么我怎么能说我想在for循环中从当前元素获取@for属性,而从另一个当前元素中获取@id?

3 个解决方案

#1


5  

how can I say that I want the @for attribute from my current element in the for loop but the @id from the other current element?

我怎么能说我想要for循环中当前元素的@for属性,而是来自其他当前元素的@id?

Use the current() function:

使用current()函数:

<xsl:value-of select="../../foos/foo[@id=current()/@for]/@id" />

Inside the square brackets, . is the node that the predicate is testing, whereas current() is the node that is the current target of the for-each.

在方括号内,。是谓词正在测试的节点,而current()是for-each的当前目标的节点。

#2


1  

As an alternative that should also improve performance you can define a key

作为替代方案,还应该提高性能,您可以定义密钥

<xsl:key name="foo-by-id" match="foos/foo" use="@id"/>

and then replace

然后更换

  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="../../foos/foo[@id=./@for]/@id" />
  </xsl:for-each>

with

  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="key('foo-by-id', @for)/@id" />
  </xsl:for-each>

#3


0  

To build on the xsl:key idea from @martin-honnen, make a key for the checked items:

要构建来自@ martin-honnen的xsl:key构思,请为已检查项创建一个键:

<xsl:key name="checked" match="foos/foo[@checked = 'yes']" use="@id" />

Then your XSLT can become:

然后你的XSLT可以成为:

<xsl:template match="/">
  <xsl:apply-templates select="/data/bars/bar[key('checked', @for)]" />
</xsl:template>

<xsl:template match="bar">
  <xsl:value-of select="@name" />
</xsl:template>

Only the foo with checked="yes" are included in the checked key (though if you are working from HTML, it's more likely that it's checked="checked"). key('checked', @for) for an element without a corresponding checked="yes" will return an empty node-set/empty sequence (depending on your XSLT version), so for those elements, the predicate will evaluate to false, so the xsl:apply-templates selects only the elements that you are interested in, so the template for bar becomes very simple.

只有带有checked =“yes”的foo才会包含在已检查的密钥中(但如果您使用的是HTML,那么它更有可能被检查=“已检查”)。没有相应的checked =“yes”的元素的key('checked',@ for)将返回一个空的node-set / empty序列(取决于你的XSLT版本),因此对于这些元素,谓词将评估为false,所以xsl:apply-templates只选择你感兴趣的元素,因此bar的模板变得非常简单。

#1


5  

how can I say that I want the @for attribute from my current element in the for loop but the @id from the other current element?

我怎么能说我想要for循环中当前元素的@for属性,而是来自其他当前元素的@id?

Use the current() function:

使用current()函数:

<xsl:value-of select="../../foos/foo[@id=current()/@for]/@id" />

Inside the square brackets, . is the node that the predicate is testing, whereas current() is the node that is the current target of the for-each.

在方括号内,。是谓词正在测试的节点,而current()是for-each的当前目标的节点。

#2


1  

As an alternative that should also improve performance you can define a key

作为替代方案,还应该提高性能,您可以定义密钥

<xsl:key name="foo-by-id" match="foos/foo" use="@id"/>

and then replace

然后更换

  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="../../foos/foo[@id=./@for]/@id" />
  </xsl:for-each>

with

  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="key('foo-by-id', @for)/@id" />
  </xsl:for-each>

#3


0  

To build on the xsl:key idea from @martin-honnen, make a key for the checked items:

要构建来自@ martin-honnen的xsl:key构思,请为已检查项创建一个键:

<xsl:key name="checked" match="foos/foo[@checked = 'yes']" use="@id" />

Then your XSLT can become:

然后你的XSLT可以成为:

<xsl:template match="/">
  <xsl:apply-templates select="/data/bars/bar[key('checked', @for)]" />
</xsl:template>

<xsl:template match="bar">
  <xsl:value-of select="@name" />
</xsl:template>

Only the foo with checked="yes" are included in the checked key (though if you are working from HTML, it's more likely that it's checked="checked"). key('checked', @for) for an element without a corresponding checked="yes" will return an empty node-set/empty sequence (depending on your XSLT version), so for those elements, the predicate will evaluate to false, so the xsl:apply-templates selects only the elements that you are interested in, so the template for bar becomes very simple.

只有带有checked =“yes”的foo才会包含在已检查的密钥中(但如果您使用的是HTML,那么它更有可能被检查=“已检查”)。没有相应的checked =“yes”的元素的key('checked',@ for)将返回一个空的node-set / empty序列(取决于你的XSLT版本),因此对于这些元素,谓词将评估为false,所以xsl:apply-templates只选择你感兴趣的元素,因此bar的模板变得非常简单。