I have the below condition that I have wriiten in xsl below..
as i have getting an value in xml of fpml:tradeId now it can be there in xml or it can not be there for example as shown below..
<fpml:tradeId tradeIdScheme=""></fpml:tradeId>
or it can contain value also
<fpml:tradeId tradeIdScheme="">10381159400</fpml:tradeId>
as advise i have change the implementation to but still not working ..
<xsl:if test = "fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId = ' '">
<xsl:value-of select="'null'" />
</xsl:if>
</ContractID>
so to deal with this problem i have come up with this below xsl , now the problem comes is that for the cases where tradeId is not there in xml it is not putting null string please advise is my below implementation of
xsl is correct
<xsl:if test = "fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId != ' '">
<xsl:choose>
<xsl:when test="contains(fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId,'-')">
<xsl:value-of select="substring-before(fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId,'-')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test = "fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId = ' '">
<xsl:value-of select="'null'" />
</xsl:if>
</ContractID>
as advise new implemetaion done but it is still not working..
<xsl:if test="normalize-space(fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId)">
<xsl:choose>
<xsl:when test="contains(fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId,'-')">
<xsl:value-of select="substring-before(fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId,'-')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test = "fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId = ' '">
<xsl:value-of select="'null'" />
</xsl:if>
</ContractID>
You're testing for
fpml:tradeId = ' '
which it doesn't in your example - the value of your fpml:tradeId is the empty string, not a string containing a space. Instead of comparing the value against ' ' for the first case you could use a test of
<xsl:if test="normalize-space(
fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId)">
In XPath a string coerces to a boolean by treating it as false if the string is empty and true if it isn't, so the test will pass if the tradeId value contains at least one non-whitespace character, and fail if it is completely empty or contains only whitespace.
For the second case
<xsl:if test="not(normalize-space(
fpml:dataDocument/*/*/fpml:partyTradeIdentifier[2]/fpml:tradeId))">
would give you the reverse test - true if the string is all whitespace or empty, false if it isn't (or just use a choose with an otherwise clause instead of two opposing if tests).
Related
I'm trying to determine if ../../coupon_code is null or empty. I've tried the methods in this thread Check if a string is null or empty in XSLT to no avail. Maybe I'm doing something wrong?
<!--Coupon Code Name and Code-->
<xsl:choose>
<xsl:when test="not(../../coupon_code)">
<xsl:if test="../../coupon_code != ''">
<xsl:value-of select="../../coupon_rule_name" /> <xsl:value-of select="../../coupon_code" /><xsl:value-of select="$sepend" />D.PROMOTION<xsl:value-of select="$sepend" />
</xsl:if>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
<!--End Coupon Code Name and Code-->
I'm doing
<xsl:when test="not(../../coupon_code)">
To determine if it's null. Then, I'm doing
<xsl:if test="../../coupon_code != ''">
To determine if it's empty.
However, I'm looking at data where this is clearly populated, and it's not entering the when/if to display the data at all. So it's failing somewhere and I don't know where.
Sometimes, ../../coupon_code will have a coupon code in it, like COUPON122. Sometimes it won't have anything in it.
You can check
<xsl:if test="normalize-space(../../coupon_code)">
<xsl:value-of select="../../coupon_rule_name" /> <xsl:value-of select="../../coupon_code" /><xsl:value-of select="$sepend" />D.PROMOTION<xsl:value-of select="$sepend" />
</xsl:if>
to have the xsl:value-ofs processed only if the ../../coupon_code element has some non-whitespace content.
In XSLT 2.0 I have a parameter than comes in as a delimited string of document names like:
ms609_0080.xml~ms609_0176.xml~ms609_0210.xml~ms609_0418.xml
I tokenize() this string and cycle through it with xsl:for-each to pass each document to a key. The results from the key I then assemble into a comma-delimited string to output to screen.
<xsl:variable name="list_of_corresp_events">
<xsl:variable name ="tokenparam" select="tokenize($paramCorrespdocs,'~')"/>
<xsl:for-each select="$tokenparam">
<xsl:choose>
<xsl:when test=".[position() != last()]">
<xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id, ', ')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
Everything works fine except that when I output the variable $list_of_corresp_events it looks like the following, with an unexpected trailing comma:
ms609-0080-2, ms609-0176-1, ms609-0210-1, ms609-0418-1,
Ordinarily the last comma should not appear based on test=".[position() != last()]" ? Possibly positions don't work for tokenized data? I didn't see a way to apply string-join() to this.
Many thanks.
Improving on the solution from #zx485, try
<xsl:for-each select="$tokenparam">
<xsl:if test="position()!=1">, </xsl:if>
<xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id"/>
</xsl:for-each>
Two things here:
(a) you don't need to repeat the same code in both conditional branches
(b) it's more efficient to output the comma separator before every item except the first, rather than after every item except the last. That's because evaluating last() involves an expensive look-ahead.
Change
<xsl:when test=".[position() != last()]">
to
<xsl:when test="position() != last()">
Then it should all work as desired.
It seems you can simplify this to
<xsl:variable name="list_of_corresp_events">
<xsl:value-of select="for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/#xml:id" separator=", "/>
</xsl:variable>
or with string-join
<xsl:variable name="list_of_corresp_events" select="string-join(for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/#xml:id, ', ')"/>
I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().
If xsl were a procedural language where variables could be reassigned, I'd use something like this:
<xsl:variable name="copyAttrib" select="true()">
<xsl:for-each select="tokenize($ignoreAttributes,',')">
<xsl:if test="compare(., name()) != 0">
<xsl:variable name="copyAttrib" select="false()"/>
</xsl:if>
</xsl:for-each>
Unfortunately, I can't do that, because xsl is functional (so says this other answer). So variables can only be assigned once.
I think the solution would look something like:
<vsl:variable name="copyAttrib">
<xsl:choose>
<xsl:when>
<xsl:for-each select="tokenize($ignoreAttributes, ',')">
<xsl:if test="compare(., name()) != 0"/>
</xsl:for-each>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Obviously not exactly that (otherwise I wouldn't be asking.)
I know that I could bypass the tokenize and for-each loop by just using replaces on ignoreAttributes and changing all the , to | and then using matches, but I'd like to avoid that if possible because then I need to deal with the possibility that ignoreAttributes (which the user provides) might contain some special characters that will change the regex pattern and escape them all.
I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().
That sounds to me like
<xsl:variable name="copyAttrib" as="xs:boolean"
select="tokenize($parameterignoreAttributes, ',') = name()"/>
You say:
Unfortunately, I can't do that, because xsl is functional
when what you mean is: "Fortunately, I don't need to do that, because XSLT is functional".
An XSLT-1.0 way of doing this is by using a recursive, named template:
<xsl:template name="copyAttrib">
<xsl:param name="attribs" />
<xsl:choose>
<xsl:when test="normalize-space(substring-before($attribs,',')) = normalize-space(name(.))">
<xsl:value-of select="'true'" />
</xsl:when>
<xsl:when test="normalize-space($attribs) = ''">
<xsl:value-of select="'false'" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="copyAttrib">
<xsl:with-param name="attribs" select="substring-after($attribs,',')" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Apply this template onto the current, the selected, node and wrap it in a <xsl:variable>:
<xsl:variable name="copyAttribResult">
<xsl:call-template name="copyAttrib">
<xsl:with-param name="attribs" select="'a,b,c,...commaSeparatedValues...'" />
</xsl:call-template>
</xsl:variable>
to get either true or false as a result.
I have the below xsl tag in which i am fetching out the values of fpml:periodMultiplier and fpml:period as shown below ...
tags in xml are :-
<fpml:periodMultiplier>1</fpml:periodMultiplier>
<fpml:period>Y</fpml:period>
extracting in xsl as shown below
<Payindextenor>
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:periodMultiplier" />
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:period" />
</Payindextenor>
so the value of Payindextenor is 1Y
now i want to put the null check in this tag since it may happen that in coming xml there can be no value for fpml:periodMultiplier and fpml:period also.
so i have come up with below xsl implementation in which i have tried that if any of the value is null then it should print null pls advise is it correct one :-
<xsl:choose>
<xsl:when test="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:periodMultiplier
!= ' '
and
../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:period
!= ' '">
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:periodMultiplier" />
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:period" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'null'" />
</xsl:otherwise>
</xsl:choose>
This is exactly the same situation as in your previous question - you're comparing against the (non-empty) string ' ' containing a single space, when what you actually want is to check for empty strings. And you can use the same solution as I suggested for that question, and test using normalize-space (which treats empty strings and strings containing only whitespace as "false" and anything else as "true"):
<xsl:choose>
<xsl:when test="normalize-space(../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:periodMultiplier)
and
normalize-space(../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:period)">
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:periodMultiplier" />
<xsl:value-of select="../fpml:calculationPeriodDates
/fpml:calculationPeriodFrequency
/fpml:period" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'null'" />
</xsl:otherwise>
</xsl:choose>
This will handle cases both where fpml:periodMultiplier or fpml:period elements are absent, and where they're present but empty.
As Ian Roberts has said, comparing a node to a single space is very different from checking for "null", but assuming you want to display "null" when both periodMultiplier and period are blank, you can do this:
<xsl:variable name="freq"
select="../fpml:calculationPeriodDates/fpml:calculationPeriodFrequency" />
<xsl:choose>
<xsl:when test="$freq/fpml:periodMultiplier != '' or
$freq/fpml:period != ''">
<xsl:value-of select="$freq/fpml:periodMultiplier" />
<xsl:value-of select="$freq/fpml:period" />
</xsl:when>
<xsl:otherwise>
<xsl:text>null</xsl:text>
</xsl:otherwise>
</xsl:choose>
I know the following xslt will work:
<xsl:attribute name="test">
<xsl:value-of select="substring(title, 1, 4000)"/>
</xsl:attribute>
But not sure what to do if there is something like the following and you want the substring over the whole attribute value not just the title or the substitle.
<xsl:attribute name="test">
<xsl:value-of select="title"/>
<xsl:if test="../../sub_title != ''">
<xsl:text> </xsl:text>
<xsl:value-of select="../sub_title"/>
</xsl:if>
</xsl:attribute>
Is it even possible to apply a substring function over multiple lines that define an attribute?
I think what you are saying is that you want to build up a long string, consisting of the values of a number of other elements, and then truncate the result.
What you could do, is use the concat function to build the attribute value, and then do a substring on that.
<xsl:attribute name="test">
<xsl:value-of select="substring(concat(title, ' ', ../sub_title), 1, 4000)" />
</xsl:attribute>
In this case, if sub_title was empty, you would end up with a space at the end of the test attribute, so you might want to add a normalize-space to this expression
<xsl:value-of select="normalize-space(substring(concat(title, ' ', ../sub_title), 1, 4000))" />
An alternate approach, if you did want to use a more complicated expression, is to do the string calculation in a variable first
<xsl:variable name="test">
<xsl:value-of select="title"/>
<xsl:if test="../../sub_title != ''">
<xsl:text> </xsl:text>
<xsl:value-of select="../sub_title"/>
</xsl:if>
</xsl:variable>
<xsl:attribute name="test">
<xsl:value-of select="substring($test, 1, 4000)" />
</xsl:attribute>
As an aside, you can simplify your code by using "Attribute Value Templates" here, instead of using the more verbose xsl:attribute command. Simply do this..
<myElement test="{substring($test, 1, 4000)}">
Here, the curly braces indicate an expression to be evaluated, rather than output literally.