Merge nodes
Merge 2 XML nodes.
Browse
Description
Easy merge 2 nodes.
XSLT
View Raw
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <!-- Merge nodes. This template will take a `default` XML node and overwrite it's values with the correspondant ones from the `input` XML node. ============================= Example call: <xsl:call-template name="merge-nodes"> <xsl:with-param name="input"> <t.1 a1="i.1"> <t.1.2>input title 1.2</t.1.2> </t.1> <c> <w>50</w> </c> </xsl:with-param> <xsl:with-param name="default"> <t.1 a1="d.1" a3="a.3"> <t.1.1>default title 1.1</t.1.1> <t.1.2>default title 1.2</t.1.2> </t.1> <d>default body</d> <c> <r>1-1</r> <w>70</w> <h>70</h> </c> </xsl:with-param> </xsl:call-template> Result: <t.1 a1="i.1" a3="a.3"> <t.1.1>default title 1.1</t.1.1> <t.1.2>input title 1.2</t.1.2> </t.1> <d>default body</d> <c> <r>1-1</r> <w>50</w> <h>70</h> </c> ============================= You can put the `merge-nodes` attribute with value `all` to a default node in order to keep everything that comes from `input` after that node 1. Without `merge-nodes`: Example call: <xsl:call-template name="merge-nodes"> <xsl:with-param name="input"> <attributes> <rel>tooltip</rel> </attributes> </xsl:with-param> <xsl:with-param name="default"> <attributes></attributes> </xsl:with-param> </xsl:call-template> Result: <attributes></attributes> 2. With `merge-nodes`: Example call: <xsl:call-template name="merge-nodes"> <xsl:with-param name="input"> <attributes> <rel>tooltip</rel> </attributes> </xsl:with-param> <xsl:with-param name="default"> <attributes merge-nodes="all"></attributes> </xsl:with-param> </xsl:call-template> Result: <attributes> <rel>tooltip</rel> </attributes> --> <xsl:template name="merge-nodes"> <xsl:param name="input"/> <xsl:param name="default"/> <xsl:variable name="i-node-set"> <merge-nodes> <xsl:copy-of select="$input"/> </merge-nodes> </xsl:variable> <xsl:variable name="d-node-set"> <merge-nodes> <xsl:copy-of select="$default"/> </merge-nodes> </xsl:variable> <xsl:variable name="result"> <xsl:apply-templates select="exsl:node-set($d-node-set)/merge-nodes" mode="merge-nodes"> <xsl:with-param name="input" select="exsl:node-set($i-node-set)/merge-nodes"/> </xsl:apply-templates> </xsl:variable> <xsl:copy-of select="exsl:node-set($result)/merge-nodes/*"/> </xsl:template> <xsl:template match="*" mode="merge-nodes"> <xsl:param name="input"/> <xsl:param name="debug"/> <xsl:variable name="name" select="name()"/> <xsl:choose> <!-- Merge current node --> <xsl:when test="$input[ name() = $name ]"> <xsl:variable name="current" select="$input[ name() = $name ]"/> <xsl:element name="{$name}"> <!-- Merge attributes --> <xsl:apply-templates select="@*[ name() != 'merge-nodes' ]" mode="merge-nodes"> <xsl:with-param name="input" select="$current"/> </xsl:apply-templates> <xsl:choose> <!-- Special mode: keep everything from this point on --> <xsl:when test="@merge-nodes = 'all'"> <xsl:copy-of select="$current/* | $current/text()"/> </xsl:when> <!-- Merge children --> <xsl:when test="count($current/*) > 0"> <xsl:apply-templates select="*" mode="merge-nodes"> <xsl:with-param name="input" select="$current/*"/> </xsl:apply-templates> </xsl:when> <!-- Final node in input, not final node in default. Write default children --> <xsl:when test="count(*) > 0"> <xsl:copy-of select="* | text()"/> </xsl:when> <!-- Final node in input, final node in default. Write input value --> <xsl:otherwise> <xsl:value-of select="$current"/> </xsl:otherwise> </xsl:choose> </xsl:element> </xsl:when> <!-- Default node --> <xsl:otherwise> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="@*[ name='merge-nodes' ]" mode="merge-nodes"> <xsl:param name="input"/> <xsl:attribute name="{name(.)}"> <xsl:choose> <!-- Keep input attribute --> <xsl:when test="$input/@*[ name() = name(current()) ]"> <xsl:value-of select="$input/@*[ name() = name(current()) ]"/> </xsl:when> <!-- Default attribute --> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> </xsl:stylesheet>