5

我有一个像这样的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>

我想选择“书”节点的子节点的第一次出现,或者换句话说,“书”节点的所有唯一子节点。

所以输出应该是这样的:

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>

它没有给我任何回报......有人可以帮我解决这个问题吗?谢谢!!

更新:

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

4

3 回答 3

3

如果您使用的是 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
于 2013-03-28T23:17:18.973 回答
3

更短/更简单——完全采用“推式”:

<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>

当此转换应用于提供的 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>

产生了想要的正确结果:

author
title
price

说明

适当使用孟池分组法

于 2013-03-29T02:08:54.867 回答
-1

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

于 2013-03-28T23:01:40.130 回答