XSLT 2.0动态XPATH表达式

时间:2016-01-20 18:04:10

标签: xpath xslt-2.0 saxon

我有一个XML文件需要根据带有XSLT 2.0的映射文件进行转换。我使用的是Saxon HE处理器。

我的映射文件:

<element root="TEST">
    <childName condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILD</childName>
    <childBez condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILDBEZ</childBez>
</element>

当CHILD的文本等于B时,我必须复制CHILD和CHILDBEZ元素以及父元素和根元素。 所以使用此输入:

<?xml version="1.0" encoding="UTF-8"?>
<TEST>
    <MyElement>
        <CHILD>A</CHILD>
        <CHILDBEZ>ABEZ</CHILDBEZ>
        <NotInteresting></NotInteresting>
    </MyElement>
    <MyElement>
        <CHILD>B</CHILD>
        <CHILDBEZ>BBEZ</CHILDBEZ>
        <NotInteresting2></NotInteresting2>
    </MyElement>
</TEST>

所需的输出:

<TEST>
    <MyElement>
        <childName>B</childName>
        <childBez>BBEZ</childBez>
    </MyElement>
</TEST>

到目前为止(基于此解决方案XSLT 2.0 XPATH expression with variable):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    
<xsl:strip-space elements="*"/>

<xsl:param name="mapping" select="document('mapping.xml')"/>

<xsl:key name="map" match="*" use="."/>

<xsl:template match="/">
    <xsl:variable name="first-pass">
        <xsl:apply-templates mode="first-pass"/>
    </xsl:variable>
    <xsl:apply-templates select="$first-pass/*"/>
</xsl:template>

<xsl:template match="*" mode="first-pass">
    <xsl:param name="parent-path" tunnel="yes"/>
    <xsl:variable name="path" select="concat($parent-path, '/', name())"/>
    <xsl:variable name="replacement" select="key('map', $path, $mapping)"/>
    <xsl:variable name="condition" select="key('map', $path, $mapping)/@condition"/>        
    <xsl:choose>
        <xsl:when test="$condition!= ''">
            <!-- if there is a condition defined in the mapping file, check for it -->
        </xsl:when>
        <xsl:otherwise>
            <xsl:element name="{if ($replacement) then name($replacement) else name()}">
                <xsl:attribute name="original" select="not($replacement)"/>
                <xsl:apply-templates mode="first-pass">
                    <xsl:with-param name="parent-path" select="$path" tunnel="yes"/>
                </xsl:apply-templates>
            </xsl:element>
        </xsl:otherwise>
    </xsl:choose>

</xsl:template>

<xsl:template match="*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[@original='true' and not(descendant::*/@original='false')]"/>    
</xsl:stylesheet>

但问题是用XSLT 2.0评估动态XPATH表达式是不可能的。有谁知道解决方法吗?另外我的映射文件有问题。当其中只有一个元素时,它根本不起作用。

1 个答案:

答案 0 :(得分:1)

如果动态XPath评估不是您选择的处理器中的选项,那么生成XSLT样式表通常是一个不错的选择。事实上,无论如何,它通常都是一个不错的选择。

一种思考方式是你的映射文件实际上是一个用非常简单的转换语言编写的程序。执行此程序有两种方法:您可以编写解释器(动态XPath评估),也可以编写编译器(XSLT样式表生成)。两者都运作良好。