如何在 XSL 中迭代多节点结构

发布于 2024-10-22 08:25:10 字数 1669 浏览 3 评论 0原文

我需要迭代多节点结构,但该结构仅由前导节点标识,并且该前导节点后面的节点可能会有所不同。

在此示例中,我需要迭代每个 -some_nodes</code>、<code><title>-some_other_nodes</code> 块

XML 文件:

<books>
    <title>book_one</title>
    <price>price_for_book_one</price>
    <notes>notes_for_book_one</notes>

    <title>book_two</title>
    <price>price_for_book_two</price>
</books>

所需的输出:

<div class="book">
    <h1 id="title">book_one</h1>
    <h2 id="values">
        <p>price_for_book_one</p>
        <p>notes_for_book_one</p>
    </h2>
</div>

<div class="book">
    <h1 id="title">book_two</h1>
    <h2 id="values">
        <p>price_for_book_two</p>
    </h2>
</div>

我的尝试:

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <h1 id="title"><xsl:text>Title:</xsl:text>
            <xsl:value-of select="." />
        </h1>

        <h2 id="values">    
        <!-- have other templates for matching all possible following-sibling nodes -->
            <xsl:apply-templates select="following-sibling::*>
        </h2>
    </xsl:for-each>
</xsl:template>

但这只是选择标题节点而不解析任何其他节点,因为“books/title”仅选择标题节点。

注意: 是两个示例节点,</code> 节点之间可以有任何内容,我还有其他模板来处理它们,但如何选择它们是我的问题。

任何想法将不胜感激。

I need to iterate through multiple-node structures, but this structure is only identified by the leading node, and the nodes following that leading node can vary.

In this example, I need to iterate through each <title>-some_nodes, <title>-some_other_nodes block

XML file:

<books>
    <title>book_one</title>
    <price>price_for_book_one</price>
    <notes>notes_for_book_one</notes>

    <title>book_two</title>
    <price>price_for_book_two</price>
</books>

Desired output:

<div class="book">
    <h1 id="title">book_one</h1>
    <h2 id="values">
        <p>price_for_book_one</p>
        <p>notes_for_book_one</p>
    </h2>
</div>

<div class="book">
    <h1 id="title">book_two</h1>
    <h2 id="values">
        <p>price_for_book_two</p>
    </h2>
</div>

My try:

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <h1 id="title"><xsl:text>Title:</xsl:text>
            <xsl:value-of select="." />
        </h1>

        <h2 id="values">    
        <!-- have other templates for matching all possible following-sibling nodes -->
            <xsl:apply-templates select="following-sibling::*>
        </h2>
    </xsl:for-each>
</xsl:template>

But this only selects the title nodes without parsing any other nodes, since "books/title" only selects the title node.

Note: <price> and <notes> are two example nodes, there could be anything in between the <title> nodes, and I have other templates for dealing with them, but how to select them is the my problem.

Any thoughts would be greatly appreciated.

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

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

发布评论

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

评论(2

飘逸的'云 2024-10-29 08:25:10

在循环内,上下文节点是 title,因此使用 . 选择它。

您可能只需要标题后面的第一个价格和注释元素。我还使用 xsl:text 来减少每个段落中的空白。

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <p>
            <xsl:text>Title: </xsl:text>
            <xsl:value-of select="." />
        </p>
        <p>
            <xsl:text>Price: </xsl:text>
            <xsl:value-of select="following-sibling::price[1]"/>
        </p>
        <p>
            <xsl:text>Notes: </xsl:text>
            <xsl:value-of select="following-sibling::notes[1]"/>
        </p>
    </xsl:for-each>
</xsl:template>

如果每个 title 之间的附加节点不固定,您可以使用模板来处理每个节点。这里重要的是用于选择属于当前标题的非标题元素的 XPath 表达式。

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <p>
            <xsl:text>Title:</xsl:text>
            <xsl:value-of select="." />
        </p>
        <xsl:apply-templates select="following-sibling::*[
                                       local-name() != 'title' and
                                       preceding-sibling::title[1] = current()]"/>
    </xsl:for-each>
</xsl:template>

<xsl:template match="price">
    <p>
        <xsl:text>Price: </xsl:text>
        <xsl:value-of select="."/>
    </p>
</xsl:template>

Inside your loop the context node is title, so it is selected with ..

You probably only want the first price and notes elements that follow a title. I have also used xsl:text to reduce the whitespace in each paragraph.

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <p>
            <xsl:text>Title: </xsl:text>
            <xsl:value-of select="." />
        </p>
        <p>
            <xsl:text>Price: </xsl:text>
            <xsl:value-of select="following-sibling::price[1]"/>
        </p>
        <p>
            <xsl:text>Notes: </xsl:text>
            <xsl:value-of select="following-sibling::notes[1]"/>
        </p>
    </xsl:for-each>
</xsl:template>

If the additional nodes between each title are not fixed, you could handle each of them with templates. The important thing here will be the XPath expression to select the non-title elements that belong to the current title.

<xsl:template match="/">
    <xsl:for-each select="books/title">
        <p>
            <xsl:text>Title:</xsl:text>
            <xsl:value-of select="." />
        </p>
        <xsl:apply-templates select="following-sibling::*[
                                       local-name() != 'title' and
                                       preceding-sibling::title[1] = current()]"/>
    </xsl:for-each>
</xsl:template>

<xsl:template match="price">
    <p>
        <xsl:text>Price: </xsl:text>
        <xsl:value-of select="."/>
    </p>
</xsl:template>
山色无中 2024-10-29 08:25:10

首先,您似乎不需要分组。 时,才需要此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="books/*">
        <p>
            <xsl:value-of
                 select="concat(translate(
                                   substring(local-name(),1,1),
                                   'qwertyuiopasdfghjklzxcvbnm',
                                   'QWERTYUIOPASDFGHJKLZXCVBNM'
                                ),
                               substring(local-name(),2),
                                ': ',
                                .
                         )" />
        </p>
    </xsl:template>
</xsl:stylesheet> 

输出:分组

<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>

仅当您要对组执行某些操作(例如换行:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kElementByPrecedingTitle"
             match="books/*"
             use="generate-id((.|preceding-sibling::*)[self::title][last()])"/>
    <xsl:template match="books/*">
        <p>
            <xsl:value-of
                 select="concat(translate(
                                   substring(local-name(),1,1),
                                   'qwertyuiopasdfghjklzxcvbnm',
                                   'QWERTYUIOPASDFGHJKLZXCVBNM'
                                ),
                               substring(local-name(),2),
                                ': ',
                                .
                         )" />
        </p>
    </xsl:template>
    <xsl:template match="books">
        <xsl:for-each select="title">
            <div class="book">
                <xsl:apply-templates
                 select="key('kElementByPrecedingTitle',generate-id())"/>
            </div>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出:)

<div class="book">
    <p>Title: book_one</p>
    <p>Price: price_for_book_one</p>
    <p>Notes: notes_for_book_one</p>
</div>
<div class="book">
    <p>Title: book_two</p>
    <p>Price: price_for_book_two</p>
</div>

First, you don't seem to need grouping. This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="books/*">
        <p>
            <xsl:value-of
                 select="concat(translate(
                                   substring(local-name(),1,1),
                                   'qwertyuiopasdfghjklzxcvbnm',
                                   'QWERTYUIOPASDFGHJKLZXCVBNM'
                                ),
                               substring(local-name(),2),
                                ': ',
                                .
                         )" />
        </p>
    </xsl:template>
</xsl:stylesheet> 

Output:

<p>Title: book_one</p>
<p>Price: price_for_book_one</p>
<p>Notes: notes_for_book_one</p>
<p>Title: book_two</p>
<p>Price: price_for_book_two</p>

Grouping would be needed only if you are going to do something with the group, like wraping:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kElementByPrecedingTitle"
             match="books/*"
             use="generate-id((.|preceding-sibling::*)[self::title][last()])"/>
    <xsl:template match="books/*">
        <p>
            <xsl:value-of
                 select="concat(translate(
                                   substring(local-name(),1,1),
                                   'qwertyuiopasdfghjklzxcvbnm',
                                   'QWERTYUIOPASDFGHJKLZXCVBNM'
                                ),
                               substring(local-name(),2),
                                ': ',
                                .
                         )" />
        </p>
    </xsl:template>
    <xsl:template match="books">
        <xsl:for-each select="title">
            <div class="book">
                <xsl:apply-templates
                 select="key('kElementByPrecedingTitle',generate-id())"/>
            </div>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Output:

<div class="book">
    <p>Title: book_one</p>
    <p>Price: price_for_book_one</p>
    <p>Notes: notes_for_book_one</p>
</div>
<div class="book">
    <p>Title: book_two</p>
    <p>Price: price_for_book_two</p>
</div>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文