xslt 1.0 help performing task on first element and different on proceeding elements

StackOverflow https://stackoverflow.com/questions/23685066

  •  23-07-2023
  •  | 
  •  

سؤال

I need to assign a variable once when the first node of many similar nodes appear. My end goal is trying to call the same template over and over from within the main template while storing variables and incrementing them.

Example XML:

<!-- Removed See below examples -->

Example XSL:

<!-- Removed See below examples -->

I will do my best to explain what's going on: $value is referenced from the main template that matches on /ROOT. The output XML needs to have an index on FILE_ITEM_NBR that is incremental everytime it is created. FILE_ITEM_NBR will be generated once outside of the loop and can be staticically set to 1. The other times it's generated are based upon the number of invoices and in this example it's twice per invoice for 3 invoices.

Im using the text from /ROOT/INVOICES/INVOICES_ROW/INV_ID as my starting number, because the number after the hypenated(-) portion of the value is generated based on row number.

I need to grab this number the first time through the loop and populate $value. Any other time I need to reference that number add a static number to it such as its occurrence in the XSL transformation. In the example I show $value + 2 and $value + 3. Then I need to store that value so that each time the loop iterates I keep adding to it.

I hope this explanation was good enough.

In short I need FILE_ITEM_NBR to be uniquely generated every time it appears during the XSL transformation.

EDIT: _______________________________________________________________________________________

I have modified the above XML and XSL examples. The following examples run and the output provided is generated.

Example XML:

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<STUFF/>
<FILE_ITEM_NBR>

</FILE_ITEM_NBR>
<CLIENTNAME>TEST CLIENT</CLIENTNAME>
<INVOICES>
    <INVOICES_ROW>
        <INV_ID>67447-1</INV_ID>
        <INV_TEST1/>
        <INV_TEST2/>
        <INV_TEST3/>
        <MAT_NAME>BLAH BLAH BLAH 1</MAT_NAME>
        <TK_ID>1</TK_ID>
        <EXP_ID>3</EXP_ID>
    </INVOICES_ROW>
    <INVOICES_ROW>
        <INV_ID>12341-2</INV_ID>
        <INV_TEST1/>
        <INV_TEST2/>
        <INV_TEST3/>
        <MAT_NAME>BLAH BLAH BLAH 2</MAT_NAME>
        <TK_ID>2</TK_ID>
        <EXP_ID>3</EXP_ID>
    </INVOICES_ROW>
    <INVOICES_ROW>
        <INV_ID>142445-3</INV_ID>
        <INV_TEST1/>
        <INV_TEST2/>
        <INV_TEST3/>
        <MAT_NAME>BLAH BLAH BLAH 3</MAT_NAME>
        <TK_ID>3</TK_ID>
        <EXP_ID>3</EXP_ID>
    </INVOICES_ROW>
</INVOICES>
</ROOT>

EXAMPLE XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1" indent="yes"/>
<xsl:template name="INV_ID">
    <xsl:choose>
        <xsl:when test="boolean(.)">
            <xsl:call-template name="substring-after-last">
                <xsl:with-param name="input" select="normalize-space(./INV_ID)"/>
                <xsl:with-param name="substr" select="'-'"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise/>
    </xsl:choose>
</xsl:template>
<xsl:template name="substring-after-last">
    <xsl:param name="input"/>
    <xsl:param name="substr"/>
    <!-- Extract the string which comes after the first occurrence -->
    <xsl:variable name="temp" select="substring-after($input,$substr)"/>
    <xsl:choose>
        <!-- If it still contains the search string the recursively process -->
        <xsl:when test="$substr and contains($temp,$substr)">
            <xsl:call-template name="substring-after-last">
                <xsl:with-param name="input" select="$temp"/>
                <xsl:with-param name="substr" select="$substr"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$temp"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template name="start-get-id">
    <xsl:choose>
        <xsl:when test="count(preceding::INVOICES_ROW) = 0">
            <!--<xsl:variable name="id">
                <xsl:call-template name="INV_ID"/>
            </xsl:variable>-->
            <xsl:value-of select="position() * 2 "/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="position() * 2 + 2"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="/ROOT">
    <root>
        <stuff-to-do>
            <xsl:value-of select="STUFF"/>
        </stuff-to-do>
        <file_item_nbr>
            <xsl:text>1</xsl:text>
        </file_item_nbr>
        <client>
            <client_name>
                <xsl:value-of select="CLIENTNAME"/>
            </client_name>
            <file_item_nbr>
                <xsl:text>2</xsl:text>
            </file_item_nbr>
            <xsl:for-each select="/ROOT/INVOICES/INVOICES_ROW">
                <invoice>
                    <inv_id>
                        <xsl:value-of select="INV_ID"/>
                    </inv_id>
                    <inv_date>
                        <xsl:value-of select="INV_TEST1"/>
                    </inv_date>
                    <inv_text>
                        <xsl:value-of select="INV_TEST2"/>
                    </inv_text>
                    <inv_due_date>
                        <xsl:value-of select="INV_TEST3"/>
                    </inv_due_date>
                    <file_item_nbr>
                        <xsl:variable name="value">
                            <xsl:call-template name="start-get-id"/>
                        </xsl:variable>
                        <xsl:variable name="result">
                            <xsl:value-of select="$value + 1"/>
                        </xsl:variable>
                        <xsl:value-of select="$result"/>
                    </file_item_nbr>
                    <mat>
                        <m_name>
                            <xsl:value-of select="MAT_NAME"/>
                        </m_name>
                        <file_item_nbr>
                            <xsl:variable name="value">
                                <xsl:call-template name="start-get-id"/>
                            </xsl:variable>
                            <xsl:variable name="result">
                                <xsl:value-of select="$value + 2"/>
                            </xsl:variable>
                            <xsl:value-of select="$result"/>
                        </file_item_nbr>
                        <tksum>
                            <tk_id>
                                <xsl:value-of select="TK_ID"/>
                            </tk_id>
                            <file_item_nbr>
                                <xsl:variable name="value">
                                    <xsl:call-template name="start-get-id"/>
                                </xsl:variable>
                                <xsl:variable name="result">
                                    <xsl:value-of select="$value + 3"/>
                                </xsl:variable>
                                <xsl:value-of select="$result"/>
                            </file_item_nbr>
                        </tksum>
                        <expense>
                            <exp_id>
                                <xsl:value-of select="EXP_ID"/>
                            </exp_id>
                            <file_item_nbr>
                                <xsl:variable name="value">
                                    <xsl:call-template name="start-get-id"/>
                                </xsl:variable>
                                <xsl:variable name="result">
                                    <xsl:value-of select="$value + 4"/>
                                </xsl:variable>
                                <xsl:value-of select="$result"/>
                            </file_item_nbr>
                        </expense>
                    </mat>
                </invoice>
            </xsl:for-each>
        </client>
    </root>
</xsl:template>
</xsl:stylesheet>

GENERATED OUTPUT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
<stuff-to-do/>
<file_item_nbr>1</file_item_nbr>
<client>
    <client_name>TEST CLIENT</client_name>
    <file_item_nbr>2</file_item_nbr>
    <invoice>
        <inv_id>67447-1</inv_id>
        <inv_date/>
        <inv_text/>
        <inv_due_date/>
        <file_item_nbr>3</file_item_nbr>
        <mat>
            <m_name>BLAH BLAH BLAH 1</m_name>
            <file_item_nbr>4</file_item_nbr>
            <tksum>
                <tk_id>1</tk_id>
                <file_item_nbr>5</file_item_nbr>
            </tksum>
            <expense>
                <exp_id>3</exp_id>
                <file_item_nbr>6</file_item_nbr>
            </expense>
        </mat>
    </invoice>
    <invoice>
        <inv_id>12341-2</inv_id>
        <inv_date/>
        <inv_text/>
        <inv_due_date/>
        <file_item_nbr>7</file_item_nbr>
        <mat>
            <m_name>BLAH BLAH BLAH 2</m_name>
            <file_item_nbr>8</file_item_nbr>
            <tksum>
                <tk_id>2</tk_id>
                <file_item_nbr>9</file_item_nbr>
            </tksum>
            <expense>
                <exp_id>3</exp_id>
                <file_item_nbr>10</file_item_nbr>
            </expense>
        </mat>
    </invoice>
    <invoice>
        <inv_id>142445-3</inv_id>
        <inv_date/>
        <inv_text/>
        <inv_due_date/>
        <file_item_nbr>9</file_item_nbr>
        <mat>
            <m_name>BLAH BLAH BLAH 3</m_name>
            <file_item_nbr>10</file_item_nbr>
            <tksum>
                <tk_id>3</tk_id>
                <file_item_nbr>11</file_item_nbr>
            </tksum>
            <expense>
                <exp_id>3</exp_id>
                <file_item_nbr>12</file_item_nbr>
            </expense>
        </mat>
    </invoice>
</client>
</root>

The generated output is what I need to achieve in my real case scenario, however after each invoice the number is behind by 1.

هل كانت مفيدة؟

المحلول

So if I understand correct you want file_item_nbr continously numbered:

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

<xsl:template match="/ROOT">
    <root>
        <stuff-to-do>
            <xsl:value-of select="STUFF"/>
        </stuff-to-do>
        <file_item_nbr>
            <xsl:text>1</xsl:text>
        </file_item_nbr>
        <client>
            <client_name>TEST CLIENT</client_name>
            <file_item_nbr>2</file_item_nbr>
            <xsl:apply-templates select="INVOICES/INVOICES_ROW"/>
        </client>
    </root>
</xsl:template>

<xsl:template match="INVOICES/INVOICES_ROW">
    <invoice>
        <inv_id>
            <xsl:value-of select="INV_ID"/>
        </inv_id>
        <inv_date>
            <xsl:value-of select="INV_TEST1"/>
        </inv_date>
        <inv_text>
            <xsl:value-of select="INV_TEST2"/>
        </inv_text>
        <inv_due_date>
            <xsl:value-of select="INV_TEST3"/>
        </inv_due_date>
        <file_item_nbr>
            <xsl:value-of select="position() * 4 - 1"/>
        </file_item_nbr>
        <mat>
            <m_name>
                <xsl:value-of select="MAT_NAME"/>
            </m_name>
            <file_item_nbr>
                <xsl:value-of select="position() * 4"/>
            </file_item_nbr>
            <tksum>
                <tk_id>
                    <xsl:value-of select="TK_ID"/>
                </tk_id>
                <file_item_nbr>
                    <xsl:value-of select="position() * 4 + 1"/>
                </file_item_nbr>
            </tksum>
            <expense>
                <exp_id>
                    <xsl:value-of select="EXP_ID"/>
                </exp_id>
                <file_item_nbr>
                    <xsl:value-of select="position() * 4 + 2"/>
                </file_item_nbr>
            </expense>
        </mat>
    </invoice>
</xsl:template>
</xsl:stylesheet>

gives the desired result...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top