首页 文章

如何使用xslt选择第一次出现的节点

提问于
浏览
4

我有一个xml,如:

<bookstores>
    <bookstore>
        <book id="1">
            <author>ABC</author> 
        </book>
        <book id="2">
            <title>YYY</title> 
        </book>
    </bookstore>
    <bookstore>
        <book id="3">
            <author>ABC</author> 
        </book>
        <book id="4">
            <author>DEF</author> 
        </book>
    </bookstore>
    <bookstore>
        <book id="5">
            <price>50</price>
        </book>
        <book id="6">
            <title>ZZZ</title> 
        </book>
    </bookstore>
</bookstores>

我想选择'book'节点的子节点的第一次出现,或者换句话说,'book'节点的所有唯一子节点 .

所以输出应该是这样的:

author
title
price

我写了一个xslt:

<xsl:for-each select="bookstores/bookstore/book"> 
    <xsl:if test="count(preceding-sibling::*[1]) = 0">
        <xsl:value-of select="local-name(*[1])"/>
    </xsl:if>
</xsl:for-each>

它没有给我任何回报......有人能给我一些帮助吗?谢谢!!

UPDATE:

如果我的xml中有几个'bookstores'元素怎么办?我只想限制每个'书店'的上下文中的唯一性,这样即使'作者'出现在一个'书店'中,它仍然可以显示在它出现在另一个'书店'?

3 回答

  • -1

    如果您使用的是XSLT1.0,那么获取不同元素的方法是使用一种名为Muenchian Grouping的技术 . 在您的情况下,您希望按书籍子元素“分组”,因此首先,您可以定义一个键,以按元素名称查找书籍的子元素

    <xsl:key name="child" match="book/*" use="local-name()" />
    

    要获取不同的名称,您可以查看所有book子元素,但只输出组中首先出现的给定名称的元素 . 你使用这个可怕的声明来做到这一点:

    <xsl:apply-templates 
       select="//book/*[generate-id() = generate-id(key('child', local-name())[1])]" />
    

    这是完整的XSLT

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:output method="text"/>
       <xsl:key name="child" match="book/*" use="local-name()" />
    
       <xsl:template match="/">
          <xsl:apply-templates select="//book/*[generate-id() = generate-id(key('child', local-name())[1])]" />
       </xsl:template>
    
       <xsl:template match="//book/*">
          <xsl:value-of select="concat(local-name(), '&#10;')" />
       </xsl:template>
    </xsl:stylesheet>
    

    应用于XML时,将输出以下内容

    author
    title
    price
    
  • 2

    Somewhat shorter/simpler -- completely in "push style":

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
     <xsl:key name="kBChildrenByName" match="book/*" use="name()"/>
    
     <xsl:template match=
      "book/*[generate-id()=generate-id(key('kBChildrenByName', name())[1])]">
         <xsl:value-of select="concat(name(), '&#xA;')"/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    When this transformation is applied to the provided XML document:

    <bookstores>
        <bookstore>
            <book id="1">
                <author>ABC</author>
            </book>
            <book id="2">
                <title>YYY</title>
            </book>
        </bookstore>
        <bookstore>
            <book id="3">
                <author>ABC</author>
            </book>
            <book id="4">
                <author>DEF</author>
            </book>
        </bookstore>
        <bookstore>
            <book id="5">
                <price>50</price>
            </book>
            <book id="6">
                <title>ZZZ</title>
            </book>
        </bookstore>
    </bookstores>
    

    the wanted, correct result is produced:

    author
    title
    price
    

    Explanation

    适当使用 Muenchian grouping method .

  • 3

    您可以使用 <xsl:for-each select="//book"> 来选择出现

相关问题