Search code examples
recursionxsltxsl-choose

XSL Choosing the correct substring based on conditions


I am transitioning from a simple 2 substring with a ' ' delimiter that currently uses the substring-before and substring-after, but now I am needing to modify it to accommodate multiple substrings that vary in quantity. I have tried several different methods I have found on this side but I am either too much of a rookie to even understand it or I don't think it would work.

<xsl:template name="print_cmp_code_by_color_and_subtype"><xsl:param name="code"/><xsl:param name="color_code"/><xsl:param name="subtype_code"/>
        <xsl:choose>
            <xsl:when test="contains($code,' ')">
                <xsl:call-template name="print_cmp_code_by_color_and_subtype">
                    <xsl:with-param name="code" select="normalize-space(substring-before($code,' '))"/>
                    <xsl:with-param name="color_code" select="$color_code"/>
                    <xsl:with-param name="subtype_code" select="$subtype_code"/>
                </xsl:call-template>
                <xsl:call-template name="print_cmp_code_by_color_and_subtype">
                    <xsl:with-param name="code" select="normalize-space(substring-after($code,' '))"/>
                    <xsl:with-param name="color_code" select="$color_code"/>
                    <xsl:with-param name="subtype_code" select="$subtype_code"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:if test="contains($code,'=')">
                    <xsl:if test="normalize-space(substring-before($code,'='))=$color_code">
                        <xsl:value-of select="normalize-space(substring-after($code,'='))"/>
                    </xsl:if>
                </xsl:if>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
<itemNo>
                    <xsl:choose>
                        <xsl:when test="cmp_code">
                            <xsl:choose>
                                <xsl:when test="contains(cmp_code,'=')">
                                    <xsl:call-template name="print_cmp_code_by_color">
                                        <xsl:with-param name="code" select="cmp_code"/>
                                        <xsl:with-param name="color_code" select="colors/color[col_type='external']/col_code"/>
                                        <xsl:with-param name="subtype_code" select="cmp_options/coption/opt_values/opt_value[(ov_keywords_list/keyword='SAGE') and (ov_active='true')]/ov_description"/>
                                    </xsl:call-template>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:value-of select="cmp_code"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="cmp_series_code"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </itemNo>

The input for the code parameter is the issue. I went from "Dog=9500 Cat=9502" to "Dog_BX=9500 Dog_CX=9502 Cat_BX=9856-BX Cat_CX=9856-CX Elephant=9787 Cow=8734

Sometimes it has a subtype, sometimes it doesn't. Sometimes it needs the color code, sometimes not.

The animal name is the subtype_code, and the BX or CX is the color_code.

The value I am trying to pass through is the corresponding substring where if the string contains an "=", then uses the substring with the matching color_code in the XML. If the substrings contain a "_", it uses the substring that matches the XMLs subtype_code. If it has "=" and "_" then it use the substring that matches the XMLs color_code and subtype_code.

I am so lost and in need of help.

Edit 1: If the color_code in the XML was "CX" and the subtype code in the XML was "Cat" then the expected output would be "9856-CX". the desired output eventually is a json

"itemNo": "9856-CX",
"qty": "1",
"jobNo": "230108",
"batchNo": "-01",
"materials": [
{
"itemNo": "6285-BX",
"qty": "6.677",
"UOM": "FEET",
"location": "230108"
}

the example of the json above is incomplete, however my main focus is parsing the correct parent itemNo to send to SAGE300

XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?>
<jobs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xfatcom2.xsd" generated="2024-04-04T16:14:13" version="2.0">
<job>
<PKEY>1</PKEY>
<ID>19444</ID>
<job_id>162</job_id>
<job_year>2024</job_year>
<job_name>9999999999</job_name>
<job_components>
<component>
<PKEY>26</PKEY>
<FKEY>1</FKEY>
<cmp_code>Dog_BX=9500 Dog_CX=9502 Cat_BX=9856-BX Cat_CX=9856-CX Elephant=9787 Cow=8734</cmp_code>
<colors>
<color>
<PKEY>38</PKEY>
<FKEY>36</FKEY>
<col_type>external</col_type>
<col_code>BX</col_code>
</color>
</colors>
<cmp_options>
<coption>
<opt_values>
<opt_value>
<ov_description>Cat</ov_description>
<ov_keywords_list>
<keyword>SAGE</keyword>
</ov_keywords_list>
<ov_active>true</ov_active>
</opt_value>
</opt_values>
</coption>
</cmp_options>
</component>
<component>
<PKEY>26</PKEY>
<FKEY>1</FKEY>
<cmp_code>Dog_BX=9500 Dog_CX=9502 Cat_BX=9856-BX Cat_CX=9856-CX Elephant=9787 Cow=8734</cmp_code>
<colors>
<color>
<PKEY>38</PKEY>
<FKEY>36</FKEY>
<col_type>external</col_type>
<col_code>CX</col_code>
</color>
</colors>
<cmp_options>
<coption>
<opt_values>
<opt_value>
<ov_description>Dog</ov_description>
<ov_keywords_list>
<keyword>SAGE</keyword>
</ov_keywords_list>
<ov_active>true</ov_active>
</opt_value>
</opt_values>
</coption>
</cmp_options>
</component>
<component>
<PKEY>26</PKEY>
<FKEY>1</FKEY>
<cmp_code>Dog_BX=9500 Dog_CX=9502 Cat_BX=9856-BX Cat_CX=9856-CX Elephant=9787 Cow=8734</cmp_code>
<colors>
<color>
<PKEY>38</PKEY>
<FKEY>36</FKEY>
<col_type>external</col_type>
<col_code>CX</col_code>
</color>
</colors>
<cmp_options>
<coption>
<opt_values>
<opt_value>
<ov_description>Elephant</ov_description>
<ov_keywords_list>
<keyword>SAGE</keyword>
</ov_keywords_list>
<ov_active>true</ov_active>
</opt_value>
</opt_values>
</coption>
</cmp_options>
</component>
</job_components>
</job>
</jobs>

Solution

  • <xsl:template name="split">
            <xsl:param name="code"/>
            <xsl:param name="color_code" select="concat(cmp_options/coption/opt_values/opt_value[(ov_keywords_list/keyword='SAGE') and (ov_active='true')]/opt_code, colors/color[col_type='external']/col_code)"/>
                <xsl:choose>
                    <xsl:when test="contains($code, $color_code)">
                        <xsl:call-template name="split">
                            <xsl:with-param name="code" select="substring-after($code, $color_code)"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="substring-before(substring-after(concat($code,' '),'='),' ')"/>
                </xsl:otherwise>
            </xsl:choose>
    </xsl:template>
    

    So I ended up spending about 2 days just looking for the right method, and found Henrik Hanson's "split string and loop" on GitHub. I still have no idea what I'm doing, but I was able to trial and error different combinations of various things.