Xml 使用XSLT 2.0在第一个父/祖先级别移动子代和子代

Xml 使用XSLT 2.0在第一个父/祖先级别移动子代和子代,xml,xslt,xpath,Xml,Xslt,Xpath,为这个XSLT转换提出解决方案时遇到问题 源输入: <root> <title>Title here.</title> <div> <p>Text here.</p> <div> <p>Text here.</p> <div> <p>Tex

为这个XSLT转换提出解决方案时遇到问题

源输入:

<root>
    <title>Title here.</title>
    <div>
        <p>Text here.</p>
        <div>
            <p>Text here.</p>
            <div>
                <p>Text here.</p>
                <div>
                    <p>Text here.</p>
                </div>
            </div>
        </div>
    </div>
</root>

标题在这里。
文本在这里

文本在这里

文本在这里

文本在这里

期望输出:

<root>
    <title>Title here.</title>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
</root>

标题在这里。
文本在这里

文本在这里

文本在这里

文本在这里


有什么想法吗?

首先要做的是身份模板

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

这将按原样复制元素,因此您只需要为要转换的元素编写模板。在本例中,您似乎希望转换至少有一个元素作为子元素的元素(根元素除外),因此模板匹配将如下所示

<xsl:template match="*/*[*]">

在这种情况下,您需要复制元素,但只处理没有其他元素作为子元素的子节点

  <xsl:copy>
     <xsl:apply-templates select="@*|node()[not(self::*[*])]"/>
  </xsl:copy>

最后,在此复制之后,您可以选择具有子元素的子元素,以便将它们复制到当前元素之后

<xsl:apply-templates select="*[*]"/>

试试这个XSLT

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

   <xsl:template match="*/*[*]">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()[not(self::*[*])]"/>
      </xsl:copy>
      <xsl:apply-templates select="*[*]"/>
   </xsl:template>

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

当应用于XML示例时,将输出以下内容

<root>
    <title>Title here.</title>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
    <div>
        <p>Text here.</p>
    </div>
</root>

标题在这里。
文本在这里

文本在这里

文本在这里

文本在这里


这是一个非常通用的解决方案,可用于所有标记名,而不仅仅是DIV标记。

根据Tim C提出的问题(其他命名标记?),您可以简单地使用:

<xsl:template match="root">
  <root>
    <xsl:for-each select="//div/p">
      <div><xsl:copy-of select="." /></div>
    </xsl:for-each>
  </root>
</xsl:template>


看起来很简单。问题是什么?是需要向上移动的仅仅是Div标记,还是可以有其他标记?转换的确切规则是什么?谢谢