在xslt中选择并行节点

时间:2015-01-28 13:31:19

标签: xslt xpath

请考虑以下xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <base>
     <a>
            <b>
                <c>Text 1</c>
            </b>
        </a>
    </base>
    <base>
        <a>
            <b>
                <c>Text 2</c>
            </b>
        </a>
    </base>
</root>

和这个xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates select="root/base[1]" />
    </xsl:template>

    <xsl:template match="base//*">
        <xsl:if test="text()">
            <xsl:value-of select="text()" />
            <!-- i need Text 2 here -->
        </xsl:if>            
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="text()" />
</xsl:stylesheet>

原始的xml更嵌套,我不知道确切的结构。但是有一个具有相同结构的并行节点。如果我的模板位于// root / base [1] / a / b / c,我想引用// root / base [2] / a / b / c

但是我只知道我在// root / base [1]下面的某个节点,并且// root / base [2]中有相同的节点。

是否有可能实现这一目标?

3 个答案:

答案 0 :(得分:1)

使用saxon的解决方案:评估扩展名(http://saxon.sourceforge.net/saxon7.9/extensions.html#evaluate

如果您使用的是xslt 1.0处理器(http://exslt.org/dyn/index.html),也可以使用dyn:evaluate:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
xmlns:saxon="http://saxon.sf.net/"
version="1.0">
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates select="root/base[1]" />
    </xsl:template>

    <xsl:template match="base//*">
        <xsl:if test="text()">
            <xsl:variable name="path">
                <xsl:call-template name="constructPath">
                    <xsl:with-param name="node" select="."/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="rewritedPath" select="concat('/root/base[2]', substring($path, 11))"/>

            <xsl:value-of select="text()" />
            <xsl:value-of select="saxon:evaluate($rewritedPath)" />
        </xsl:if>            
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template name="constructPath">
        <xsl:param name="node"/>

        <xsl:choose>
            <xsl:when test="$node/parent::node()/name()">
                <xsl:call-template name="constructPath">
                    <xsl:with-param name="node" select="$node/parent::node()"/>
                </xsl:call-template>
                <xsl:value-of select="concat('/', $node/name())"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat('/', $node/name())"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="text()" />
</xsl:stylesheet>

这里我们使用递归模板&#34; constructPath&#34;创建字符串并在evaluate()函数中处理它。这将选择并行分支中的确切节点。希望这会有所帮助。

答案 1 :(得分:1)

此样式表不需要扩展,也不对唯一名称做任何假设;无聊的部分是通过正确的&#34;双节点&#34;每次拨打xsl:apply-templates

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates select="root/base[1]">
            <xsl:with-param name="twin" select="root/base[2]"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*">
        <xsl:param name="twin"/>
        <xsl:if test="text()">
            <xsl:value-of select="text()" />
            <xsl:value-of select="$twin/text()"/>
        </xsl:if>            
        <xsl:for-each select="*">
            <xsl:variable name="pos" select="position()"/>
            <xsl:apply-templates select=".">
                <xsl:with-param name="twin" select="$twin/*[$pos]"/>
            </xsl:apply-templates>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="text()" />
</xsl:stylesheet>

答案 2 :(得分:0)

尝试以下代码。仅当每个基本元素具有具有唯一元素名称的子元素时,此代码才有效。

<?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">
   <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates select="root/base[1]" />
    </xsl:template>

    <xsl:template match="base//*">
        <xsl:if test="text()">
            <xsl:variable name="name" select="name()"/>
            <xsl:value-of select="text()" />
            <xsl:value-of select="ancestor::base/following-sibling::base[1]//*[name() = $name]" />
       </xsl:if>            
       <xsl:apply-templates />
   </xsl:template>

<xsl:template match="text()" />

但是你可以使用dyn:来自exslt扩展或saxon:eval