XSLT:复制元素及其周围的元素(递归循环错误)

XSLT: Copy Element with its surrounding Elements (Recursive Loop Error)

我正在努力寻找这个问题的解决方案,因为我最终陷入了递归循环。

XML 来源示例:

<runtime xmlns="http://xxx/v1"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="xxx.xsd">
    <messages>
        <message>
            <severity>debug</severity>
            <source>Client</source>
            <subject>Subject</subject>
            <body>Body</body>
        </message>
    </messages>

我需要将 Messages 元素放在 body 元素中

  <runtime xmlns="http://xxx/v1"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="xxx.xsd">
        <messages>
            <message>
                <severity>debug</severity>
                <source>Client</source>
                <subject>Subject</subject>

                <body>

                <messages>
                    <message>
                        <severity>debug</severity>
                        <source>Client</source>
                        <subject>Subject</subject>
                        <body>Body</body>
                </message>
                </messages>

               </body>

            </message>
        </messages>

我无法在不陷入循环错误的情况下提出可行的解决方案。任何帮助都适用。

这是您可以查看的一种方式:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v1="http://xxx/v1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="v1:body">
    <xsl:copy>
        <xsl:copy-of select="../.."/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

作为智力练习,在 XSLT 2.0 中,您可以:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://xxx/v1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- identity transform -->
<xsl:template match="@*|node()" mode="#all">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" mode="#current"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="body">
    <xsl:copy>
        <xsl:apply-templates select="../.." mode="copy"/>
    </xsl:copy>
</xsl:template>

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

</xsl:stylesheet>

您必须 运行 复制模板,但 <body> 元素除外。对于这个特殊标签,制作另一个带有名称的复制模板以从新开始驱动转换,并使用另一个路径来避免循环。

主体的经典复制模板执行

<xsl:template match="node()[local-name()!='body'] | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
</xsl:template>

对于正文元素,通过指定另一条路径(带模式)从头开始复制

 <xsl:template match="*[local-name()='body']">
    <xsl:copy>
        <xsl:apply-templates select="/*:runtime/*:messages" mode='embedded'/>
    </xsl:copy>
</xsl:template>

并使用另一个复制模板将标签复制到 body 元素中

<xsl:template match="node() | @*" mode="embedded">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" mode="embedded"/>
    </xsl:copy>
</xsl:template>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<runtime xmlns="http://xxx/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="xxx.xsd">
    <messages>
        <message>
            <severity>debug</severity>
            <source>Client</source>
            <subject>Subject</subject>
            <body>
                <messages>
                    <message>
                        <severity>debug</severity>
                        <source>Client</source>
                        <subject>Subject</subject>
                        <body>Body</body>
                    </message>
                </messages>
            </body>
        </message>
    </messages>
</runtime>