将XSL模板应用于两个不同源文件之一时,如何引用其他源中的“匹配”节点?

时间:2013-10-23 19:39:01

标签: xslt xpath xslt-2.0

我正在使用XSLT转换来自两个差异源XML的信息。第一源中的每个相关节点具有在第二源文件中具有等效“id”属性的节点,该属性包含需要合并的额外信息。第二个源中没有匹配的任何节点都无关紧要,因此第一个源需要驱动结果。

以下是问题的简化版本:

XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:two="http://www.mycompany.com/schemas/1.0">

    <xsl:param name="secondDoc" as="document-node()" />

    <xsl:template match="/">
        <Employees>
            <xsl:apply-templates match="$secondDoc/two:People/two:Person" />
        <Employees>
    </xsl:template>

    <xsl:template match="two:Person">
        <Employee>
            <xsl:value-of select="/Employees/Employee[@id='@id']/FirstName" />
            <xsl:value-of select="two:LastName" />
        </Employee>
    </xsl:template>

</xsl:stylesheet>

第一来源:

<?xml version="1.0" encoding="UTF-8"?>
<Employees>
    <Employee id="1">
        <FirstName>John</FirstName>
    </Employee>
</Employees>

第二来源:

<?xml version="1.0" encoding="UTF-8"?>
<People xmlns="http://www.mycompany.com/schemas/1.0">
    <Person id="1">
        <LastName>Doe</LastName>
    </Person>
</People>

我尝试使用的方法是创建与第二个源使用的命名空间前缀匹配的模板,然后匹配模板中的等效节点。问题是我不知道如何将XPath返回到根模板。当然,语句的值失败了。

我尝试过的一种方法是将xsl:with-param添加到xsl:apply-templates&gt;并将匹配节点作为变量发送给模板。如果我手动选择了一个节点(Employee [1]),这有效,但由于with-param似乎没有采用apply-templates选择的上下文,我不知道如何将“id”属性绑定在一起

有没有办法引用回根模板,或者我的方法是错误的?

编辑:我想到了一个可能的解决方案,尽管它可能不是最干净的。我可以将“Employees”节点作为参数传递给模板,然后匹配模板内特定员工的“id”标签,并使用结果节点作为参考。这看起来像在这个例子中传递根节点,但实际上这是整个XSL的一小部分。希望有一种更简单的方法。

2 个答案:

答案 0 :(得分:2)

这是一个稍微不同的方法,接受你所说的关于驱动结果的第一个来源的内容,并调用第二个来源。这可能很有用:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:two="http://www.mycompany.com/schemas/1.0" version="2.0">

<xsl:variable name="source2" select="doc('source2.xml')"></xsl:variable>

<xsl:template match="/">
    <Employees>
        <xsl:apply-templates select="/Employees/Employee"/>
    </Employees>
</xsl:template>

<xsl:template match="Employee">
    <Employee>
        <xsl:value-of select="FirstName" />
        <xsl:text> </xsl:text>
        <xsl:value-of select="$source2/two:People/two:Person[@id=current()/@id]/two:LastName" />
    </Employee>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:2)

使用变量存储对主输入文档的根节点的引用:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:two="http://www.mycompany.com/schemas/1.0">

    <xsl:param name="secondDoc" as="document-node()" />

    <xsl:variable name="main-root" select="/"/>

    <xsl:template match="/">
        <Employees>
            <xsl:apply-templates match="$secondDoc/two:People/two:Person" />
        <Employees>
    </xsl:template>

    <xsl:template match="two:Person">
        <Employee>
            <xsl:value-of select="$main-root/Employees/Employee[@id = current()/@id]/FirstName" />
            <xsl:value-of select="two:LastName" />
        </Employee>
    </xsl:template>

</xsl:stylesheet>

然后当然使用密钥进行交叉引用:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:two="http://www.mycompany.com/schemas/1.0">

    <xsl:param name="secondDoc" as="document-node()" />

    <xsl:key name="id" match="Employee" use="@id"/>
    <xsl:variable name="main-root" select="/"/>    
    <xsl:template match="/">
        <Employees>
            <xsl:apply-templates match="$secondDoc/two:People/two:Person" />
        <Employees>
    </xsl:template>

    <xsl:template match="two:Person">
        <Employee>
            <xsl:value-of select="key('id', @id, $main-root)/FirstName" />
            <xsl:value-of select="two:LastName" />
        </Employee>
    </xsl:template>

</xsl:stylesheet>