Home > Mobile >  Using XSL transform, how do I only return XML elements that require a change
Using XSL transform, how do I only return XML elements that require a change

Time:04-30

I have an XLM that I need to process with XSL, my code concatenates several elements to the description element but the output needs to only include elements that have changed.

Right now, my code returns everything correctly concatenated but it also returns elements that did not need any changes.

My sample XML has 3 items, the first does not have any changes so it does not need to be returned. The second has a change in Quantity the third needs the concatenation part so those last two are the only ones that should be returned.

Sample XML

<?xml version='1.0' encoding='UTF-8'?>
<document>
    <myObjects>
        <Base>
            <Code>11</Code>
            <Item>216</Item>
            <Build>BH</Build>
            <Quantity>203</Quantity>
            <Description>BH-203-216|Description 1</Description>
        </Base>
        
        <Base>
            <Code>19</Code>
            <Item>169</Item>
            <Build>FM</Build>
            <Quantity>2</Quantity>
            <Description>FM-201-169|Description 2</Description>
        </Base>
        
        <Base>
            <Code>20</Code>
            <Item>169</Item>
            <Build>MM</Build>
            <Quantity></Quantity>
            <Description>Description 3</Description>
        </Base>


    </myObjects>
</document>

The resulting XML should look like this:

<document>
   <myObjects>
      <Base>
         <Code>19</Code>
         <Description>FM-2-169|Description 2</Description>
      </Base>
      <Base>
         <Code>20</Code>
         <Description>MM-169|Description 3</Description>
      </Base>
   </myObjects>
</document>

My XSL code:

<?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 concat-->
    <xsl:template match="Base">
        <xsl:variable name="currentPre" select="substring-before(Description,'|')" />
        <xsl:variable name="currentPost" select="substring-after(Description,'|')" />
        <xsl:variable name="NewPre" select="string-join((Build,Quantity/text(),Item/text()), '-')" />
 
        <xsl:copy>
        
            <xsl:choose>
                <xsl:when test="not(contains(Description, '|'))">
                    <xsl:variable name="emptyDes" select="Description" />
                    <xsl:copy-of select="Code"/>
                    <Description>
                        <xsl:value-of select="string-join((Build,Quantity/text(),Item/text()), '-'), Description" separator="|"/>
                    </Description>
                </xsl:when>
                    
                <xsl:otherwise>
                    <xsl:copy-of select="Code"/>
                    <Description>
                        <xsl:value-of select="string-join((Build,Quantity/text(),Item/text()), '-'), $currentPost" separator="|"/>
                    </Description>
                </xsl:otherwise>
            </xsl:choose>

        </xsl:copy>

    </xsl:template>
</xsl:stylesheet>

CodePudding user response:

If you test whether the newly constructed Description value is equal to the current Description value, and only copy when different, you can also consolidate the logic for generating those items:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
    <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 concat-->
    <xsl:template match="Base">
        <xsl:variable name="currentPre" select="substring-before(Description,'|')" as="xs:string"/>
        <xsl:variable name="currentPost" select="substring-after(Description,'|')[normalize-space()]" as="xs:string?" />
        <xsl:variable name="NewPost" select="($currentPost,Description)[1]"/>
        <xsl:variable name="NewPre" select="string-join((Build,Quantity/text(),Item/text()), '-')" />
        <xsl:variable name="NewDescription" select="string-join(($NewPre, $NewPost), '|')"/>
        <xsl:if test="not(Description eq $NewDescription)">
            <xsl:copy>
                <xsl:copy-of select="Code"/>
                <Description><xsl:value-of select="$NewDescription"/></Description>
            </xsl:copy>
        </xsl:if>   
    </xsl:template>
</xsl:stylesheet>
  • Related