XSLT遍历author时匹配book的writers IDREFS并关联输出排序书籍
解决你的XSLT匹配多作者书籍问题
首先,咱们来拆解你遇到的两个核心问题:
- 关联当前遍历的作者:你原来的XPath
//book[//author/@id = @writers]会匹配所有作者的id和任意book的writers,而不是只匹配当前正在处理的那个作者; - 处理多值的writers属性:因为writers是IDREFS类型(用逗号分隔多个id),直接用等于号只会匹配完全一致的字符串,得用包含判断,还要避免部分匹配(比如id是007的作者不会被误匹配到writers里的0077)。
修正后的完整XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <body> <ol> <xsl:for-each select="//author"> <li> <b>ID: </b><xsl:value-of select="@id"/> <ul> <xsl:call-template name="auth_infos"/> <xsl:call-template name="books_stuff"/> </ul> </li> </xsl:for-each> </ol> </body> </xsl:template> <xsl:template name="auth_infos"> <li><b>Name: </b><xsl:value-of select="name"/></li> </xsl:template> <xsl:template name="books_stuff"> <!-- 定义当前作者的id变量,方便后续使用 --> <xsl:variable name="currentAuthorId" select="@id"/> <!-- 检查是否有匹配当前作者的书籍 --> <xsl:if test="exists(//book[contains(concat(',', @writers, ','), concat(',', $currentAuthorId, ','))])"> <li><b>Book(s): </b> <ul> <!-- 遍历匹配的书籍,并按price降序排序 --> <xsl:for-each select="//book[contains(concat(',', @writers, ','), concat(',', $currentAuthorId, ','))]"> <xsl:sort select="price" data-type="number" order="descending"/> <li><b>Title: </b><xsl:value-of select="title"/></li> </xsl:for-each> </ul> </li> </xsl:if> </xsl:template> </xsl:stylesheet>
关键修正点说明
- 关联当前作者:通过定义变量
$currentAuthorId获取当前遍历的author的id,确保后续匹配只针对这个作者; - 安全的多值匹配:用
concat(',', @writers, ',')把writers属性包裹在逗号里,再用contains判断当前作者id是否在其中,这样能避免像007被误匹配到0077这类部分一致的情况; - 正确获取书籍标题:把原来的
//title改成title,这样只会取当前book节点下的title,而不是文档里第一个title; - 排序优化:给
xsl:sort加上data-type="number",确保price是按数字大小排序,而不是字符串排序; - 空列表隐藏:用
exists()函数判断是否有匹配书籍,没有的话就不会显示Book(s)这一项。
预期输出(格式化后)
- ID: 007
- Name: James
- Book(s):
- Title: Two authors wrote me
- ID: 911
- Name: Police
- Book(s):
- Title: Two authors wrote me
- Title: Only one here
- ID: 666
- Name: Diablo
内容的提问来源于stack exchange,提问作者payne
相关产品推荐
相关产品推荐

