如何使用其属性值匹配两组节点,而不使用两个<xsl:for-each> </xsl:for-each>

时间:2013-05-30 19:29:36

标签: xml xpath xslt-1.0

我正在使用XSLT 1.0来处理具有以下样本结构的xml文档:

<root>
    <descriptions>
        <description name="abc">
            <detail>XXXXXXXXXXXXX</detail>
        </description>
        <description name="def">
            <detail>XXXXXXXXXXXXX</detail>
        </description>
        <description name="ghi">
            <detail>XXXXXXXXXXXXX</detail>
        </description>
        <description name="lmn">
            <detail>XXXXXXXXXXXXX</detail>
        </description>
        // ....... several more description elements
    </descriptions>

    <list>
        <book name="abc"/>
        <book name="def"/>
        <book name="lmn"/>
    </list>
</root> 

我希望使用'name'属性将'list'节点下的'book'与'description'下的'description'相匹配。所以输出就像:

abc
XXXXXXXXXXXXX

def
XXXXXXXXXXXXX

lmn
XXXXXXXXXXXXX

我试过了:

<?xml version="1.0" encoding="ISO-8859-1"?>

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

<xsl:for-each select="root/list/book">
    <xsl:param name="bookName" select="@name"/>
    <xsl:for-each select="root/descriptions/description">
        <xsl:if test="$bookName = @name">
            <h3><xsl:value-of select="$bookName"/></h3>
            <p><xsl:value-of select="detail"/></p>
        </xsl:if>
    </xsl:for-each>
</xsl:for-each>
</xsl:stylesheet>

我认为必须有一种更有效的方法来实现这一点,而不是使用嵌套for-each,但我想不到一个......所以有人能给我一些帮助吗?谢谢!!

1 个答案:

答案 0 :(得分:2)

您可以使用谓词,它更简洁,可能更高效(取决于您的XSLT处理器):

<xsl:for-each select="root/list/book">
    <xsl:param name="bookName" select="@name"/>
    <xsl:variable name="desc"
          select="/root/descriptions/description[@name = $bookName]" />
    <h3><xsl:value-of select="$bookName"/></h3>
    <p><xsl:value-of select="$desc/detail"/></p>
</xsl:for-each>

为了提高效率,请使用密钥。例如。将此声明放在<xsl:output>之后:

<xsl:key name="descriptions-by-name" match="description" use="@name" />

然后更改<xsl:variable> select属性以使用密钥:

    <xsl:variable name="desc"
          select="key('descriptions-by-name', $bookName)" />