Move an xml element to another element using xslt

I have an XML that looks like

<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 convert 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 must be nested inside the simpleSteps element immediately after the opening tag. Inside simple steps, there may be other varList elements that cannot be changed.

Any ideas how to achieve this using XSLT? I am new to XSLT and tried in vain all day ... Any help would really be appreciated.

Lutz

+4
source share
2 answers

The following stylesheet:

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

At this input:

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

It produces:

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

Edit: Only the previous varList moved to its associated simpleSteps . All other varList elements varList copied unchanged.

It is unexpectedly not clear to me whether this is the desired behavior, or there may be several varList elements already inside the simpleSteps element that should not be changed. See my original solution for this case:

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

At this input:

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

It produces:

 <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> 
+4
source

This is a simpler and shorter solution :

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

when applied to the provided XML document:

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

exactly the desired, correct result is obtained:

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

Explanation

  • identification rule / template copies each node "as is". There are only two exceptions described below.

  • An overriding template that matches only the first varList child of the top element does not have a body - this will actually invalidate the action of copying the identity template for this element.

  • The overriding template corresponding to the first child element of the simpleSteps element has two functions: a) copies the desired varList element (a child of the top element), and then b) it calls the identification template, copy yourself to the output.

+2
source

Source: https://habr.com/ru/post/1348124/


All Articles