xslt 具有父节点的递归子节点

Posted

技术标签:

【中文标题】xslt 具有父节点的递归子节点【英文标题】:xslt recursive child nodes with parent node 【发布时间】:2017-05-04 08:44:34 【问题描述】:

我想知道在 xslt 2.0 中解决此解决方案的更好方法。

输入:

<Root>
    <Record>
        <FName>Abc</FName>
        <MName>FAbc</MName>
        <Kid>
            <CName>C1Abc<CName>
        </Kid>
        <Kid>
            <CName>C2Abc<CName>
        </Kid>
    </Record>
    <Record>
        <FName>Def</FName>
        <MName>FDef</MName>
        <Kid>
            <CName>C1Def<CName>
        </Kid>
    </Record>
    <Record>
        <FName>Xyz</FName>
        <MName>FXyz</MName>
    </Record>
</Root>

输出:

<Root>
    <Record>
        <FName>Abc</FName>
        <MName>FAbc</MName>
        <CName>C1Abc<CName>
    </Record>
    <Record>
        <FName>Abc</FName>
        <MName>FAbc</MName>
        <CName>C2Abc<CName>
    </Record>
    <Record>
        <FName>Def</FName>
        <MName>FDef</MName>
        <CName>C1Def<CName>
    </Record>
    <Record>
        <FName>Xyz</FName>
        <MName>FXyz</MName>
        <CName></CName>
    </Record>
</Root>

XSLT:

<?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"
    version="2.0">

    <xsl:template match="Root">
        <Root>
            <xsl:apply-templates select="Record">
            </xsl:apply-templates>
        </Root>
    </xsl:template>

    <xsl:template match="Record">
        <xsl:choose>
            <xsl:when test="Kid">
                <xsl:apply-templates select="Kid">                              
                </xsl:apply-templates>  
            </xsl:when>
            <xsl:otherwise>
                <Record>   
                    <FName>
                        <xsl:value-of select="FName"/>
                    </FName>
                    <MName>
                        <xsl:value-of select="MName"/>
                    </MName>        
                    <CName>
                        <xsl:value-of select="Kid/CName"/>
                    </CName>
                </Record>                                   
            </xsl:otherwise>
        </xsl:choose>       
    </xsl:template>

    <xsl:template match="Kid">  
        <Record>   
            <FName>
                <xsl:value-of select="../FName"/>
            </FName>
            <MName>
                <xsl:value-of select="../MName"/>
            </MName>
            <CName> 
                <xsl:value-of select="CName"/>
            </CName>            
        </Record>               
    </xsl:template>
</xsl:stylesheet>

我的 xslt 工作正常,我能够得到我期望的输出。但我想听听是否有其他更好的方法来做到这一点。主要是为了避免任何性能问题,因为将有数千条记录和更多数据。谢谢。

【问题讨论】:

会一直存在FNameMName 吗?或者任何子元素都可以是可选的? 你真的有性能问题吗?您是否使用 XSLT 处理器分析了现有代码以找出需要改进的代码? @Tim C,所有子元素都是可选的,但如果没有值,则应该有一个空标签 @MartinHonnen,并没有真正进行那些性能测试。我对编写 xslt 很陌生,我更想了解我在 xslt 中最终犯的任何愚蠢行为。 【参考方案1】:

你可以重写

<xsl:template match="Record">
    <xsl:choose>
        <xsl:when test="Kid">
            <xsl:apply-templates select="Kid">                              
            </xsl:apply-templates>  
        </xsl:when>
        <xsl:otherwise>
            <Record>   
                <FName>
                    <xsl:value-of select="FName"/>
                </FName>
                <MName>
                    <xsl:value-of select="MName"/>
                </MName>        
                <CName>
                    <xsl:value-of select="Kid/CName"/>
                </CName>
            </Record>                                   
        </xsl:otherwise>
    </xsl:choose>       
</xsl:template>

作为

<xsl:template match="Record[not(Kid)]">
            <Record>   
                <FName>
                    <xsl:value-of select="FName"/>
                </FName>
                <MName>
                    <xsl:value-of select="MName"/>
                </MName>        
                <CName></CName>
            </Record>                                       
</xsl:template>

<xsl:template match="Record[Kid]">
  <xsl:apply-templates select="Kid"/>
</xsl:template>

【讨论】:

感谢马丁的评论。顺便说一句,是否有地方可以重写 ../ (从当前节点移回)或者这是正确的方法? 我认为没有必要用.. 重写对父节点的访问。我建议的重写也主要是装饰性的,但总的来说,我认为使用带有谓词的模板匹配模式来区分不同的结构比在单个模板中使用 xsl:choose/xsl:when 更清晰、更优雅。

以上是关于xslt 具有父节点的递归子节点的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 将具有父节点的节点移动到具有给定属性的每个父节点的兄弟节点中

XSLT 根据最大​​子节点对父节点进行排序

具有递归 CTE 的 Postgres:在保留树结构的同时按受欢迎程度对子节点进行排序/排序(父节点始终高于子节点)

XSLT 1.0 - 连接已知子节点,按未知父节点分组

在 XSLT 中对每个父节点下的子节点进行分组

如何使用 xslt 将父节点命名空间复制到子元素?