XSLT 1.0 - 对XML元素进行分组

3
需要将来自系统A的请求转换为系统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>

首先,我必须根据bookOrderIDbook分组到Bundle中。然后通过比较bookRefIDauthorID,将author分组到Bundle中。
我尝试使用XSLT的key() generate-id()函数,但无法得到预期的结果。
请帮助我找到解决方案。
2个回答

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>

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>

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

然后,它使用=运算符的属性来查找所有相关的作者: =运算符将每一侧的全部节点与对方进行比较。可以将其视为节点集合的一种"内连接"。这样,您就可以使用简单的<xsl:copy-of>复制正确的节点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接