将 for-each 中的元素 ID 与另一个元素的 ID 匹配

Match an element's ID from within a for-each with another element's ID

提问人:payne 提问时间:2/9/2019 最后编辑:payne 更新时间:2/9/2019 访问量:288

问:

对不起,如果我的标题不是很清楚:我很难想出一个恰当的方式来简洁地表达我的问题。

这是我的结构的样子:XML

<library>
    <books>
        <book writers="007,911">
            <title>Two authors wrote me</title>
            <price>4.00</price>
        </book>
        <book writers="911">
            <title>Only one here</title>
            <price>2.50</price>
        </book>
    </books>
    <authors>
        <author id="007">
            <name>James</name>
        </author>
        <author id="911">
            <name>Police</name>
        </author>
        <author id="666">
            <name>Diablo</name>
        </author>
    </authors>
</library>

对于每个作者,我的目标是:列出他们的孩子(这里我只介绍),但也列出当前匹配至少一个 .如果未找到 -match,则不应显示该特定项的 s 列表。该列表应按所有匹配项的价格降序排序。namebookidwritersbookbookauthor

以下是我到目前为止所做的代码的基本部分:XSLT

<xsl:template match="/"> <!-- I'm skipping all the irrelevant <html> stuff, of course. -->

    <body>
        <ol> 
            <xsl:for-each select="//author">
                <li>
                    <b>ID: </b><xsl:value-of select="@id"/>
                    <ul>
                        <xsl:call-template name="auth_infos"></xsl:call-template>
                        <xsl:call-template name="books_stuff"></xsl:call-template>
                    </ul>
                </li>
            </xsl:for-each>
        </ol>
    </body>

</xsl:template>

<xsl:template name="auth_infos">
    <li><b>Name: </b><xsl:value-of select="name"/></li>
</xsl:template>

<xsl:template name="books_stuff">
    <xsl:if test="//book[//author/@id = @writers]"> <!-- This is supposed to make sure that if the author doesn't have any books listed in the database, then there shouldn't be an empty list of books. Only his name should be presented. -->
        <li><b>Book(s): </b>
            <xsl:for-each select="//book[//author/@id = @writers]">
                <xsl:sort select="price" order="descending"/> <!-- Because I would also like to sort them based on their price. -->
                <li><b>Title: </b><xsl:value-of select="//title"/></li>
            </xsl:for-each>
        </li>
    </xsl:if>
</xsl:template>

显然,我对这个特定的 XPath 表达式有问题:.我似乎不明白如何确保我只验证正在迭代的电流 id 的匹配。此外,由于 s 可以有多个( 到 的 id),我不确定如何应用运算符。"//book[//author/@id = @writers]"authorbookwritersIDREFSauthorcontains

结果将是这样的:

-ID: 007
    -Name: James
    -Book(s):
        -Title: Two authors wrote me
-ID: 911
    -Name: Police
    -Book(s):
        -Title: Two authors wrote me
        -Title: Only one here
-ID: 666
    -Name: Diablo
XML XSLT XPATH XHTML

评论

0赞 michael.hor257k 2/9/2019
这里的主要问题是不等于 .其余的都是微不足道的。您的处理器是否支持 XSLT 2.0?007007,911
0赞 payne 2/9/2019
@michael.hor257k 哼哼,我不确定。如果这是你的问题,我使用。Oxygen XML Editor 19.1
0赞 michael.hor257k 2/9/2019
不,这是我的问题:stackoverflow.com/questions/25244370/......此外,氧气是一个测试环境。重要的是您将在生产中使用的处理器。
0赞 payne 2/9/2019
@michael.hor257k 这不是用于部署,而是用于教育目的。我认为我不应该担心要使用的处理器版本。在大多数情况下,这是我们作为备忘单得到的,但它似乎相当不完整。
0赞 michael.hor257k 2/9/2019
我问的原因是因为在 XSLT 2.0 中更容易执行此任务。我不会说法语,我不明白在这种情况下“这就是我们作为备忘单得到的东西”是什么意思。这是家庭作业吗?

答:

1赞 michael.hor257k 2/9/2019 #1

假设您仅限于 XSLT 1.0,这将有点尴尬:

XSLT 1.0

<xsl:stylesheet version="1.0"   
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    
<xsl:output method="html" encoding="utf-8"/>  

<xsl:template match="/library">    
   <body>
        <ol> 
            <xsl:for-each select="authors/author">
                <xsl:variable name="books" select="../../books/book[contains(concat(',', @writers, ','), concat(',', current()/@id, ','))]"/>
                <li>
                    <b>ID: </b>
                    <xsl:value-of select="@id"/>
                    <ul>
                        <li>
                            <b>Name: </b>
                            <xsl:value-of select="name"/>
                        </li>
                        <xsl:if test="$books">
                            <li>
                                <b>Book(s): </b>
                                <ul>
                                    <xsl:for-each select="$books">
                                        <xsl:sort select="price" data-type="number" order="descending"/> 
                                        <li><b>Title: </b><xsl:value-of select="title"/></li>
                                    </xsl:for-each>
                                </ul>
                            </li>
                        </xsl:if>
                    </ul>
                </li>
            </xsl:for-each>
        </ol>
    </body>
</xsl:template>    

</xsl:stylesheet>    

应用于您的示例,结果为:

<body><ol>
<li>
<b>ID: </b>007<ul>
<li>
<b>Name: </b>James</li>
<li>
<b>Book(s): </b><ul><li>
<b>Title: </b>Two authors wrote me</li></ul>
</li>
</ul>
</li>
<li>
<b>ID: </b>911<ul>
<li>
<b>Name: </b>Police</li>
<li>
<b>Book(s): </b><ul>
<li>
<b>Title: </b>Two authors wrote me</li>
<li>
<b>Title: </b>Only one here</li>
</ul>
</li>
</ul>
</li>
<li>
<b>ID: </b>666<ul><li>
<b>Name: </b>Diablo</li></ul>
</li>
</ol></body>

呈现为:

enter image description here

评论

0赞 payne 2/9/2019
这行得通。 :有趣的台词,那里!不确定我自己会不会想通。随意添加有关该表达式工作原理的更多细节。我现在也很好奇一个版本会好多少。"../../books/book[contains(concat(',', @writers, ','), concat(',', current()/@id, ','))]"XSLT 2.0
1赞 michael.hor257k 2/9/2019
@payne 它通过搜索 in - IOW 来工作,无论它在搜索文本中的位置如何,它都会明确地找到搜索字符串。在 XSLT 2.0 中,您可以使用该函数来解析搜索到的文本,然后进行比较,或者(甚至更好)将其用作,007,,007,911,tokenize()=
0赞 payne 2/12/2019
我刚刚意识到我的 XML 格式不正确:在同一属性中引用多个 ID 的方法是将它们与 而不是 .:(SPACES ( )COMMAS (,)
0赞 payne 2/12/2019
它使它变得简单得多!溶液:。谢谢你的帮助。//book[contains(@writers, current()/@id)]
1赞 michael.hor257k 2/12/2019
@payne 使用哪种分隔符并不重要。问题是误报:(例如 包含或 )。仅当所有 ID 的长度相同时,您的解决方案才有效。1271227