0

I am trying to make something to act as a null check decimal fields for use in xslt transformations. I was thinking I could also make similar for other data types as I need. I made this

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wd="urn:com.workday.report/CR_Question"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:this="urn:this-stylesheet"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
    <xsl:function name="this:NullCheckField" as="xsd:string">
        <xsl:param name="node" as="xsd:string"/>
        <xsl:param name="fieldName" as="xsd:string"/>
        
        <xsl:variable name="variableName">
            <xsl:choose>
                <xsl:when test="not(exists(concat($node, '/', $fieldName)))">
                    <xsl:value-of select="format-number(0, '#.00')"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:variable name="x">
                        <xsl:value-of select="concat($node, '/', $fieldName)"/>
                    </xsl:variable>
                    
                    <xsl:variable name="y">
                        <xsl:value-of select="$x"/>
                    </xsl:variable>
                    <xsl:value-of select="format-number(number($y), '#.00')"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:value-of select="$variableName"/>
    </xsl:function> 
    
    <xsl:output method="text" indent="yes"/>
    
    <xsl:template match="wd:Report_Entry">
        
        <xsl:value-of select="this:NullCheckField('wd:Report_Data/wd:Report_Entry','wd:deduction_amount')"/>

        <xsl:text>&#xa;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

and i tried calling it with this line

<wd:Report_Data xmlns:wd="urn:com.workday.report/CR_Question">
    <wd:Report_Entry>
        <wd:Employee_ID>1555111</wd:Employee_ID>
        <wd:Check_Date>2022-04-28</wd:Check_Date>
        <wd:NegDeductIndc>0</wd:NegDeductIndc>
        <wd:Deduction_YTD>0</wd:Deduction_YTD>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Employee_ID>1555222</wd:Employee_ID>
        <wd:Check_Date>2022-04-28</wd:Check_Date>
        <wd:NegDeductIndc>0</wd:NegDeductIndc>
        <wd:Deduction_YTD>0</wd:Deduction_YTD>
    </wd:Report_Entry>
</wd:Report_Data>

When I run this, the test should fail and use the hard coded 0 since the node is not there, but instead of dropping into

<xsl:when test="not(exists(concat($node, '/', $fieldName)))">
    <xsl:value-of select="format-number(0, '#.00')"/>
</xsl:when>

It keeps dropping into the and failing out. I am not sure of two things. The first is why is my exist check not working correctly and falling into the Other question - am I able to pass the node names and concat them like this?

debugger cap

Edit: Updated function as of now

<!-- param type 1 = decimal -->
<!-- param type 2 = integer -->
<!-- param type 3 = string -->
<xsl:function name="this:NullCheckField" as="xsd:string">
    <xsl:param name="node"/>
    <xsl:param name="type" as="xsd:integer"/>
    
    <xsl:variable name="variableName">
        <xsl:choose>
            <xsl:when test="not(exists($node))">
                <xsl:choose>
                    <xsl:when test="$type = 1">
                        <xsl:value-of select="format-number(0, '#.00')"/>
                    </xsl:when>
                    <xsl:when test="$type = 2">
                        <xsl:value-of select="0"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="x">
                    <xsl:value-of select="$node[0]"/>
                </xsl:variable>
                
                <xsl:choose>
                    <xsl:when test="$type = 1">
                        <xsl:value-of select="format-number(number($x), '#.00')"/>
                    </xsl:when>
                    <xsl:when test="$type = 2">
                        <xsl:value-of select="number($x)"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$x"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="$variableName"/>
</xsl:function>

The problem I am trying to resolve is my integration will not always produce the empty nodes. Sometimes there is a missing node and I have been doing checks like this

    <xsl:choose>
        <xsl:when test="not(exists(wd:DPDEEYDEDS))">
            <xsl:value-of select="' '"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="wd:DPDEEYDEDS"/>
        </xsl:otherwise>
    </xsl:choose>

Some of these are decimal, some are integer, some are spaces. I'm trying to do a dynamic null check. The function will be called, the field node evaluated, if it is not a missing or empty node then it formats the value, otherwise return a default 0|0.00|' '.

1 Answer 1

2

Unless you want to move to XSLT with xsl:evaluate support the whole idea of passing in strings with XPath fragments is nonsense.

If, in the context of template match="wd:Report_Entry", you want to pass that Report_Entry element to a function use . e.g. this:my-function(., 'deduction_amount'). The first function argument should be of type node() or element(), certainly you don't want to atomize the node to a string.

Then you could check e.g. test="$node/*[local-name() = $fieldName]" to check for the existence of a child element with local name $fieldName.

I don't see any need to work with element names as as strings, you can simply pass in e.g. this:my-function(wd:deduction_amount), with the type of the paramter being node()? or node()* and then do any exists check on that, if needed.

The whole construction of nested, untyped variables is unnecessarily complicated and inefficient.

I don't even see the need for the function, doing e.g. format-number((wd:deduction_amount, 0)[1], '#.00') inside the template suffices.

Sign up to request clarification or add additional context in comments.

5 Comments

i changed a bit of my code. I am now passing the node as you suggested and the parameter for the function is <xsl:param name="node"/>. How do I select the value of the node? I do an exists($node) check, and if it does I try and get the value by doing <xsl:value-of select="$node" />, but I just keep selecting the node's name and not value. I've also tried setting the node-set.
I edited question to have my updated function now. Where I have "$node[0]" I was also trying to do node-set(). I keep getting either document fragments or elements but cant select their value.
Don't edit questions to present some different code after you got an answer. $node[0] is nonsense in XPath where the first item in a sequence has index 1 and not 0. Most of your attempts are rather erratic and convoluted, perhaps try a step back and read up on the basics of XPath 2.0. There are lots of resources, one free is cranesoftwrights.github.io/books/ptux/index.htm.
i still dont understand what the answer is, and i figured it better than posting the question again. it seems erratic, bc i am totally new to xslt - im net code and this foreign. ive been reading and all i can find are individuals specific examples and none of it makes sense. ive tried doing node-select(with diff stuff in here) and ive tried all sorts of indexing. im running around in circles trying to do what should be simple and built in. SQL has isnull(field, default), while .net doesnt have a one line, it's insane easy to go (something == null)? trueCondition : falseCondition.
i needed this, text(): <xsl:value-of select="$node/text()"/>

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.