用xslt将XML元素移到另一个元素

问题描述

| 我有一个看起来像这样的XML
<executionPlan name=\"Test\" >
<paramList>
    <param name=\"param1\" default=\"\"/>
</paramList>

<varList>
    <var name=\"bla\" default=\":[param1]\"/>
</varList>

<simpleSteps limitToHostSet=\"bla\">
    <execNative>
        <exec cmd=\"/bin/sh\"/>
    </execNative>
</simpleSteps>
我需要将其转换为如下形式:
<executionPlan name=\"Test\" >
<paramList>
    <param name=\"param1\" default=\"\"/>
</paramList>

<simpleSteps limitToHostSet=\"bla\">
    <varList>
        <var name=\"bla\" default=\":[param1]\"/>
    </varList>
    <execNative>
        <exec cmd=\"/bin/sh\"/>
    </execNative>
</simpleSteps>
如您所见,varList元素需要嵌套在simpleTags元素内,紧接在开始标记之后。 simpleSteps中可能还有其他varList元素,不能更改。 有什么想法可以使用XSLT实现吗?我是XSLT的新手,一整天都徒劳地尝试了...任何帮助将不胜感激。 鲁兹     

解决方法

以下样式表:
<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
    <xsl:template match=\"@*|node()\">
        <xsl:copy>
            <xsl:apply-templates select=\"@*|node()\" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match=\"varList[following-sibling::*[1][self::simpleSteps]]\" />
    <xsl:template match=\"simpleSteps\">
        <xsl:copy>
            <xsl:apply-templates select=\"@*\" />
            <xsl:copy-of select=\"preceding-sibling::varList[1]\" />
            <xsl:apply-templates select=\"node()\" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
在此输入上:
<executionPlan name=\"Test\">
    <paramList>
        <param name=\"param1\" default=\"\" />
    </paramList>
    <varList>
        <var name=\"bla\" default=\":[param1]\" />
    </varList>
    <varList>
        <var name=\"bla2\" default=\":[param2]\" />
    </varList>
    <simpleSteps limitToHostSet=\"bla\">
        <execNative>
            <exec cmd=\"/bin/sh\" />
        </execNative>
    </simpleSteps>
</executionPlan>
产生:
<executionPlan name=\"Test\">
    <paramList>
        <param name=\"param1\" default=\"\" />
    </paramList>
    <varList>
        <var name=\"bla\" default=\":[param1]\" />
    </varList>
    <simpleSteps limitToHostSet=\"bla\">
        <varList>
            <var name=\"bla2\" default=\":[param2]\" />
        </varList>
        <execNative>
            <exec cmd=\"/bin/sh\" />
        </execNative>
    </simpleSteps>
</executionPlan>
编辑:仅将紧前面的ѭ5移入与其关联的
simpleSteps
。所有其他“ 5”元素均原样复制。 我突然不清楚这是否是所需的行为,或者在or6ѭ元素内是否已有多个
varList
元素应该保持不变。对于这种情况,请参阅我的原始解决方案:
<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
    <xsl:template match=\"@*|node()\">
        <xsl:copy>
            <xsl:apply-templates select=\"@*|node()\" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match=\"varList\" />
    <xsl:template match=\"simpleSteps\">
        <xsl:copy>
            <xsl:apply-templates select=\"@*\" />
            <xsl:copy-of select=\"../varList\" />
            <xsl:apply-templates select=\"node()\" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
在此输入上:
<executionPlan name=\"Test\">
    <paramList>
        <param name=\"param1\" default=\"\" />
    </paramList>
    <varList>
        <var name=\"bla\" default=\":[param1]\" />
    </varList>
    <simpleSteps limitToHostSet=\"bla\">
        <varList>
            <var name=\"bla7\" default=\":[param7]\" />
        </varList>
        <execNative>
            <exec cmd=\"/bin/sh\" />
        </execNative>
    </simpleSteps>
</executionPlan>
产生:
<executionPlan name=\"Test\">
    <paramList>
        <param name=\"param1\" default=\"\" />
    </paramList>
    <simpleSteps limitToHostSet=\"bla\">
        <varList>
            <var name=\"bla\" default=\":[param1]\" />
        </varList>
        <varList>
            <var name=\"bla7\" default=\":[param7]\" />
        </varList>
        <execNative>
            <exec cmd=\"/bin/sh\" />
        </execNative>
    </simpleSteps>
</executionPlan>
    ,这是一个更简单,更短的解决方案:
<xsl:stylesheet version=\"1.0\"
 xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
 <xsl:output omit-xml-declaration=\"yes\" indent=\"yes\"/>
 <xsl:strip-space elements=\"*\"/>

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

 <xsl:template match=\"simpleSteps/*[1]\">
  <xsl:copy-of select=\"/*/varList[1]\"/>
  <xsl:call-template name=\"identity\"/>
 </xsl:template>

 <xsl:template match=\"/*/varList[1]\"/>
</xsl:stylesheet>
当应用于提供的XML文档时:
<executionPlan name=\"Test\" >
    <paramList>
        <param name=\"param1\" default=\"\"/>
    </paramList>
    <varList>
        <var name=\"bla\" default=\":[param1]\"/>
    </varList>
    <simpleSteps limitToHostSet=\"bla\">
        <execNative>
            <exec cmd=\"/bin/sh\"/>
        </execNative>
    </simpleSteps>
</executionPlan>
正是想要的,正确的结果产生了:
<executionPlan name=\"Test\">
   <paramList>
      <param name=\"param1\" default=\"\"/>
   </paramList>
   <simpleSteps limitToHostSet=\"bla\">
      <varList>
         <var name=\"bla\" default=\":[param1]\"/>
      </varList>
      <execNative>
         <exec cmd=\"/bin/sh\"/>
      </execNative>
   </simpleSteps>
</executionPlan>
说明: 身份规则/模板按“原样”复制每个节点。只有两个例外,如下所述。 仅匹配top元素的第一个“ 5”子元素的覆盖模板没有主体-这实际上废除了此元素的身份模板的复制操作。 匹配
simpleSteps
的第一个元素子元素的覆盖模板有两件事:a)复制所需的
varList
(顶部元素的子元素),然后b)调用身份模板将自身复制到输出。