xslt 在不同的节点上?

发布于 2024-09-28 05:09:23 字数 709 浏览 5 评论 0原文

我有以下架构:

<parent>
  <child id="1" name="Child 1 Version 1" />
</parent>
<parent>
  <child id="2" name="Child 2 Version 1" />
</parent>
<parent>
  <child id="1" name="Child 1 Version 2" />
</parent>

我只想处理每个 id 的最后一个节点。以下是我根据一些阅读尝试过的方法:

  <xsl:for-each select="//parent/child">
    <xsl:sort select="@id"/>
    <xsl:if test="not(@id=following-sibling::*/@id)">
      <xsl:element name="child">
        <xsl:value-of select="@name"/>
      </xsl:element>
    </xsl:if>
  </xsl:for-each>

但它似乎不起作用。我的输出仍然包含所有三个元素。关于我可以采取哪些措施来纠正我的问题有什么想法吗?

I have the following schema:

<parent>
  <child id="1" name="Child 1 Version 1" />
</parent>
<parent>
  <child id="2" name="Child 2 Version 1" />
</parent>
<parent>
  <child id="1" name="Child 1 Version 2" />
</parent>

I want to handle only the last node for each id. Below is what I have tried based on some reading:

  <xsl:for-each select="//parent/child">
    <xsl:sort select="@id"/>
    <xsl:if test="not(@id=following-sibling::*/@id)">
      <xsl:element name="child">
        <xsl:value-of select="@name"/>
      </xsl:element>
    </xsl:if>
  </xsl:for-each>

But it does not seem to work. My output still contains all three elements. Any ideas on what I can do to correct my issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萤火眠眠 2024-10-05 05:09:23

我只想处理最后一个
每个 id 的节点。以下是我所拥有的
根据一些阅读尝试:

  <xsl:for-each select="//parent/child"> 
    <xsl:sort select="@id"/> 
    <xsl:if test="not(@id=following-sibling::*/@id)"> 
      <xsl:element name="child"> 
        <xsl:value-of select="@name"/> 
      </xsl:element> 
    </xsl:if> 
  </xsl:for-each> 

但是好像不行。我的
输出仍然包含所有三个
元素。关于我能做什么的任何想法
纠正我的问题?

此代码的问题是,即使节点位于已排序的节点集中,它们的 following-sibling 仍然是文档中的节点。

为了使此代码正常工作,首先创建一个全新的文档,其中节点以所需的方式排序,然后(在 XSLT 1.0 中,需要使用 xxx:node-set() 生成的 RTF 上的扩展名,使其成为普通的 XML 文档)在此文档上,节点根据需要具有其同级节点。

解决方案

此转换提供了一种可能的 XSLT 1.0 解决方案,不需要使用扩展函数:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kchildById" match="child" use="@id"/>

 <xsl:template match="/*">
  <t>
    <xsl:apply-templates select=
    "*/child[generate-id()
            =
             generate-id(key('kchildById',
                             @id)[last()]
                         )
            ]
    "/>
  </t>
 </xsl:template>

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

当应用于提供的 XML 片段时(包装在顶部元素中以变得很好) -形成的 XML 文档并为 id="2" 添加第二个版本):

<t>
    <parent>
        <child id="1" name="Child 1 Version 1" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 1" />
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 2" />
    </parent>
</t>

产生想要的结果

<t>
   <child>Child 1 Version 2</child>
   <child>Child 2 Version 2</child>
</t>

请注意:使用慕尼黑分组方法。

That I want to only handle the last
node for each id. Below is what I have
tried based on some reading:

  <xsl:for-each select="//parent/child"> 
    <xsl:sort select="@id"/> 
    <xsl:if test="not(@id=following-sibling::*/@id)"> 
      <xsl:element name="child"> 
        <xsl:value-of select="@name"/> 
      </xsl:element> 
    </xsl:if> 
  </xsl:for-each> 

But it does not seem to work. My
output still contains all three of the
elements. Any ideas on what I can do
to correct my issue?

The problem with this code is that even though the nodes are in a sorted node-set, their following-sibling s are still the ones in the document.

In order for this code to work, one would first create an entirely new document in which the nodes are sorted in the desired way, then (in XSLT 1.0 it is necessary to use the xxx:node-set() extension on the produced RTF to make it an ordinary XML document) on this document the nodes have their siblings as desired.

Solution:

This transformation presents one possible XSLT 1.0 solution that does not require the use of extension functions:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kchildById" match="child" use="@id"/>

 <xsl:template match="/*">
  <t>
    <xsl:apply-templates select=
    "*/child[generate-id()
            =
             generate-id(key('kchildById',
                             @id)[last()]
                         )
            ]
    "/>
  </t>
 </xsl:template>

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

when applied on the provided XML fragment (wrapped in a top element to become well-formed XML document and adding a second version for id="2"):

<t>
    <parent>
        <child id="1" name="Child 1 Version 1" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 1" />
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 2" />
    </parent>
</t>

produces the wanted result:

<t>
   <child>Child 1 Version 2</child>
   <child>Child 2 Version 2</child>
</t>

Do note: the use of the Muenchian method for grouping.

国粹 2024-10-05 05:09:23

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kParentByChildId" match="parent" use="child/@id"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="parent[count(.|key('kParentByChildId',
                                            child/@id)[last()]) != 1]"/>
</xsl:stylesheet>

输出:

<root>
    <parent>
        <child id="2" name="Child 2 Version 1"></child>
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2"></child>
    </parent>
</root>

注释。按@id分组,选择组中的最后一个。

编辑:以防万一这令人困惑。上面的样式表意味着:复制除那些没有最后一个@id同类的之外的所有内容。因此,它不是选择组中的最后一个,而是作为反向逻辑,条带化不是组中的最后一个。

第二。为什么你的不工作?嗯,因为following-sibling 轴。您找到第一个同类的方法来自于旧时代,当时几乎没有处理器实现密钥。现在那些日子已经一去不复返了。

因此,这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="t">
        <xsl:for-each select="parent/child">
            <xsl:sort select="@id"/>
            <xsl:if test="not(@id=following::child/@id)">
                <xsl:element name="child">
                    <xsl:value-of select="@name"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出:

<child>Child 1 Version 2</child>
<child>Child 2 Version 1</child>

注意跟随轴,因为元素没有兄弟元素。

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kParentByChildId" match="parent" use="child/@id"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="parent[count(.|key('kParentByChildId',
                                            child/@id)[last()]) != 1]"/>
</xsl:stylesheet>

Output:

<root>
    <parent>
        <child id="2" name="Child 2 Version 1"></child>
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2"></child>
    </parent>
</root>

Note. Grouping by @id, selecting last of the group.

Edit: Just in case this is confusing. Above stylesheet means: copy everything execpt those child not having the last @id of the same kind. So, it's not selecting the last of the group, but as reverse logic, striping not last in the group.

Second. Why yours is not working? Well, because of the following-sibling axis. Your method for finding the first of a kind is from an old time where there was few processor implementing keys. Now those days are gone.

So, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="t">
        <xsl:for-each select="parent/child">
            <xsl:sort select="@id"/>
            <xsl:if test="not(@id=following::child/@id)">
                <xsl:element name="child">
                    <xsl:value-of select="@name"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Output:

<child>Child 1 Version 2</child>
<child>Child 2 Version 1</child>

Note: following axis, because child elements have not siblings.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文