Das exportierte Customizing mithilfe von XSL ändern

Dieses Projekt bietet verschiedene Möglichkeiten, um ein exportiertes NLI B2B Customizing zu manipulieren. Zum Einsatz kommen XML, XSL, YML, AWK, SQL.

Vergleiche auch Customizing Import/Export

Die Global Property EXPORT_SINGLE_XML=true ist Voraussetzung für die weitere Arbeit mit den XSL-Werkzeugen. Damit wird das Customizing in einer einzigen XML unter dem Tag gruppiert.

Werkzeuge

Notepad++

Der Editor kann Witespaces ergaenzen, um die Lesbarkeit von XMLs zu verbessern. Nutze hierfur das Plugin “XML Tools”.

Der Editor kann zwei Dateien miteinander vergleichen und Unterschiede aufzeigen. Nutze hierfur das Plugin “Compare”.

XSL mit Saxon

http://www.saxonica.com/documentation9.5/using-xsl/commandline.html

vgl BTOB-3253

Mit diesem Tool konnen XSLTs ausgefuehrt werden.

java -jar saxon9he.jar -s:in.xml -xsl:CleanUp.xsl -o:out.xml '!indent=yes'

XSD

Mit Hilfe einer XSD kann die Struktur einer XML validiert werden.

AWK

AWK ist ein Linux Werkzeug, mit dem auf der Konsole eine Texttransformation durchgeführt werden kann.

Customizing Disarmer

Der Customizing Disarmer ist ein jar-Werkzeug, mit dessen Hilfe die Migration eines Customizings zwischen Test & Prod unterstützt wird.

XSL Transformationen

Die folgenden XSL & XSD Dokumente finden sich im Anhang.

CleanUp.xsl

entfernt Inhalte aus dem XML, die nicht importiert werden. Die Einträge werden nach Primärschlüsseln sortiert. Die Reihenfolge der Unterelemente wird angepasst.

Falls alle Pflichtdaten vorhanden sind, genuegt das Ergebnis nun Importable.xsd

Falls keine optionalen Elemente fehlen, oder falls IMPORT_CUSTOMIZING_WITH_DEFAULT_VALUES gesetzt ist, kann das Customizing nun importiert werden.

CleanIdleChannelActions.xsl

entfernt alle Actions aus Channels, die nicht aktiv sind.

CleanIdleActions.xsl

entfernt alle Actions, die in keinem Channel konfiguriert sind.

Select.xsl

Diese XSL muss vor Anwendung manuell angepasst werden. Wähle eine Teilmenge des Customizings aus. Hierfür sind in der XSL in den Kopfzeilen (xsl:variable) entsprechende Filter als XPath einzutragen. Zugehörige Extensions/Content-Dateien werden natürlich nicht selektiert.

SelectTransitive.xsl

analog zu Select.xsl Hier werden automatisch nur die Aktions selektiert, die in den ausgewählten Channels auftauchen.

AddHeaders.xsl

fügt Header Einträge hinzu. Vor einem Import müssen diese durch ein CleanUp.xsl entfernt werden.

Folgende Header werden erzeugt:

  • ActionHeader: Action ohne Properties.
  • ChannelHeader: Channel ohne Actions.
  • ServiceHeader: Service ohne Properties.
  • UserHeader: User ohne Rollen.
  • RoleHeader: Rolle ohne Attribute.

Header vereinfachen den Vergleich zweier Customizings. (Header können möglicherweise durch andere XSL Transformationen gelöscht werden)

SelectPks.xsl

Selektiert einzig die Primärschlüssel im Customizing. Hilfreich, wenn auf Primärschlüssel-Konflikte geprüft werden soll.

B2Bxml-To-HumanYml.xsl

Diese Manipulation kann (noch) nicht rückgängig gemacht werden.

Führt mehrere Änderungen durch, um ein B2B Customizing lesbar zu machen. CleanUp, Format Hierarchy, Add ActionNames in ChannelsActions, Use YAMLList Syntax

Format Hierarchy: Die B2B Darstellung der Channels, Users & Roles ist nicht geeignet um von Menschen gelesen zu werden: Ein Eintrag der Channel-Liste ist eine Kombination aus Channel und Action, analog bei Users und Roles.

Diese XSL bereitet die Darstellung der Channels, Users & Roles auf. Ein Channel besteht nun aus Kopfdaten (z.B. Name & Richtung) sowie einer Liste von Actions, analog User & Role.

Mit Hilfe der yml2Sql.awk kann aus der yml eine SQL gebaut werden.

XSLs weiter entwickeln

die meisten XSL Transformationen basieren auf Modifikationen des CleanUp.xsl Falls eine XSL weiter enwickelt wird, müssen die Änderungen entsprechend an allen Transformationen erfolgen.

konkrete Use Cases

Customizing exportieren und aufbereiten

Ziel der folgenden Schritte ist es, ein Customizing in XML so aufzubereiten, dass es von Menschen bearbeitet werden kann.

  1. (empfohlen) aktiviere Hashwerte für Contents und Extensions (GlobalProperty EXPORT_CUSTOMIZING_WITH_HASH = true)
  2. exportiere das Customizing in einer einzigen XML (GlobalProperty EXPORT_SINGLE_XML = true).
  3. Hinweis: Export erfolgt sortiert nach Primärschlüssel
  4. Erzeugen zwei neue Dateien:
    • Customizing.xml / B2B-To-Human.xsl -> menschenlesbarer Customizing-Export. Konvertiere danach in YML: https://dataconverter.curiousconcept.com/
    • Customizing.xml / CleanUp.xsl -> bereinigtes XML, das weiterhin importierbar ist.

ReplaceActionId

Um eine ActionId x durch Id y zu ersetzen: (Dies kann sinnvoll sein, wenn zwei Customizings logisch identisch sind, aber unterschiedliche ActionIds vergeben haben, oder wenn verhindert werden soll, dass beim Import vorhandene Ids überschrieben werden)

Vorbedingung: y wird bisher nicht als ActionId genutzt

WICHTIG: falls beim späteren Import nicht “altes Customizing löschen” markiert ist, müssen vor dem Import alle betroffenen alten Actions und Channels manuell gelöscht werden.

Suche nach <actionId>x</actionId> und ersetze jedes Vorkommen durch <actionId>y</actionId>

Analog können auch folgende Ids ersetzt werden: <channelId>x</channelId> <serviceId>x</serviceId> etc.

Vergleich zweier Customizings

Im folgenden wird beschrieben, wie zwei Customizings in XML miteinander verglichen werden können.

  • exportiere und bereinige beide Customizings mit Hilfe von CleanUp.xsl
  • die folgenden Schritte sind mit Notepad++ ausführbar
  • formatiere beide XMLs mit Plugin XML Tools Pretty Print (ctrl+alt+shift+B)
  • lege beide XMLs nebeneinander (sekundärklick auf Dokumenten-Tab -> Move to other view)
  • führe das Plugin Compare aus
  • falls die Unterschiede zu groß sind, führe zunächst SelectPks.xsl aus und compare auf diesen Dateien.
  • Hinweis zu Content/Extension Hashes: falls im Compare zwei Hashwerte nicht übereinstimmen, handelt es sich nicht um den gleichen Content/Extension.

Import eines manipulierten Customizing XMLs in die B2B

  • falls beim Import nicht “altes Customizing löschen” markiert werden soll, muss vorher geprüft werden, dass keiner der Datenbank Primärschlüssel bereits verwendet wird. (außer diese sollen gezielt überschrieben werden) Verwende hierfür SelectPks.xsl und führe ein weiteres Notepad++ Compare durch.
  • Das Customizing darf nur erlaubte Werte enthalten. Deshalb ist ggf. ein CleanUp.xsl auszuführen.
  • falls Defaultwerte fehlen, müssen diese ergänzt werden: aktiviere vor dem Import die GlobalProperty IMPORT_CUSTOMIZING_WITH_DEFAULT_VALUES = true
  • ob ein Customizing mit Hilfe der B2B importiert werden kann (mit Hilfe von IMPORT_CUSTOMIZING_WITH_DEFAULT_VALUES), kann mit Importable.xsd ueberprueft werden. (Das Erfuellen der XSD ist hinreichend aber nicht notwendig.)

Attachments

Importable.xsd

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<!-- DataType Byte means here 0 (false) or 1 (true) -->
	<xs:element name="customizing">
		<xs:complexType>
			<xs:all>
				<xs:element name="registeredActions">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="registeredAction" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:integer" name="actionId"/>
										<xs:element type="xs:string" name="name"/>
										<xs:element type="xs:string" name="classname"/>
										<xs:element type="xs:string" name="type"/>
										<xs:element type="xs:string" name="vendor"/>
										<xs:element type="xs:string" name="version"/>
										<xs:element type="xs:string" name="description"/>
										<xs:element name="properties">
											<xs:complexType>
												<xs:sequence>
													<xs:element name="actionPropertyMon" maxOccurs="unbounded" minOccurs="0">
														<xs:complexType>
															<xs:all>
																<!-- Foreign Key -->
																<xs:element type="xs:integer" name="actionId"/>
																<xs:element type="xs:string" name="monitoringName"/>
																<xs:element type="xs:string" name="val"/>
																<xs:element type="xs:string" name="type"/>
																<xs:element type="xs:byte" name="profMonitoring"/>
																<xs:element type="xs:byte" name="techMonitoring"/>
																<xs:element type="xs:byte" name="overwriteMC"/>
																<xs:element type="xs:byte" name="mandatory"/>
																<xs:element type="xs:string" name="io"/>
																<!-- Primary Key -->
																<xs:element type="xs:string" name="propertyKey"/>
															</xs:all>
														</xs:complexType>
													</xs:element>
												</xs:sequence>
											</xs:complexType>
										</xs:element>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="channels">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="channel" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="channelId"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="messageType"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="messageVersion"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="presentationType"/>
										<xs:element type="xs:byte" name="direction"/>
										<!-- Foreign Key -->
										<xs:element type="xs:integer" name="actionId"/>
										<xs:element type="xs:integer" name="executePosition"/>
										<xs:element type="xs:byte" name="executeAction"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="services">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="service" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="serviceId"/>
										<xs:element type="xs:string" name="name"/>
										<xs:element type="xs:string" name="classname"/>
										<xs:element type="xs:string" name="type"/>
										<xs:element type="xs:byte" name="startup"/>
										<xs:element type="xs:string" name="channelId"/>
										<xs:element type="xs:byte" name="direction"/>
										<xs:element type="xs:string" name="state"/>
										<xs:element type="xs:string" name="createdBy"/>
										<!-- type=timestamp? always null -->
										<xs:element type="xs:string" name="createdAt"/>
										<xs:element name="serviceProperties">
											<xs:complexType>
												<xs:sequence>
													<xs:element name="serviceProperty" maxOccurs="unbounded" minOccurs="0">
														<xs:complexType>
															<xs:all>
																<!-- Primary Key -->
																<xs:element type="xs:string" name="propertyKey"/>
																<xs:element type="xs:string" name="monitoringName"/>
																<xs:element type="xs:string" name="val"/>
																<xs:element type="xs:string" name="type"/>
																<xs:element type="xs:byte" name="profMonitoring"/>
																<xs:element type="xs:byte" name="techMonitoring"/>
																<xs:element type="xs:byte" name="overwriteMC"/>
																<!-- Foreign Key -->
																<xs:element type="xs:string" name="serviceId"/>
															</xs:all>
														</xs:complexType>
													</xs:element>
												</xs:sequence>
											</xs:complexType>
										</xs:element>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="globalProperties">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="globalProperty" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="propertyKey"/>
										<xs:element type="xs:string" name="val"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="contentList">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="content" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="provider"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="version"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="type"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="format"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="formatVersion"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="destFormatVersion"/>
										<xs:element type="xs:string" name="filename"/>
										<!-- may be part of export, but must not be imported -->
										<xs:element type="xs:string" name="hash" minOccurs="0"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="extensions">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="extension" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="type"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="provider"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="version"/>
										<xs:element type="xs:string" name="filename"/>
										<!-- may be part of export, but must not be imported -->
										<xs:element type="xs:string" name="hash" minOccurs="0"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="users">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="user" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="userId"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="roleId"/>
										<xs:element type="xs:string" name="description"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="roles">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="role" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="roleId"/>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="roleAttributeId"/>
										<xs:element type="xs:string" name="description"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
				<xs:element name="roleAttributes">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="roleAttribute" maxOccurs="unbounded" minOccurs="0">
								<xs:complexType>
									<xs:all>
										<!-- Primary Key -->
										<xs:element type="xs:string" name="roleAttributeId"/>
										<xs:element type="xs:string" name="roleAttributeValue"/>
									</xs:all>
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:all>
		</xs:complexType>
	</xs:element>
</xs:schema>

CleanUp.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- remove values which are not imported. -->
	<!-- Sort by primary keys. -->
	<!-- Rearrange elements, e.g. action properties at the end of an action (instead of start). -->
	<xsl:variable name="actions" select="/customizing/registeredActions/registeredAction" />
	<xsl:variable name="channels" select="/customizing/channels/channel" />
	<xsl:variable name="services" select="/customizing/services/service" />
	<xsl:variable name="globalProperties" select="/customizing/globalProperties/globalProperty" />
	<xsl:variable name="contents" select="/customizing/contentList/content" />
	<xsl:variable name="extensions" select="/customizing/extensions/extension" />
	<xsl:variable name="users" select="/customizing/users/user" />
	<xsl:variable name="roles" select="/customizing/roles/role" />
	<xsl:variable name="attributes" select="/customizing/roleAttributes/roleAttribute" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<!-- Primary Key -->
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:if test="type != ''">
							<xsl:copy-of select="type" />
						</xsl:if>
						<xsl:if test="vendor != ''">
							<xsl:copy-of select="vendor" />
						</xsl:if>
						<xsl:if test="version != ''">
							<xsl:copy-of select="version" />
						</xsl:if>
						<xsl:if test="description != ''">
							<xsl:copy-of select="description" />
						</xsl:if>
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<!-- Primary Key -->
									<xsl:copy-of select="propertyKey" />
									<xsl:if test="monitoringName != ''">
										<xsl:copy-of select="monitoringName" />
									</xsl:if>
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:if test="overwriteMC != '0'">
										<xsl:copy-of select="overwriteMC" />
									</xsl:if>
									<xsl:if test="profMonitoring != '0'">
										<xsl:copy-of select="profMonitoring" />
									</xsl:if>
									<xsl:if test="techMonitoring != '0'">
										<xsl:copy-of select="techMonitoring" />
									</xsl:if>
									<xsl:if test="io != ''">
										<xsl:copy-of select="io" />
									</xsl:if>
									<!--<xsl:copy-of select="actionId" /> -->
									<!-- can be derived -->
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<!-- Primary Key -->
						<xsl:copy-of select="channelId" />
						<xsl:if test="messageType != ''">
							<!-- Primary Key -->
							<xsl:copy-of select="messageType" />
						</xsl:if>
						<xsl:if test="messageVersion != ''">
							<!-- Primary Key -->
							<xsl:copy-of select="messageVersion" />
						</xsl:if>
						<xsl:if test="presentationType != ''">
							<!-- Primary Key -->
							<xsl:copy-of select="presentationType" />
						</xsl:if>
						<xsl:copy-of select="direction" />
						<!-- Primary Key -->
						<xsl:copy-of select="actionId" />
						<!-- <xsl:copy-of select="actionName" /> -->
						<!-- not imported -->
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
						<!-- 0/1 -->
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<!-- Primary Key -->
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:if test="state != ''">
							<xsl:copy-of select="state" />
						</xsl:if>
						<xsl:if test="createdBy != ''">
							<xsl:copy-of select="createdBy" />
						</xsl:if>
						<xsl:if test="createdAt != ''">
							<xsl:copy-of select="createdAt" />
						</xsl:if>
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<!-- Primary Key -->
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:if test="type != ''">
										<xsl:copy-of select="type" />
									</xsl:if>
									<xsl:if test="overwriteMC != '0'">
										<xsl:copy-of select="overwriteMC" />
									</xsl:if>
									<xsl:if test="profMonitoring != '0'">
										<xsl:copy-of select="profMonitoring" />
									</xsl:if>
									<xsl:if test="techMonitoring != '0'">
										<xsl:copy-of select="techMonitoring" />
									</xsl:if>
									<!--<xsl:copy-of select="serviceId" /> -->
									<!-- can be derived -->
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<!-- Primary Key -->
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<!-- Primary Key -->
						<xsl:copy-of select="provider" />
						<!-- Primary Key -->
						<xsl:copy-of select="version" />
						<!-- Primary Key -->
						<xsl:copy-of select="type" />
						<!-- Primary Key -->
						<xsl:copy-of select="format" />
						<!-- Primary Key -->
						<xsl:copy-of select="formatVersion" />
						<!-- Primary Key -->
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<!-- <xsl:copy-of select="hash" /> -->
						<!-- not imported -->
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<!-- Primary Key -->
						<xsl:copy-of select="type" />
						<xsl:if test="provider != ''">
							<!-- Primary Key -->
							<xsl:copy-of select="provider" />
						</xsl:if>
						<xsl:if test="version != ''">
							<!-- Primary Key -->
							<xsl:copy-of select="version" />
						</xsl:if>
						<xsl:copy-of select="filename" />
						<!-- <xsl:copy-of select="hash" /> -->
						<!-- not imported -->
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<!-- Primary Key -->
						<xsl:copy-of select="userId"/>
						<!-- Primary Key -->
						<xsl:copy-of select="roleId"/>
						<xsl:if test="description != ''">
							<xsl:copy-of select="description"/>
						</xsl:if>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<!-- Primary Key -->
						<xsl:copy-of select="roleId"/>
						<!-- Primary Key -->
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<!-- Primary Key -->
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

B2Bxml-To-HumanYml.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>

	<!-- Achtung: Passwoerter werden nicht exportiert! -->

	<xsl:variable name="actions" select="/customizing/registeredActions/registeredAction" />
	<xsl:variable name="channels" select="/customizing/channels/channel" />
	<xsl:variable name="services" select="/customizing/services/service" />
	<xsl:variable name="globalProperties" select="/customizing/globalProperties/globalProperty" />
	<xsl:variable name="contents" select="/customizing/contentList/content" />
	<xsl:variable name="extensions" select="/customizing/extensions/extension" />
	<xsl:variable name="users" select="/customizing/users/user" />
	<xsl:variable name="roles" select="/customizing/roles/role" />
	<xsl:variable name="attributes" select="/customizing/roleAttributes/roleAttribute" />

	<xsl:key name="channelKey" match="/customizing/channels/channel" use="concat(channelId,messageType,messageVersion,presentationType)" />
	<xsl:key name="userId" match="/customizing/users/user/userId/text()" use="." />
	<xsl:key name="roleId" match="/customizing/roles/role/roleId/text()" use="." />

	<xsl:template match="/">

		<xsl:text>accounts:&#xA;</xsl:text>
		<xsl:for-each select="/customizing/users/user/userId/text()[generate-id() = generate-id(key('userId',.)[1])]">
			<xsl:sort select="."/>
			<xsl:value-of select="concat('  ', ../../userId, ':&#xA;')"/>
			<xsl:text>    roles:[ </xsl:text>
			<xsl:variable name="userId">
				<xsl:value-of select="." />
			</xsl:variable>
			<xsl:variable name="userRoles" select="/customizing/users/user[userId/text() = $userId]"/>
			<xsl:for-each select="$userRoles">
				<xsl:sort select="roleId" />
				<xsl:value-of select="roleId"/>
				<xsl:choose>
					<xsl:when test="position() &lt; count($userRoles)"><xsl:text>, </xsl:text></xsl:when>
					<xsl:otherwise><xsl:text> </xsl:text></xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
			<xsl:text>]&#xA;</xsl:text>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>roles:&#xA;</xsl:text>
		<xsl:for-each select="/customizing/roles/role/roleId/text()[generate-id() = generate-id(key('roleId',.)[1])]">
			<xsl:sort select="."/>
			<xsl:value-of select="concat('  ', ../../roleId, ':&#xA;')"/>
			<xsl:variable name="roleId">
				<xsl:value-of select="." />
			</xsl:variable>
			<xsl:for-each select="/customizing/roles/role[roleId/text() = $roleId]">
				<xsl:sort select="roleAttributeId" />
				<xsl:value-of select="concat('    - ', roleAttributeId, '&#xA;')"/>
			</xsl:for-each>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>roleAttributes:&#xA;</xsl:text>
		<xsl:for-each select="$attributes">
			<xsl:sort select="roleAttributeId"/>
			<xsl:value-of select="concat('  ', roleAttributeId, ': ', roleAttributeValue, '&#xA;')"/>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>globalProperties:&#xA;</xsl:text>
		<xsl:for-each select="$globalProperties">
			<xsl:sort select="propertyKey"/>
			<xsl:value-of select="concat('  ', propertyKey, ': &quot;', val, '&quot;&#xA;')"/>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>services:&#xA;</xsl:text>
		<xsl:for-each select="$services">
			<xsl:sort select="serviceId"/>
			<xsl:value-of select="concat('  &quot;', serviceId, '&quot;:&#xA;')"/>
			<xsl:if test="name and name != ''">
				<xsl:value-of select="concat('    name: ', name, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="classname and classname != ''">
				<xsl:value-of select="concat('    class: ', classname, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="type and type != ''">
				<xsl:value-of select="concat('    type: ', type, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="startup and startup != '0'">
				<xsl:text>    startup: true&#xA;</xsl:text>
			</xsl:if>
			<xsl:if test="channelId and channelId != ''">
				<xsl:value-of select="concat('    channel: ', channelId, '&#xA;')"/>
			</xsl:if>
			<xsl:choose>
				<xsl:when test="direction = '1'">
					<xsl:text>    direction: IN&#xA;</xsl:text>
				</xsl:when>
				<xsl:otherwise>
					<xsl:text>    direction: OUT&#xA;</xsl:text>
				</xsl:otherwise>
			</xsl:choose>
			<xsl:if test="state">
				<xsl:value-of select="concat('    state: ', state, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="createdBy">
				<xsl:value-of select="concat('    createdBy: ', createdBy, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="createdAt">
				<xsl:value-of select="concat('    createdAt: ', createdAt, '&#xA;')"/>
			</xsl:if>
			<xsl:text>    properties:&#xA;</xsl:text>
			<xsl:for-each select="serviceProperties/serviceProperty">
				<xsl:sort select="propertyKey"/>
				<xsl:choose>
					<xsl:when test="(not(profMonitoring) or profMonitoring='0') and
					(not(techMonitoring) or techMonitoring='0') and
					(not(overwriteMC) or overwriteMC='0') and
					(not(type) or type='')">
						<xsl:value-of select="concat('      ', propertyKey, ': &quot;', val, '&quot;&#xA;')"/>
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="concat('      ', propertyKey, ':&#xA;')"/>
						<xsl:value-of select="concat('        value: &quot;', val, '&quot;&#xA;')"/>
						<xsl:if test="type and type != ''">
							<xsl:value-of select="concat('        type: ', type, '&#xA;')"/>
						</xsl:if>
						<xsl:if test="overwriteMC and overwriteMC != '0'">
							<xsl:text>        owMc: true&#xA;</xsl:text>
						</xsl:if>
						<xsl:if test="profMonitoring and profMonitoring != '0'">
							<xsl:text>        profMon: true&#xA;</xsl:text>
						</xsl:if>
						<xsl:if test="techMonitoring and techMonitoring != '0'">
							<xsl:text>        techMon: true&#xA;</xsl:text>
						</xsl:if>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>actions:&#xA;</xsl:text>
		<xsl:for-each select="$actions">
			<xsl:sort data-type="number" select="name"/>
			<xsl:value-of select="concat('  &quot;', name, '&quot;:&#xA;')"/>
			<xsl:value-of select="concat('    id: ', actionId, '&#xA;')"/>
			<xsl:if test="classname and classname!=''">
				<xsl:value-of select="concat('    class: ', classname, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="type and type!=''">
				<xsl:value-of select="concat('    type: ', type, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="description and description!=''">
				<xsl:value-of select='concat("    description: &apos;", description, "&apos;&#xA;")'/>
			</xsl:if>
			<xsl:if test="vendor and vendor!=''">
				<xsl:value-of select="concat('    vendor: ', vendor, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="version and version!=''">
				<xsl:value-of select="concat('    version: ', version, '&#xA;')"/>
			</xsl:if>
			<xsl:text>    properties:&#xA;</xsl:text>
			<xsl:for-each select="properties/actionPropertyMon">
				<xsl:sort select="propertyKey"/>
				<xsl:choose>
					<xsl:when test="(not(type) or type='') and
					(not(profMonitoring) or profMonitoring='0') and
					(not(techMonitoring) or techMonitoring='0') and
					(not(overwriteMC) or overwriteMC='0') and
					(not(io) or io='') and
					(not(monitoringName) or monitoringName='')">
						<xsl:value-of select="concat('      ', propertyKey, ': &quot;', val, '&quot;&#xA;')"/>
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="concat('      ', propertyKey, ':&#xA;')"/>
						<xsl:value-of select="concat('        value: &quot;', val, '&quot;&#xA;')"/>
						<xsl:if test="overwriteMC and overwriteMC != '0'">
							<xsl:text>        owMc: true&#xA;</xsl:text>
						</xsl:if>
						<xsl:if test="profMonitoring and profMonitoring != '0'">
							<xsl:text>        profMon: true&#xA;</xsl:text>
						</xsl:if>
						<xsl:if test="techMonitoring and techMonitoring != '0'">
							<xsl:text>        techMon: true&#xA;</xsl:text>
						</xsl:if>
						<xsl:if test="io and io != ''">
							<xsl:value-of select="concat('        io: ', io, '&#xA;')"/>
						</xsl:if>
						<xsl:if test="type and type != ''">
							<xsl:value-of select="concat('        type: ', type, '&#xA;')"/>
						</xsl:if>
						<xsl:if test="monitoringName and monitoringName != ''">
							<xsl:value-of select="concat('        monitoringName: ', monitoringName, '&#xA;')"/>
						</xsl:if>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>channels:&#xA;</xsl:text>
		<xsl:for-each select="/customizing/channels/channel[generate-id() = generate-id(key('channelKey',concat(channelId,messageType,messageVersion,presentationType))[1])]">
			<xsl:sort select="channelId"/>
			<xsl:sort select="messageType"/>
			<xsl:sort select="messageVersion"/>
			<xsl:sort select="presentationType"/>
			<xsl:text>  -&#xA;</xsl:text>
			<xsl:value-of select="concat('    id: ', channelId, '&#xA;')"/>
			<xsl:if test="messageType and messageType != ''">
				<xsl:value-of select="concat('    formatType: ', messageType, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="messageVersion and messageVersion != ''">
				<xsl:value-of select="concat('    formatVersion: ', messageVersion, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="presentationType and presentationType != ''">
				<xsl:value-of select="concat('    presentationType: ', presentationType, '&#xA;')"/>
			</xsl:if>
			<xsl:choose>
				<xsl:when test="direction = '1'">
					<xsl:text>    direction: OUT&#xA;</xsl:text>
				</xsl:when>
				<xsl:otherwise>
					<xsl:text>    direction: IN&#xA;</xsl:text>
				</xsl:otherwise>
			</xsl:choose>
			<xsl:variable name="channelPrimaryKey">
				<xsl:copy-of select="concat(channelId,messageType,messageVersion,presentationType)" />
			</xsl:variable>
			<xsl:text>    actions:&#xA;</xsl:text>
			<xsl:for-each select="/customizing/channels/channel[concat(channelId,messageType,messageVersion,presentationType) = $channelPrimaryKey]">
				<xsl:sort select="executePosition" data-type="number"/>
				<xsl:variable name="channelActionId">
					<xsl:value-of select="actionId" />
				</xsl:variable>
				<xsl:variable name="actionName">
					<xsl:value-of select="/customizing/registeredActions/registeredAction[actionId = $channelActionId]/name" />
				</xsl:variable>
				<xsl:variable name="actionKey">
					<xsl:choose>
						<xsl:when test="$actionName and $actionName != ''"><xsl:value-of select="$actionName"/></xsl:when>
						<xsl:otherwise><xsl:value-of select="$channelActionId"/></xsl:otherwise>
					</xsl:choose>
				</xsl:variable>
				<xsl:variable name="active">
					<xsl:choose>
						<xsl:when test="executeAction=1">true</xsl:when>
						<xsl:otherwise>false</xsl:otherwise>
					</xsl:choose>
				</xsl:variable>
				<xsl:value-of select="concat('      &quot;', $actionKey, '&quot;: ', $active, '&#xA;')"/>
			</xsl:for-each>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>extensions:&#xA;</xsl:text>
		<xsl:for-each select="$extensions">
			<xsl:sort select="type"/>
			<xsl:sort select="provider"/>
			<xsl:sort select="version"/>
			<xsl:text>  -&#xA;</xsl:text>
			<xsl:if test="type and type != ''">
				<xsl:value-of select="concat('    type: ', type, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="provider and provider != ''">
				<xsl:value-of select="concat('    provider: ', provider, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="version and version != ''">
				<xsl:value-of select="concat('    version: ', version, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="filename and filename != ''">
				<xsl:value-of select="concat('    file: ', filename, '&#xA;')"/>
			</xsl:if>
		</xsl:for-each>

		<xsl:text>&#xA;</xsl:text>
		<xsl:text>contents:&#xA;</xsl:text>
		<xsl:for-each select="$contents">
			<xsl:sort select="provider"/>
			<xsl:sort select="version"/>
			<xsl:sort select="type"/>
			<xsl:sort select="format"/>
			<xsl:sort select="formatVersion"/>
			<xsl:sort select="destFormatVersion"/>
			<xsl:text>  -&#xA;</xsl:text>
			<xsl:if test="type and type != ''">
				<xsl:value-of select="concat('    type: ', type, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="provider and provider != ''">
				<xsl:value-of select="concat('    provider: ', provider, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="version and version != ''">
				<xsl:value-of select="concat('    version: ', version, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="format and format != ''">
				<xsl:value-of select="concat('    format: ', format, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="formatVersion and formatVersion != ''">
				<xsl:value-of select="concat('    formatVersion: ', formatVersion, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="destFormatVersion and destFormatVersion != ''">
				<xsl:value-of select="concat('    destFormatVersion: ', destFormatVersion, '&#xA;')"/>
			</xsl:if>
			<xsl:if test="filename and filename != ''">
				<xsl:value-of select="concat('    file: ', filename, '&#xA;')"/>
			</xsl:if>
		</xsl:for-each>

	</xsl:template>

</xsl:stylesheet>

CleanIdleChannelActions.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- Remove channelActions which are not executed. -->
	<xsl:variable name="actions" select="//registeredActions/registeredAction" />
	<xsl:variable name="channels" select="//channels/channel[executeAction='1']" />
	<xsl:variable name="services" select="//services/service" />
	<xsl:variable name="globalProperties" select="//globalProperties/globalProperty" />
	<xsl:variable name="contents" select="//contentList/content" />
	<xsl:variable name="extensions" select="//extensions/extension" />
	<xsl:variable name="users" select="//users/user" />
	<xsl:variable name="roles" select="//roles/role" />
	<xsl:variable name="attributes" select="//roleAttributes/roleAttribute" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="vendor" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="description" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="monitoringName" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="io" />
									<xsl:copy-of select="actionId" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="state" />
						<xsl:copy-of select="createdBy" />
						<xsl:copy-of select="createdAt" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="serviceId" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="description"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

CleanIdleActions.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- Remove actions which are not assigned to any channel. -->
	<xsl:variable name="channels" select="//channels/channel" />
	<xsl:variable name="actions" select="//registeredActions/registeredAction[actionId = $channels/actionId]" />
	<xsl:variable name="services" select="//services/service" />
	<xsl:variable name="globalProperties" select="//globalProperties/globalProperty" />
	<xsl:variable name="contents" select="//contentList/content" />
	<xsl:variable name="extensions" select="//extensions/extension" />
	<xsl:variable name="users" select="//users/user" />
	<xsl:variable name="roles" select="//roles/role" />
	<xsl:variable name="attributes" select="//roleAttributes/roleAttribute" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="vendor" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="description" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="monitoringName" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="io" />
									<xsl:copy-of select="actionId" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="state" />
						<xsl:copy-of select="createdBy" />
						<xsl:copy-of select="createdAt" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="serviceId" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="description"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

Select.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- Select only specified elements. Selects nothing by default. -->
	<!-- Syntax Example: select="//extension[type='FLEXIBLE_INDEX' and provider='NLI']|//extension[type='GENERIC_MAP']" -->
	<xsl:variable name="actions" select="//registeredAction[actionId='VOID']" />
	<xsl:variable name="channels" select="//channel[channelId='VOID']" />
	<xsl:variable name="services" select="//service[serviceId='VOID']" />
	<xsl:variable name="globalProperties" select="//globalProperty[propertyKey='VOID']" />
	<xsl:variable name="contents" select="//content[format='VOID' and formatVersion='VOID' and destFormatVersion='VOID']" />
	<xsl:variable name="extensions" select="//extension[provider='VOID']" />
	<xsl:variable name="users" select="//user[userId='VOID']" />
	<xsl:variable name="roles" select="//role[roleId='VOID']" />
	<xsl:variable name="attributes" select="//roleAttribute[roleAttributeId='VOID']" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="vendor" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="description" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="monitoringName" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="io" />
									<xsl:copy-of select="actionId" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="state" />
						<xsl:copy-of select="createdBy" />
						<xsl:copy-of select="createdAt" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="serviceId" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="description"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

SelectTransitive.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- Select only specified elements. Selects nothing by default. -->
	<!-- An action is selected if and only if it is part of a selected channel. -->
	<!-- Syntax Example: select="//channel[channelId='IN_ISU' and messageType='UTILMD']|//channel[channelId='OUT_ISU']" -->
	<xsl:variable name="channels" select="//channel[channelId='VOID' and executeAction='1']" />
	<xsl:variable name="actions" select="//registeredActions/registeredAction[actionId = $channels/actionId]" />
	<xsl:variable name="services" select="//service[serviceId='VOID']" />
	<xsl:variable name="globalProperties" select="//globalProperty[propertyKey='VOID']" />
	<xsl:variable name="contents" select="//content[format='VOID' and formatVersion='VOID' and destFormatVersion='VOID']" />
	<xsl:variable name="extensions" select="//extension[provider='VOID']" />
	<xsl:variable name="users" select="//user[userId='VOID']" />
	<xsl:variable name="roles" select="//role[roleId='VOID']" />
	<xsl:variable name="attributes" select="//roleAttribute[roleAttributeId='VOID']" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="vendor" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="description" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="monitoringName" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="io" />
									<xsl:copy-of select="actionId" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="state" />
						<xsl:copy-of select="createdBy" />
						<xsl:copy-of select="createdAt" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="serviceId" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="description"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

AddHeaders.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- Add headers to actions (no properties),channels (no actions), services (no properties), users (no roles), roles (no attributes). -->
	<xsl:variable name="actions" select="//registeredActions/registeredAction" />
	<xsl:variable name="channelHeaders" select="//channels/channel[generate-id() = generate-id(key('channelKey',concat(channelId,messageType,messageVersion,presentationType))[1])]" />
	<xsl:variable name="channels" select="//channels/channel" />
	<xsl:variable name="services" select="//services/service" />
	<xsl:variable name="globalProperties" select="//globalProperties/globalProperty" />
	<xsl:variable name="contents" select="//contentList/content" />
	<xsl:variable name="extensions" select="//extensions/extension" />
	<xsl:variable name="userHeaders" select="//users/user/userId/text()[generate-id() = generate-id(key('userId',.)[1])]/../.." />
	<xsl:variable name="users" select="//users/user" />
	<xsl:variable name="roleHeaders" select="//roles/role/roleId/text()[generate-id() = generate-id(key('roleId',.)[1])]/../.." />
	<xsl:variable name="roles" select="//roles/role" />
	<xsl:variable name="attributes" select="//roleAttributes/roleAttribute" />
	<xsl:key name="channelKey" match="//channels/channel" use="concat(channelId,messageType,messageVersion,presentationType)" />
	<xsl:key name="userId" match="//users/user/userId/text()" use="." />
	<xsl:key name="roleId" match="//roles/role/roleId/text()" use="." />
	<xsl:template match="/customizing">
		<customizing>
			<actionHeaders>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<actionHeader>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="description" />
					</actionHeader>
				</xsl:for-each>
			</actionHeaders>
			<channelHeaders>
				<xsl:for-each select="$channelHeaders">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<channelHeader>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
					</channelHeader>
				</xsl:for-each>
			</channelHeaders>
			<serviceHeaders>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<serviceHeader>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
					</serviceHeader>
				</xsl:for-each>
			</serviceHeaders>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
						<xsl:copy-of select="val" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="filename" />
						<xsl:copy-of select="hash" />
					</extension>
				</xsl:for-each>
			</extensions>
			<userHeaders>
				<xsl:for-each select="$userHeaders">
					<xsl:sort select="userId"/>
					<userHeader>
						<xsl:copy-of select="userId"/>
					</userHeader>
				</xsl:for-each>
			</userHeaders>
			<roleHeaders>
				<xsl:for-each select="$roleHeaders">
					<xsl:sort select="roleId"/>
					<roleHeader>
						<xsl:copy-of select="roleId"/>
					</roleHeader>
				</xsl:for-each>
			</roleHeaders>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
						<xsl:copy-of select="roleAttributeValue" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="vendor" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="description" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="monitoringName" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="io" />
									<xsl:copy-of select="actionId" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="executePosition" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="actionId" />
						<xsl:copy-of select="actionName" />
						<xsl:copy-of select="executePosition" />
						<xsl:copy-of select="executeAction" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<xsl:copy-of select="name" />
						<xsl:copy-of select="classname" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="startup" />
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="direction" />
						<xsl:copy-of select="state" />
						<xsl:copy-of select="createdBy" />
						<xsl:copy-of select="createdAt" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
									<xsl:copy-of select="val" />
									<xsl:copy-of select="type" />
									<xsl:copy-of select="overwriteMC" />
									<xsl:copy-of select="profMonitoring" />
									<xsl:copy-of select="techMonitoring" />
									<xsl:copy-of select="serviceId" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="description"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

SelectPks.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<!-- select only primary keys. Order by Primary Keys. Also ChannelActions will be ordered by PK, not by executePosition. -->
	<xsl:variable name="actions" select="//registeredActions/registeredAction" />
	<xsl:variable name="channels" select="//channels/channel" />
	<xsl:variable name="services" select="//services/service" />
	<xsl:variable name="globalProperties" select="//globalProperties/globalProperty" />
	<xsl:variable name="contents" select="//contentList/content" />
	<xsl:variable name="extensions" select="//extensions/extension" />
	<xsl:variable name="users" select="//users/user" />
	<xsl:variable name="roles" select="//roles/role" />
	<xsl:variable name="attributes" select="//roleAttributes/roleAttribute" />
	<xsl:template match="/customizing">
		<customizing>
			<registeredActions>
				<xsl:for-each select="$actions">
					<xsl:sort data-type="number" select="actionId"/>
					<registeredAction>
						<xsl:copy-of select="actionId" />
						<properties>
							<xsl:for-each select="properties/actionPropertyMon">
								<xsl:sort select="propertyKey"/>
								<actionPropertyMon>
									<xsl:copy-of select="propertyKey" />
								</actionPropertyMon>
							</xsl:for-each>
						</properties>
					</registeredAction>
				</xsl:for-each>
			</registeredActions>
			<channels>
				<xsl:for-each select="$channels">
					<xsl:sort select="channelId"/>
					<xsl:sort select="messageType"/>
					<xsl:sort select="messageVersion"/>
					<xsl:sort select="presentationType"/>
					<xsl:sort select="actionId" data-type="number"/>
					<channel>
						<xsl:copy-of select="channelId" />
						<xsl:copy-of select="messageType" />
						<xsl:copy-of select="messageVersion" />
						<xsl:copy-of select="presentationType" />
						<xsl:copy-of select="actionId" />
					</channel>
				</xsl:for-each>
			</channels>
			<services>
				<xsl:for-each select="$services">
					<xsl:sort select="serviceId"/>
					<service>
						<xsl:copy-of select="serviceId" />
						<serviceProperties>
							<xsl:for-each select="serviceProperties/serviceProperty">
								<xsl:sort select="propertyKey"/>
								<serviceProperty>
									<xsl:copy-of select="propertyKey" />
								</serviceProperty>
							</xsl:for-each>
						</serviceProperties>
					</service>
				</xsl:for-each>
			</services>
			<globalProperties>
				<xsl:for-each select="$globalProperties">
					<xsl:sort select="propertyKey"/>
					<globalProperty>
						<xsl:copy-of select="propertyKey" />
					</globalProperty>
				</xsl:for-each>
			</globalProperties>
			<contentList>
				<xsl:for-each select="$contents">
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<xsl:sort select="type"/>
					<xsl:sort select="format"/>
					<xsl:sort select="formatVersion"/>
					<xsl:sort select="destFormatVersion"/>
					<content>
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
						<xsl:copy-of select="type" />
						<xsl:copy-of select="format" />
						<xsl:copy-of select="formatVersion" />
						<xsl:copy-of select="destFormatVersion" />
					</content>
				</xsl:for-each>
			</contentList>
			<extensions>
				<xsl:for-each select="$extensions">
					<xsl:sort select="type"/>
					<xsl:sort select="provider"/>
					<xsl:sort select="version"/>
					<extension>
						<xsl:copy-of select="type" />
						<xsl:copy-of select="provider" />
						<xsl:copy-of select="version" />
					</extension>
				</xsl:for-each>
			</extensions>
			<users>
				<xsl:for-each select="$users">
					<xsl:sort select="userId"/>
					<xsl:sort select="roleId"/>
					<user>
						<xsl:copy-of select="userId"/>
						<xsl:copy-of select="roleId"/>
					</user>
				</xsl:for-each>
			</users>
			<roles>
				<xsl:for-each select="$roles">
					<xsl:sort select="roleId"/>
					<xsl:sort select="roleAttributeId"/>
					<role>
						<xsl:copy-of select="roleId"/>
						<xsl:copy-of select="roleAttributeId"/>
					</role>
				</xsl:for-each>
			</roles>
			<roleAttributes>
				<xsl:for-each select="$attributes">
					<xsl:sort select="roleAttributeId"/>
					<roleAttribute>
						<xsl:copy-of select="roleAttributeId" />
					</roleAttribute>
				</xsl:for-each>
			</roleAttributes>
		</customizing>
	</xsl:template>
</xsl:stylesheet>

yml2Sql.awk

{
    if (!isComment()) {
        splitKeyValue()
        updateLevel()
        if (level == 0) {
            updateType()
        } else {
            if (type == "account")
                parseAccount()
            else if (type == "role")
                parseRole()
            else if (type == "roleAttribute")
                parseRoleAttribute()
            else if (type == "globalProperty")
                parseGlobalProperty()
            else if (type == "service")
                parseService()
            else if (type == "action")
                parseAction()
            else if (type == "channel")
                parseChannel()
            else if (type == "extension")
                parseExtension()
            else if (type == "content")
                parseContent()
        }
    }
}
END {
    printAccountsWithRoles()
    printRolesWithRoleAttributes()
    printRoleAttributes()
    printGlobalProperties()
    printServicesWithProperties()
    printActionsWithProperties()
    printChannels()
    printExtensions()
    printContents()
}

function splitKeyValue() {
    split($0, keyValue, ":")
    key = keyValue[1]
    value = substr($0, length(key) + 2)
    key = cleanString(key)
    value = cleanString(value)
}

function updateLevel() {
	indent = getIndent($0)
	if (indent > lastIndent)
	    indentations[indent] = ++level
	else if (indent < lastIndent)
	    level = indentations[indent]
	lastIndent = indent
}

function updateType() {
    if (key == "accounts")
        type = "account"
    else if (key == "roles")
        type = "role"
    else if (key == "roleAttributes")
        type = "roleAttribute"
    else if (key == "globalProperties")
        type = "globalProperty"
    else if (key == "services")
        type = "service"
    else if (key == "actions")
        type = "action"
    else if (key == "channels")
        type = "channel"
    else if (key == "extensions")
        type = "extension"
    else if (key == "contents")
        type = "content"
    else
        type = key
}

function parseAccount() {
    if (level == 1) {
        accountAttributes[++numAccounts, "user"] = key
    } else if (level == 2) {
        if (key != "roles") {
            accountAttributes[numAccounts, key] = value
        } else {
            i = numAccounts
            value = cleanList(value)
            if (value == "") {
                numAccountRoles[i] = 0
            } else {
                split(value, roles, ",")
                for (j in roles) {
                    accountRoles[i, j] = trim(roles[j])
                }
                numAccountRoles[i] = j
            }
        }
    } else if (level == 3) {
        i = numAccounts
        j = ++numAccountRoles[i]
        if (isListEntry(key)) {
            key = cleanString(substr(key, 2))
        }
        accountRoles[i, j] = key
    }
}

function parseRole() {
    if (level == 1) {
        roleIds[++numRoles] = key
        i = numRoles
        value = cleanList(value)
        if (value == "") {
            numRoleRoleAttributes[i] = 0
        } else {
            split(value, attributes, ",")
            for (j in attributes) {
                roleRoleAttributeId[i, j] = trim(attributes[j])
            }
            numRoleRoleAttributes[i] = j
        }
    } else if (level == 2) {
        i = numRoles
        j = ++numRoleRoleAttributes[i]
        if (isListEntry(key)) {
            key = cleanString(substr(key, 2))
        }
        roleRoleAttributeId[i, j] = key
    }
}

function parseRoleAttribute() {
    if (level != 1)
        return
    i = ++numRoleAttributes
    roleAttributes[i, "id"] = key
    roleAttributes[i, "value"] = value
}

function parseGlobalProperty() {
    if (level != 1)
        return
    i = ++numGlobalProperties
    globalProperties[i, "key"] = key
    globalProperties[i, "value"] = value
}

function parseService() {
    if (level == 1) {
        serviceAttributes[++numServices, "id"] = key
    } else if (level == 2) {
        if (key != "properties")
            serviceAttributes[numServices, key] = value
    } else if (level == 3) {
        i = numServices
        j = ++numServiceProperties[i]
        servicePropertyAttributes[i, j, "key"] = key
        servicePropertyAttributes[i, j, "value"] = value
    } else if (level == 4) {
        i = numServices
        j = numServiceProperties[i]
        servicePropertyAttributes[i, j, key] = value
    }
}

function parseAction() {
    if (level == 1) {
        actionAttributes[++numActions, "name"] = key
    } else if (level == 2) {
        if (key != "properties")
            actionAttributes[numActions, key] = value
    } else if (level == 3) {
        i = numActions
        j = ++numActionProperties[i]
        actionPropertyAttributes[i, j, "key"] = key
        actionPropertyAttributes[i, j, "value"] = value
    } else if (level == 4) {
        i = numActions
        j = numActionProperties[i]
        actionPropertyAttributes[i, j, key] = value
    }
}

function parseChannel() {
    if (level == 1) {
        if (isListEntry(key))
            ++numChannels
    } else if (level == 2) {
        if (key != "actions")
            channelAttributes[numChannels, key] = value
    } else if (level == 3) {
        i = numChannels
        j = ++numChannelActions[i]
        channelActionNames[i, j] = key
        channelActionExecutions[i, j] = value
    }
}

function parseExtension() {
    if (level == 1) {
        if (isListEntry(key))
            ++numExtensions
    } else if (level == 2) {
        extensionAttributes[numExtensions, key] = value
    }
}

function parseContent() {
    if (level == 1) {
        if (isListEntry(key))
            ++numContents
    } else if (level == 2) {
        contentAttributes[numContents, key] = value
    }
}

function printAccountsWithRoles() {
    if (numAccounts == 0)
        return
	print ""
	print "-- ############ ######## ############"
	print "-- ############ ACCOUNTS ############"
	print "-- ############ ######## ############"
	print ""
	print "-- b2bbp_adm_account: userId, password, firstName, lastName, email, organization"
	print "-- b2bbp_adm_user: userid, roleid, description"
	for (i=1; i<=numAccounts; ++i) {
	    printf "\n-- ACCOUNT %s\n", accountAttributes[i, "user"]
		printf "INSERT INTO b2bbp_adm_account VALUES (%s, %s, %s, %s, %s, %s);\n",
				str(accountAttributes[i, "user"]),
				str(accountAttributes[i, "password"]),
				str(accountAttributes[i, "firstName"]),
				str(accountAttributes[i, "lastName"]),
				str(accountAttributes[i, "email"]),
				str(accountAttributes[i, "organization"])
		for (j=1; j<=numAccountRoles[i]; ++j) {
		    printf "INSERT INTO b2bbp_adm_user VALUES (%s, %s, %s);\n",
		            str(accountAttributes[i, "user"]),
		            str(accountRoles[i, j]),
		            "''"
		}
	}
}

function printRolesWithRoleAttributes() {
    if (numRoles == 0)
        return
	print ""
	print "-- ############ ##### ############"
	print "-- ############ ROLES ############"
	print "-- ############ ##### ############"
	print ""
	print "-- b2bbp_adm_role: roleId, roleAttributeId, description"
	for (i=1; i<=numRoles; ++i) {
	    printf "\n-- ROLE %s\n", roleIds[i]
	    for (j=1; j<=numRoleRoleAttributes[i]; ++j) {
            printf "INSERT INTO b2bbp_adm_role VALUES (%s, %s, %s);\n",
                    str(roleIds[i]),
                    str(roleRoleAttributeId[i, j]),
                    str(roleRoleAttributeDescription[i, j])
		}
	}
}

function printRoleAttributes() {
    if (numRoleAttributes == 0)
        return
	print ""
	print "-- ############ ############### ############"
	print "-- ############ ROLE ATTRIBUTES ############"
	print "-- ############ ############### ############"
	print ""
	print "-- b2bbp_adm_role_attribute: roleAttributeId, roleAttributeValue"
	for (i=1; i<=numRoleAttributes; ++i) {
		printf "INSERT INTO b2bbp_adm_role_attribute VALUES (%s, %s);\n",
				str(roleAttributes[i, "id"]),
				str(roleAttributes[i, "value"])
	}
}

function printGlobalProperties() {
    if (numGlobalProperties == 0)
        return
	print ""
	print "-- ############ ################# ############"
	print "-- ############ GLOBAL PROPERTIES ############"
	print "-- ############ ################# ############"
	print ""
	print "-- b2bbp_adm_global_property: propertyKey, val"
	for (i=1; i<=numGlobalProperties; ++i) {
		printf "INSERT INTO b2bbp_adm_global_property VALUES (%s, %s);\n",
				str(globalProperties[i, "key"]),
				str(globalProperties[i, "value"])
	}
}

function printServicesWithProperties() {
    if (numServices == 0)
        return
 	print ""
 	print "-- ############ ######## ############"
 	print "-- ############ SERVICES ############"
 	print "-- ############ ######## ############"
 	print ""
 	print "-- b2bbp_adm_service: serviceId, channel, createDate, createdBy, type, name, startup, state, class, direction"
 	print "-- b2bbp_adm_service_property: key, serviceId, value, type, profMon, techMon, monName, owMc"
 	for (i=1; i<=numServices; ++i) {
 		printf "\n-- SERVICE %s\n", serviceAttributes[i, "id"]
 		printf "INSERT INTO b2bbp_adm_service VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);\n",
 				str(serviceAttributes[i, "id"]),
 				str(serviceAttributes[i, "channel"]),
 				orNull(serviceAttributes[i, "createDate"]),
 				str(serviceAttributes[i, "createdBy"]),
 				str(serviceAttributes[i, "type"]),
 				str(serviceAttributes[i, "name"]),
 				boolToInt(serviceAttributes[i, "startup"]),
 				str(serviceAttributes[i, "state"]),
 				str(serviceAttributes[i, "class"]),
 				serviceDirToInt(serviceAttributes[i, "direction"])
 		for (j=1; j<=numServiceProperties[i]; ++j) {
 			printf "INSERT INTO b2bbp_adm_service_property VALUES (%s, %s, %s, %s, %s, %s, %s, %s);\n",
 					str(servicePropertyAttributes[i, j, "key"]),
 					str(serviceAttributes[i, "id"]),
 					str(servicePropertyAttributes[i, j, "value"]),
 					str(servicePropertyAttributes[i, j, "type"]),
 					boolToInt(servicePropertyAttributes[i, j, "profMon"]),
 					boolToInt(servicePropertyAttributes[i, j, "techMon"]),
 					str(servicePropertyAttributes[i, j, "monName"]),
 					boolToInt(servicePropertyAttributes[i, j, "owMc"])
 		}
 	}
}

function printActionsWithProperties() {
    if (numActions == 0)
        return
	print ""
	print "-- ############ ####### ############"
	print "-- ############ ACTIONS ############"
	print "-- ############ ####### ############"
	print ""
	print "-- b2bbp_adm_action_registry: actionId, vendor, classname, version, name, type, description"
	print "-- b2bbp_adm_action_property_mon: propertyKey, actionId, val, type, mandatory, io, profMonitoring, techMonitoring, monitoringName, overwriteMc"
	for (i=1; i<=numActions; ++i) {
		printf "\n-- ACTION %s\n", actionAttributes[i, "id"] " / " actionAttributes[i, "name"]
		printf "INSERT INTO b2bbp_adm_action_registry VALUES (%s, %s, %s, %s, %s, %s, %s);\n",
				str(actionAttributes[i, "id"]),
				str(actionAttributes[i, "vendor"]),
				str(actionAttributes[i, "class"]),
				str(actionAttributes[i, "version"]),
				str(actionAttributes[i, "name"]),
				str(actionAttributes[i, "type"]),
				str(actionAttributes[i, "description"])
		for (j=1; j<=numActionProperties[i]; ++j) {
			printf "INSERT INTO b2bbp_adm_action_property_mon VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);\n",
					str(actionPropertyAttributes[i, j, "key"]),
					str(actionAttributes[i, "id"]),
					str(actionPropertyAttributes[i, j, "value"]),
					str(actionPropertyAttributes[i, j, "type"]),
					str(actionPropertyAttributes[i, j, "mandatory"]),
                    str(actionPropertyAttributes[i, j, "io"]),
					boolToInt(actionPropertyAttributes[i, j, "profMon"]),
					boolToInt(actionPropertyAttributes[i, j, "techMon"]),
					str(actionPropertyAttributes[i, j, "monName"]),
					boolToInt(actionPropertyAttributes[i, j, "owMc"])
		}
	}
}

function printChannels() {
    if (numChannels == 0)
        return
	print ""
	print "-- ############ ######## ############"
	print "-- ############ CHANNELS ############"
	print "-- ############ ######## ############"
	print ""
	print "-- b2bbp_adm_channel: channelId, actionId, messageType, messageVersion, presentationType, executeAction, executePosition, direction"
    for (i=1; i<=numChannels; ++i) {
		printf "\n-- CHANNEL %s\n", channelAttributes[i, "id"] " / " channelAttributes[i, "formatType"]
		for (j=1; j<=numChannelActions[i]; ++j) {
			printf "INSERT INTO b2bbp_adm_channel VALUES (%s, %s, %s, %s, %s, %s, %s, %s);\n",
					str(channelAttributes[i, "id"]),
					str(getActionIdByName(channelActionNames[i, j])),
					str(channelAttributes[i, "formatType"]),
					str(channelAttributes[i, "formatVersion"]),
					str(channelAttributes[i, "presentationType"]),
                    boolToInt(channelActionExecutions[i, j]),
					j * 10,
					channelDirToInt(channelAttributes[i, "direction"])
		}
	}
}

function printExtensions() {
    if (numExtensions == 0)
        return
	print ""
	print "-- ############ ########## ############"
	print "-- ############ EXTENSIONS ############"
	print "-- ############ ########## ############"
	print ""
	print "-- b2bbp_adm_extension: provider, version, type, extension"
	for (i=1; i<=numExtensions; ++i) {
		printf "INSERT INTO b2bbp_extension VALUES (%s, %s, %s, %s);\n",
				str(extensionAttributes[i, "provider"]),
				str(extensionAttributes[i, "version"]),
				str(extensionAttributes[i, "type"]),
				readFile(getExtensionFileName(i))
	}
}

function printContents() {
    if (numContents == 0)
        return
	print ""
	print "-- ############ ######## ############"
	print "-- ############ CONTENTS ############"
	print "-- ############ ######## ############"
	print ""
	print "-- b2bbp_adm_content: provider, version, type, format, formatVersion, destFormatVersion, content"
	for (i=1; i<=numContents; ++i) {
		printf "INSERT INTO b2bbp_content VALUES (%s, %s, %s, %s, %s, %s, %s);\n",
				str(contentAttributes[i, "provider"]),
				str(contentAttributes[i, "version"]),
				str(contentAttributes[i, "type"]),
                str(contentAttributes[i, "formatType"]),
                str(contentAttributes[i, "formatVersion"]),
                str(contentAttributes[i, "destFormat"]),
				readFile(getContentFileName(i))
	}
}

function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s }
function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
function trim(s) { return rtrim(ltrim(s)); }

function cleanString(s) {
    s = trim(s)
    if (match(s, "^\".*\"$") || match(s, "^'.*'$"))
        return substr(s, 2, length(s)-2)
    if (match(s, "^\"") || match(s, "^'")) {
        print "unsupported quotation"
        exit 1
    }
    return s
}

function isComment() {
    commentIdx = match(ltrim($0), "^#")
    return commentIdx > 0
}

function cleanList(s) {
    if (match(s, "^\\[.*\\]$"))
        return substr(s, 2, length(s)-2)
    return s
}

function boolToInt(b) { return b == "true" ? 1 : 0 }

function serviceDirToInt(d) {
    if (d == "IN")
        return 1;
    if (d == "OUT")
        return 0;
    return d;
}

function channelDirToInt(d) {
    if (d == "IN")
        return 0;
    if (d == "OUT")
        return 1;
    return d;
}

function str(x) { return "'" x "'" }
function orNull(x) { return x == "" ? "null" : str(x) }

function isListEntry(key) { return match(key, "^-") }

function getIndent(line) {
    indexOfFirstNoneWhiteSpace = match(line, "\\S")
    if (indexOfFirstNoneWhiteSpace == 0)
        return 0
    else
        return indexOfFirstNoneWhiteSpace - 1
}

function getExtensionFileName(i) {
    file = extensionAttributes[i, "file"]
    if (file != "")
        return file
    provider = extensionAttributes[i, "provider"]
    version = extensionAttributes[i, "version"]
    type = extensionAttributes[i, "type"]
    return "extension/" provider "-" version "." type
}

function getContentFileName(i) {
    file = contentAttributes[i, "file"]
    if (file != "")
        return file
    provider = contentAttributes[i, "provider"]
    version = contentAttributes[i, "version"]
    type = contentAttributes[i, "type"]
    formatType = contentAttributes[i, "formatType"]
    formatVersion = contentAttributes[i, "formatVersion"]
    destFormat = contentAttributes[i, "destFormat"]
    return "content/" provider "-" version "-" formatType "-" formatVersion "-" destFormat "." type
}

function readFile(fileName) {
    return "pg_read_binary_file('/docker-entrypoint-initdb.d/" fileName "')"
}

function getActionIdByName(name) {
    for (k=1; k<=numActions; ++k) {
        if (name == actionAttributes[k, "name"])
            return actionAttributes[k, "id"]
    }
    return "?"
}
View Me   Edit Me