匹配一个或多个子节点的 XSL 密钥
XSL key matching one or more child nodes
我有一个按书名结构的复杂 XML 文件。类似这样的东西,但有数百本书,有时每本书有很多作者。
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
我需要输出的是按字母顺序排列的作者列表,然后是他们编写的每本书的列表,也按字母顺序排列,例如:
Arnold, Grant — Ken Lum; Shore, Forest and Beyond
Thom, Ian M. — Shore, Forest and Beyond
我有一个代码版本工作得很好,但速度很慢,所以我正在尝试优化我的方法。我最近从这里的另一个用户那里了解到 Muenchian method 分组,我正在尝试应用它。
我现在特别关注的部分是获取每位作者的书名列表。这就是我现在拥有的:
<xsl:key name="books-by-author" match="Book"
use="concat(Author/GivenName, Contributor/Surname)" />
…
<xsl:template match="Author">
…
<xsl:apply-templates mode="ByAuthor" select=
"key('books-by-author',
concat(GivenName, Surname)
)">
<xsl:sort select="Title/TitleText"/>
</xsl:apply-templates>
</template>
但这似乎只匹配作者列在第一位的书籍,例如:
Arnold, Grant — Ken Lum
Thom, Ian M. — Shore, Forest and Beyond
我认为 xsl:key
仅使用第一个 Author
元素,而不是检查每个作者。是否可以像这样检查每个 Author
?或者有更好的方法吗?
我建议你这样看:
XML
<Books>
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
</Books>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="author" match="Author" use="concat(Surname, ', ', GivenName)" />
<xsl:template match="/Books">
<Authors>
<!-- for each unique author -->
<xsl:for-each select="Book/Author[count(. | key('author', concat(Surname, ', ', GivenName))[1]) = 1]">
<xsl:sort select="Surname"/>
<xsl:sort select="GivenName"/>
<Author>
<!-- author's details-->
<xsl:copy-of select="Surname | GivenName"/>
<!-- list author's books -->
<Books>
<xsl:for-each select="key('author', concat(Surname, ', ', GivenName))/parent::Book">
<xsl:sort select="Title"/>
<xsl:copy-of select="Title"/>
</xsl:for-each>
</Books>
</Author>
</xsl:for-each>
</Authors>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<Authors>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
<Books>
<Title>Ken Lum</Title>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
<Books>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
</Authors>
我有一个按书名结构的复杂 XML 文件。类似这样的东西,但有数百本书,有时每本书有很多作者。
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
我需要输出的是按字母顺序排列的作者列表,然后是他们编写的每本书的列表,也按字母顺序排列,例如:
Arnold, Grant — Ken Lum; Shore, Forest and Beyond
Thom, Ian M. — Shore, Forest and Beyond
我有一个代码版本工作得很好,但速度很慢,所以我正在尝试优化我的方法。我最近从这里的另一个用户那里了解到 Muenchian method 分组,我正在尝试应用它。
我现在特别关注的部分是获取每位作者的书名列表。这就是我现在拥有的:
<xsl:key name="books-by-author" match="Book"
use="concat(Author/GivenName, Contributor/Surname)" />
…
<xsl:template match="Author">
…
<xsl:apply-templates mode="ByAuthor" select=
"key('books-by-author',
concat(GivenName, Surname)
)">
<xsl:sort select="Title/TitleText"/>
</xsl:apply-templates>
</template>
但这似乎只匹配作者列在第一位的书籍,例如:
Arnold, Grant — Ken Lum
Thom, Ian M. — Shore, Forest and Beyond
我认为 xsl:key
仅使用第一个 Author
元素,而不是检查每个作者。是否可以像这样检查每个 Author
?或者有更好的方法吗?
我建议你这样看:
XML
<Books>
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
</Books>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="author" match="Author" use="concat(Surname, ', ', GivenName)" />
<xsl:template match="/Books">
<Authors>
<!-- for each unique author -->
<xsl:for-each select="Book/Author[count(. | key('author', concat(Surname, ', ', GivenName))[1]) = 1]">
<xsl:sort select="Surname"/>
<xsl:sort select="GivenName"/>
<Author>
<!-- author's details-->
<xsl:copy-of select="Surname | GivenName"/>
<!-- list author's books -->
<Books>
<xsl:for-each select="key('author', concat(Surname, ', ', GivenName))/parent::Book">
<xsl:sort select="Title"/>
<xsl:copy-of select="Title"/>
</xsl:for-each>
</Books>
</Author>
</xsl:for-each>
</Authors>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<Authors>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
<Books>
<Title>Ken Lum</Title>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
<Books>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
</Authors>