Home > other >  Using XSL to concatenate several xml fields following certain criteria
Using XSL to concatenate several xml fields following certain criteria

Time:04-28

I am trying to concatenate several XML fields into another XML fields using XSL.

I want to take an XML with several elements, some of those elements I want to concatenate together, according to some criteria, and add the newly concatenated string to one of the element.

The concatenation should follow the following pattern:

If all elements are all there: build-Space-Item|Description

If there is no Space data: build-Item|Description

If there is no Item: build-Space|Description

If there is no Space and no Item: build|Description

I am very new to XSLT and stumbling around trying to find the correct syntax to create the logic.

My XML looks like this:

<?xml version='1.0' encoding='UTF-8'?>
<document>
    <businessobjects>
        <BaseOrder>
            <Code>1190.00</Code>
            <Item>VE216</Item>
            <buil>CORP</buil>
            <Space></Space>
            <Type>Request</Type>
            <Description>Description 1</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>64497.00</Code>
            <Item>HP01</Item>
            <buil>FO3</buil>
            <Space>002</Space>
            <Type>PPM</Type>
            <Description>Description 2</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>77793.00</Code>
            <Item></Item>
            <buil>EN4</buil>
            <Space>123</Space>
            <Type>Request</Type>
            <Description>Description 3</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>70796.00</Code>
            <Item></Item>
            <buil>SHS</buil>
            <Space></Space>
            <Type>Event</Type>
            <Description>Description 4</Description>
        </BaseOrder>
    </businessobjects>
</document>

My output XML should sendup looking like this:

<?xml version='1.0' encoding='UTF-8'?>
<document>
    <businessobjects>
        <BaseOrder>
            <Code>1190.00</Code>
            <Description>CORP-VE216|Description 1</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>64497.00</Code>
            <Description>FO3-002-HP01|Description 2</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>77793.00</Code>
            <Description>EN4-123|Description 3</Description>
        </BaseOrder>
        <BaseOrder>
            <Code>70796.00</Code>
            <Description>SHS|Description 4</Description>
        </BaseOrder>
    </businessobjects>
</document>

My XSL is only catching on the first case, this might be because of the choose(?). Can anyone give me a lead on how to properly do this?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="utf-8" media-type="xml/plain"/>
    <xsl:strip-space elements="*"/>

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

    <!-- drop elements with smart (kinda..) concat-->
<xsl:template match="BaseOrder">

    <BaseOrder>
        <xsl:variable name="noSpace" select="concat(build,'-',Item,'|')" />
        <xsl:variable name="noItem" select="concat(build,'-',Space,'|')" />
        <xsl:variable name="noSpaceItem" select="concat(build,'|')" />
        <xsl:variable name="full" select="concat(build,'-',Space,'-',Item,'|')" />
        
        <xsl:choose>
            <!-- no space -->
            <xsl:when test="not(@Space)">
                <Code>
                    <xsl:value-of select="Code"/>
                </Code>
                <Description>
                    <xsl:value-of select="concat($noSpace,Description)"/>
                </Description>
            </xsl:when>
            <!-- no Item -->
            <xsl:when test="not(@Item)">
                <Code>
                    <xsl:value-of select="Code"/>
                </Code>
                <Description>
                    <xsl:value-of select="concat($noItem,Description)"/>
                </Description>
            </xsl:when>
            <!-- no Space or Item -->
            <xsl:when test="not(@Space) and not(@Item)">
                <Code>
                    <xsl:value-of select="Code"/>
                </Code>
                <Description>
                    <xsl:value-of select="concat($noSpaceItem,Description)"/>
                </Description>
                
            </xsl:when>
            <!-- When all -->
            <xsl:otherwise>
                <Code>
                    <xsl:value-of select="Code"/>
                </Code>
                <Description>
                    <xsl:value-of select="concat($full,Description)"/>
                </Description>
                
            </xsl:otherwise>
        </xsl:choose>
    </BaseOrder>

</xsl:template>    

</xsl:stylesheet>

Edit: Elements not Attributes..

CodePudding user response:

How about simply:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="BaseOrder">
    <xsl:copy>
        <xsl:copy-of select="Code"/>
        <Description>
            <xsl:value-of select="buil, Space[text()], Item[text()]" separator="-"/>
            <xsl:text>|</xsl:text>
            <xsl:value-of select="Description"/>
         </Description>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Or, if you prefer:

<xsl:template match="BaseOrder">
    <xsl:copy>
        <xsl:copy-of select="Code"/>
        <Description>
            <xsl:value-of select="string-join((buil, Space/text(), Item/text()), '-'), Description" separator="|"/>
         </Description>
    </xsl:copy>
</xsl:template>
  • Related