0

The 'when' condition is not identifying empty elements correctly. The desired output should display the 'EMPTYAddress2' attribute. I have tried various 'not' conditions also but no luck. Please help I'm a newbie. I am using Oxygen XML Developer and no errors are being returned.

XML source file:

<InterfaceData>
    <OBJECT_ACTION_ID>16283</OBJECT_ACTION_ID>
    <Employee>
        <Employee>
            <EmployeeBasic>
                <EmployeeNo>50064</EmployeeNo>
            </EmployeeBasic>
            <EmployeeBasic_DateMarriageCeased>
                <PersonDetailsRecords>
                    <PersonDetails>
                        <DateMarriageCeased/>
                    </PersonDetails>
                </PersonDetailsRecords>
            </EmployeeBasic_DateMarriageCeased>
            <EmployeeAddress>
                <AddressRecords>
                    <AddressDetails>
                        <Address1>Line1</Address1>
                        <Address2/>
                        <Address3>Line3</Address3>
                        <Address4>Line4</Address4>
                        <Postcode>Postcode</Postcode>
                    </AddressDetails>
                </AddressRecords>
            </EmployeeAddress>
        </Employee>
    </Employee>
</InterfaceData>

XSL stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template match="/">
        <xsl:for-each-group select="//InterfaceData" group-by="OBJECT_ACTION_ID">
            <!-- Employee -->
            <EmployeeAddress>
                <xsl:for-each   select="current-group()//AddressDetails">
                    <xsl:call-template  name="CGIderiveAddress">
                        <xsl:with-param name="myVarAddress1" select="current-group()//Address1/text()"/>
                        <xsl:with-param name="myVarAddress2" select="current-group()//Address2/text()"/>
                        <xsl:with-param name="myVarAddress3" select="current-group()//Address3/text()"/>
                        <xsl:with-param name="myVarAddress4" select="current-group()//Address4/text()"/>
                        <xsl:with-param name="myVarPostcode" select="current-group()//Postcode/text()"/>
                    </xsl:call-template>
                </xsl:for-each>
            </EmployeeAddress>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template name="CGIderiveAddress">
        <xsl:param name="myVarAddress1"/>
        <xsl:param name="myVarAddress2"/>
        <xsl:param name="myVarAddress3"/>
        <xsl:param name="myVarAddress4"/>
        <xsl:param name="myVarPostcode"/>
        <xsl:attribute name="Address1">
            <xsl:value-of select="$myVarAddress1"/>
        </xsl:attribute>
        <xsl:choose>
            <!-- Address Line 2 is empty and Adress Line 3 exists -->
            <xsl:when test="$myVarAddress2 = ''">
                <xsl:attribute name="EMPTYAddress2">
                    <xsl:value-of select="'EMPTYAddress2'"/>
                </xsl:attribute>
            </xsl:when>
            <xsl:otherwise>
                <xsl:attribute name="NotEMPTYAddress2">
                    <xsl:value-of select="'NotEMPTYAddress2'"/>
                </xsl:attribute>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

XSL Output:

<?xml version="1.0" encoding="UTF-8"?>
<EmployeeAddress Address1="Line1"
                 NotEMPTYAddress2="NotEMPTYAddress2"/>
3
  • 1
    Using current-group() when you don't have any for-each-group does not make sense at all. Commented Oct 2, 2017 at 11:12
  • 1
    I am afraid a for-each-group without any group-by or group-adjacent or group-starting-with/ending-with does not make sense either. If the grouping is not relevant than take the time to prepare a minimal but complete sample allowing us to reproduce the problem, with the input you have, the output you get and the result you want. Commented Oct 2, 2017 at 11:24
  • Also, you are doing for-each-group on AddressRecords which is the root element, and there will only ever be one of them. This is not something you would group on. Commented Oct 2, 2017 at 12:51

2 Answers 2

1

Using /text() is nearly always a mistake. In this case, if the Address2 element exists and has no children, then Address2/text() is an empty sequence (NOT a node with zero-length string value!); when you test an empty sequence for equality with anything, even a zero-length string, the result is always false.

I think the template CGIderiveAddress is expecting all its parameters to be strings, so it would be a good idea to declare it as such using as="xs:string" on the xsl:param element. If you had done that, you would get an error message saying that you are supplying an empty sequence where it isn't allowed. Error messages are always better than incorrect results, and a good way of achieving them is to declare the types of all your variables and (especially) parameters.

Then simply use <xsl:with-param select="current-group()//Address2"/>. Since the expected value is a string, the Address2 element will be atomized and turned into a string, which will be a zero-length string if the Address2 element is empty. If you also want a zero-length string when Address2 is absent, use string(current-group()//Address2).

Looking at the code more carefully, there's another glaring bug here:

<xsl:for-each select="current-group()//AddressDetails">
    <xsl:call-template  name="CGIderiveAddress">
      <xsl:with-param name="myVarAddress1" 
            select="current-group()//Address1/text()"/>

I feel sure that you actually want to pass the Address1 value for the AddressDetails that you are currently processing, not all the Address1 values for the current group of elements. That's simply

<xsl:with-param name="myVarAddress1" select="Address1"/>
Sign up to request clarification or add additional context in comments.

3 Comments

Brilliant, thanks for the explanation. So beneficial for a newbie like me!
I have tried setting the parameter type as suggested <xsl:param name="myVarAddress1" as="xs:string"/> however, I am receiving an error XPST0081: Namespace prefix 'xs' has not been declared
Then declare it, dear Murfy... You need xmlns:xs="http://www.w3.org/2001/XML/Schema" on the xsl:stylesheet element.
1

You are defining myVarAddress2 like so...

<xsl:with-param name="myVarAddress2" select="current-group()//Address2/text()"/>

But Address2 in your input XML sample does not contain any child text nodes, so the $myVarAddress2 parameter contains an empty sequence. An empty sequence is not the same an an empty string, and so the test $myVarAddress2 = '' is false.

Instead, as you are using XSLT 2.0, you could do this....

<xsl:when test="empty($myVarAddress2)">

Note that I can't see how grouping comes into your XSLT, not least because InterfaceData is the root element.

Also, for the XSLT shown in your question, you could simplify the parameters like so...

<xsl:with-param name="myVarAddress2" select="Address2/text()"/>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.