Author:
vladG
Version:
1.0
Release Date:
21 Aug 2012
Category:
Output

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>

Discuss this XSLT Utility

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details