XSLT 1.0 - 对xml元素进行分组

时间:2011-10-21 08:42:26

标签: xml xslt xpath

需要将请求从系统A转换为fint到系统B的请求。

假设我有一个类似于系统A的XML文档:

<root>
<Bundle>
    <authors>
        <author>
            <authorID>100</authorID>
            <authorName>Kathisiera</authorName>
        </author>
        <author>
            <authorID>200</authorID>
            <authorName>Bates</authorName>
        </author>
        <author>
            <authorID>300</authorID>
            <authorName>Gavin King</authorName>
        </author>
    </authors>
    <books>
        <book>
            <bookOrderID>1111</bookOrderID>
            <bookName>Head First Java</bookName>
            <bookRefID>100</bookRefID>
        </book>
        <book>
            <bookOrderID>5555</bookOrderID>
            <bookName>Head First Servlets</bookName>
            <bookRefID>200</bookRefID>
        </book>
        <book>
            <bookOrderID>1111</bookOrderID>
            <bookName>Hibernate In Action</bookName>
            <bookRefID>300</bookRefID>
        </book>
    </books>
</Bundle>

我必须将此请求放入系统B的请求结构中:

<root>
<Bundle>
    <authors>
        <author>
            <authorID>100</authorID>
            <authorName>Kathisiera</authorName>
        </author>
        <author>
            <authorID>300</authorID>
            <authorName>Gavin King</authorName>
        </author>
    </authors>
    <books>
        <book>
            <bookOrderID>1111</bookOrderID>
            <bookName>Head First Java</bookName>
            <bookRefID>100</bookRefID>
        </book>
        <book>
            <bookOrderID>1111</bookOrderID>
            <bookName>Hibernate In Action</bookName>
            <bookRefID>300</bookRefID>
        </book>
    </books>
</Bundle>
<Bundle>
    <authors>
        <author>
            <authorID>200</authorID>
            <authorName>Bates</authorName>
        </author>
    </authors>
    <books>
        <book>
            <bookOrderID>5555</bookOrderID>
            <bookName>Head First Servlets</bookName>
            <bookRefID>200</bookRefID>
        </book>
    </books>
</Bundle>

首先,我必须根据bookBundle内对bookOrderID进行分组。然后将authorBundle进行比较,将bookRefID内的authorID分组。

我尝试使用xslt的key() generate-id()函数。但无法得到预期的结果。

请帮我解决问题。

2 个答案:

答案 0 :(得分:1)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>

    <xsl:key name="k" match="book" use="bookOrderID"/>
    <xsl:key name="a" match="author" use="authorID"/>

    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="//books"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="books">

        <xsl:apply-templates select="book[generate-id(.) = generate-id(key('k', bookOrderID))]"/>

    </xsl:template>

    <xsl:template match="book">
        <Bundle>
            <authors>
                <xsl:apply-templates select="key('a', key('k', bookOrderID)/bookRefID)"/>
            </authors>

            <books>
                <xsl:copy-of select="key('k', bookOrderID)"/>
            </books>
        </Bundle>
    </xsl:template>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

输入:

<root>
    <Bundle>
        <authors>
            <author>
                <authorID>100</authorID>
                <authorName>Kathisiera</authorName>
            </author>
            <author>
                <authorID>200</authorID>
                <authorName>Bates</authorName>
            </author>
            <author>
                <authorID>300</authorID>
                <authorName>Gavin King</authorName>
            </author>
        </authors>
        <books>
            <book>
                <bookOrderID>1111</bookOrderID>
                <bookName>Head First Java</bookName>
                <bookRefID>100</bookRefID>
            </book>
            <book>
                <bookOrderID>5555</bookOrderID>
                <bookName>Head First Servlets</bookName>
                <bookRefID>200</bookRefID>
            </book>
            <book>
                <bookOrderID>1111</bookOrderID>
                <bookName>Hibernate In Action</bookName>
                <bookRefID>300</bookRefID>
            </book>
        </books>
    </Bundle>
</root>

输出:

<root>
    <Bundle>
        <authors>
            <author>
                <authorID>100</authorID>
                <authorName>Kathisiera</authorName>
            </author>
            <author>
                <authorID>300</authorID>
                <authorName>Gavin King</authorName>
            </author>
        </authors>
        <books>
            <book>
                <bookOrderID>1111</bookOrderID>
                <bookName>Head First Java</bookName>
                <bookRefID>100</bookRefID>
            </book>
            <book>
                <bookOrderID>1111</bookOrderID>
                <bookName>Hibernate In Action</bookName>
                <bookRefID>300</bookRefID>
            </book>
        </books>
    </Bundle>
    <Bundle>
        <authors>
            <author>
                <authorID>200</authorID>
                <authorName>Bates</authorName>
            </author>
        </authors>
        <books>
            <book>
                <bookOrderID>5555</bookOrderID>
                <bookName>Head First Servlets</bookName>
                <bookRefID>200</bookRefID>
            </book>
        </books>
    </Bundle>
</root>

答案 1 :(得分:0)

这是一种方法:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>

  <xsl:key name="kBook" match="book" use="bookOrderID" />

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="root">
    <xsl:apply-templates mode="bundle" select="Bundle/books/book[
      generate-id()
      =
      generate-id(key('kBook', bookOrderID)[1])
    ]" />
  </xsl:template>

  <xsl:template match="book" mode="bundle">
    <xsl:variable name="bookGroup" select="key('kBook', bookOrderID)" />
    <Bundle>
      <authors>
        <xsl:copy-of select="//author[authorID = $bookGroup/bookRefID]" />
      </authors>
      <books>
        <xsl:copy-of select="$bookGroup" />
      </books>
    </Bundle>
  </xsl:template>
</xsl:stylesheet>

这会根据bookOrderID使用<xsl:key>对书籍进行分组。

之后,它使用=运算符的属性来查找所有相关的autors:=运算符将两侧的所有节点相互比较。可以将其视为节点集的一种“内部联接”。这样,您可以使用简单的<xsl:copy-of>复制正确的节点。