Переместите элемент xml в другой элемент с помощью xslt

У меня есть 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>

and I need to transform it to look like this:

<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>

As you can see the varList element needs to be nested inside the simpleSteps element immediately behind the opening tag. There may be other varList elements inside simpleSteps which must not be changed.

Любые идеи, как добиться этого с помощью XSLT? Я новичок в XSLT и тщетно пытался целый день... Любая помощь будет очень признательна.

Лутц


person Lutz    schedule 14.04.2011    source источник
comment
Только первый varList внутри первого simpleSteps? simpleSteps' varList ребенок должен быть объединен или оставлен как родной брат?   -  person    schedule 14.04.2011
comment
Хороший вопрос, +1. Смотрите мой ответ для более короткого и простого решения и подробного объяснения.   -  person Dimitre Novatchev    schedule 15.04.2011


Ответы (2)


Следующая таблица стилей:

<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>

Изменить: только непосредственно предшествующий varList перемещается в связанный с ним simpleSteps. Все остальные элементы varList копируются без изменений.

Мне вдруг стало непонятно, является ли это желаемым поведением или может быть несколько элементов varList уже внутри элемента simpleSteps, которые должны быть неизменными. См. мое оригинальное решение для этого случая:

<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>
person Wayne    schedule 14.04.2011

Это более простое и короткое решение:

<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>

Пояснение:

  1. правило идентификации/template копирует каждый узел "как есть". Есть только два исключения, описанные ниже.

  2. Шаблон переопределения, который соответствует только первому varList дочернему элементу верхнего элемента, не имеет тела — это эффективно отменяет действие копирования шаблона идентификации для этого элемента.

  3. Переопределяющий шаблон, соответствующий первому дочернему элементу simpleSteps, делает две вещи: а) копирует требуемый элемент varList (дочерний элемент верхнего элемента), а затем б) вызывает шаблон удостоверения, чтобы скопировать себя в выходной файл.

person Dimitre Novatchev    schedule 15.04.2011