NotTekk
NotTekk

Reputation: 29

How to create node after other specific Node in XSLT 3

I'm currently trying to create a XSL Script that would create a Node (Production) before the Node (Release) and keep the format of the other nodes. Currently my Script is printing the Node (Production) with all the correct information I need but it is creating the node on the place of my Node (Device) by pushing it to the side, as you can see below:

Current result:

<launcher>
    <configs>
        <!-- CREATES PRODUCTION NODE SMASHED WITH THE DEVICE NODE -->
        <config name="ALBA_production" extension="ALBA" version="" stage="PRODUCTION"><title>ALBA (Production)</title></config><config name="ALBA" extends="ALBA" abstract="true">
            <param name="deviceName">ALBA</param>
        </config>
        <config name="ALBA_release" extends="ALBA" version="${releaseSITEVersion}">
            <title>ALBA (Release)</title>           
        </config>
        <config name="ALBA_test" extends="ALBA" version="${testSITEVersion5227}">
            <title>ALBA (Test)</title>      
        </config>
        <!-- MANY MORE NODES AFTER THIS ONE -->
    </configs>
</launcher>

I need this (Production) Node to be after the (Device) Node but before the (Release) Node, as seen here:

<launcher>
    <configs>
        <config name="ALBA" extends="ALBA" abstract="true">
            <param name="deviceName">ALBA</param>
        </config>
        
        <!-- CREATES PRODUCTION NODE HERE -->
        <config name="ALBA_production" extension="ALBA" version="" stage="PRODUCTION">
            <title>ALBA (Production)</title>
        </config>
        <!-- -->
        
        <config name="ALBA_release" extends="ALBA" version="${releaseSITEVersion}">
            <title>ALBA (Release)</title>           
        </config>
        <config name="ALBA_test" extends="ALBA" version="${testSITEVersion5227}">
            <title>ALBA (Test)</title>      
        </config>
        <!-- MANY MORE NODES AFTER THIS ONE -->
    </configs>
</launcher>

This is my current input File (XML) (consider that there will be more blocks of nodes that follow the same structure that I've just shown):

<launcher>
    <configs>
        <config name="ALBA" extends="ALBA" abstract="true">
            <param name="deviceName">ALBA</param>
        </config>
        <!-- CREATES PRODUCTION NODE HERE -->
        <config name="ALBA_release" extends="ALBA" version="${releaseSITEVersion}">
            <title>ALBA (Release)</title>           
        </config>
        <config name="ALBA_test" extends="ALBA" version="${testSITEVersion5227}">
            <title>ALBA (Test)</title>      
        </config>
        <!-- MANY MORE NODES AFTER THIS ONE -->
    </configs>
</launcher>

And finally but never the less my current code:

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="config">
        <xsl:variable name="namePrefix"
            select="replace(replace(@name, '_release', ''), '_test', '')" />
        <xsl:if
            test="count(. | //configs/config[contains(@name, $namePrefix)][1]) &lt;= 1">
            <xsl:apply-templates select="."
                mode="create_production">
                <xsl:with-param name="productionName"
                    select="concat($namePrefix, '_production')" />
            </xsl:apply-templates>
        </xsl:if>
        <xsl:copy-of select="." />
    </xsl:template>

    <xsl:template match="config" mode="create_production">
        <xsl:param name="productionName" />
        <xsl:variable name="versionspec" select="@version" />
        <xsl:variable name="extensionspec" select="@extends" />
        <xsl:if test="not(../config[@name=$productionName])">
            <xsl:copy>
                <xsl:attribute name="name"><xsl:value-of
                    select="$productionName" /></xsl:attribute>
                <xsl:attribute name="extension"><xsl:value-of
                    select="$extensionspec" /></xsl:attribute>
                <xsl:attribute name="version"><xsl:value-of
                    select="$versionspec" /></xsl:attribute>
                <xsl:attribute name="stage">PRODUCTION</xsl:attribute>
                <title>
                    <xsl:value-of
                        select="replace($productionName, '_production', ' (Production)')" />
                </title>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

As I mentioned before my code is outputting the right node but only in the wrong position, that is what I need to know how to solve. Any suggestions?

Upvotes: 0

Views: 79

Answers (1)

Conal Tuohy
Conal Tuohy

Reputation: 3215

It looks like you are creating a new "Production" config based on an existing config which is the first config in the document which has a particular prefix. In the example data you posted, that's a "device" config. Your template FIRST creates the Production config and THEN copies the original (<xsl:copy-of select="." />), but if you want the original (device) config to come first then the xsl:copy-of should be the FIRST child of your <xsl:template match="config">, not the last child.

Upvotes: 1

Related Questions