How to change all decimal value to zeroes in XSL
Example value:
from : 9876.123
to : 9876.000
Well,
floor(9876.123)
returns:
9876
and:
format-number(floor(9876.123), '#.000')
returns:
9876.000
I don't see why this would be useful, but in case you do want to preserve the number of decimal places, I would use:
format-number(floor($amount), translate($amount, '123456789', '000000000'))
In case the number of digits after the decimal point is unknown in advance, use:
concat(substring-before(., '.'),
'.',
translate(substring-after(., '.'), '123456789', '000000000'))
Here is a complete XSLT transformation example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="d">
<xsl:value-of select=
"concat(substring-before(., '.'),
'.',
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
Update
Someone requested that integer values (not containing decimal point) are also processed correctly (copied intact).
I also added to this that negative values and / or currency denominations should also be processed correctly.
Although this falls outside the scope of the current problem, here is again a single XPath 1.0 expression that produces the wanted result:
concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))
And here again is the complete transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="d">
<xsl:value-of select=
"concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>-$1.234</d>
<d>-1.234</d>
<d>-.234</d>
<d>9876</d>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
-$1.000
-1.000
-.000
9876
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
Related
I have an XML which has Decimal field which need to formatted to European Currency format.
The Current its having US format.
-<Envelope>
-<Body>
-<getPriceRecommendationResponse>
-<status>
<statusCode>Success</statusCode>
</status>
-<priceRecommendation>
<tssArticleNumber>Item Number1234</tssArticleNumber>
<compoundCode>N123</compoundCode>
<compoundGroupCodeBucket>A</compoundGroupCodeBucket>
<compoundCodeBucket>N123 & others</compoundCodeBucket>
<qualityIndexCode>-</qualityIndexCode>
<qualityIndexBucket>Std Quality</qualityIndexBucket>
<weight>66.0341</weight>
<weightGroupBucket>BT 123.1234 and 12345.1234</weightGroupBucket>
<weightIsValidBucket>YES</weightIsValidBucket>
<subGroupCode>PT</subGroupCode>
<subGroupCodeBucket>7:B03</subGroupCodeBucket>
<stockDistinction>MTS</stockDistinction>
<productIdBucket>PT0401450-T46N</productIdBucket>
<referencePrice>42.076</referencePrice>
<averageQuantity>9</averageQuantity>
<quantityAdjustments>0.96</quantityAdjustments>
<highDV>2.123789</highDV>
<averageDV>1.25141</averageDV>
<lowDV>0.79983</lowDV>
<additionalAdjustmentsTotal>1</additionalAdjustmentsTotal>
<highPrice>19876.9124796544</highPrice>
<averagePrice>12345.5481540736</averagePrice>
<lowPrice>123344567.3075011968</lowPrice>
</priceRecommendation>
</getPriceRecommendationResponse>
</Body>
</Envelope>
Please help me with an xslt which can format all the Decimal Nodes in the XML.
The below is an xslt i am already using. I am expecting a similar one. Thanks
//this has been taken from a Microsoft knowledgebase aricle and strips out the
//namespaces from an XML message using a style sheet
XslTransform := XslTransform.XslTransform;
XMLStyleSheet := XMLStyleSheet.XmlDocument;
XMLStyleSheet.InnerXml(
'<?xml version="1.0" encoding="UTF-8"?>'+
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxml="urn:schemas-microsoft-com:xslt">'+
'<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="UTF-8" indent="yes"/>' +
'<xsl:template match="#*|node()">'+
'<xsl:copy>'+
'<xsl:apply-templates select="#*|node()"/>'+
'</xsl:copy>'+
'</xsl:template>'+
'<xsl:template match="'+OldNode+'">'+
'<xsl:variable name="oldNode" select="'+OldNode+'"/>' +
'<xsl:variable name="newNodeXml">' +
'<xsl:element name="'+NewNode+'">' +
'<xsl:copy-of select="$oldNode/#*|node()"/>' +
'<xsl:copy-of select="$oldNode/child::*"/>' +
'<xsl:copy-of select="$oldNode/#*"/>' +
'</xsl:element>' +
'</xsl:variable>' +
'<xsl:copy-of select="msxml:node-set($newNodeXml)"/>' +
'</xsl:template>' +
'</xsl:stylesheet>'
);
XslTransform.Load(XMLStyleSheet);
writer := writer.StringWriter();
XslTransform.Transform(Source, nullXsltArgumentList, writer);
Destination := Destination.XmlDocument;
Destination.InnerXml(writer.ToString());
Thank you guys for your response. I hope i can make the things more clear to you. The European format is "," for Decimal separator and "." for Digit Grouping. Whereas US have the reverse. For example 1,000.156 in US and 1.000,156 for Europe. Yes Rnet i have tried the decimal-format its working fine, but the problem here is i need to use it multiple times for the Fields. I want an XSLT which change the format for all the decimal fields at once. I hope you got my point
Thank you Michael, I have tried your code but getting an error.
A call to System.Xml.Xsl.XslTransform.Load failed with this message: Expression must evaluate to a node-set.
I have changed the code little bit given by Michael, but still getting the same error.
'<?xml-stylesheet type="text/xsl" href="decimalformat.xsl"?>'+
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">'+
'<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>'+
'<xsl:strip-space elements="*"/>'+
'<xsl:decimal-format name="eu" decimal-separator="," grouping-separator="." />'+
'<!-- identity transform -->'+
'<xsl:template match="#*|node()">'+
' <xsl:copy>'+
' <xsl:apply-templates select="#*|node()"/>'+
' </xsl:copy>'+
'</xsl:template>'+
'<xsl:template match="*[number()=number()]">'+
' <xsl:copy>'+
' <xsl:value-of select=translate("format-number(., '#.##0,##########', 'eu'), ',', '.')" />'+
' </xsl:copy>'+
'</xsl:template>'+
'</xsl:stylesheet>'
In my application its not working. I have found a similar post here http://mikeschinkel.com/blog/gettingpastthexslterrorexpressionmustevaluatetoanodeset/#comment-484235
<xsl:value-of select="format-number(., '#.##0,##########', 'eu')" />
I am getting the error if i include the above code. i have tried it this way as well.
<xsl:value-of select=translate("format-number(., '#.##0,##########', 'eu'), ',', '.')" />
the problem here is i need to use it multiple times for the Fields. I
want an XSLT which change the format for all the decimal fields at
once.
This could be accomplished by a template that matches only elements containing strictly numeric values, for example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:decimal-format name="eu" decimal-separator=',' grouping-separator='.' />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[number()=number()]">
<xsl:copy>
<xsl:value-of select="format-number(., '#.##0,##########', 'eu')" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note:
This will not work with your input, because it contains an unescaped ampersand character;
This will not process elements that contain numbers as part of a string, e.g:
<weightGroupBucket>BT 123.1234 and 12345.1234</weightGroupBucket>
This has nothing to do with currency.
I am using XSLT to create XML file. A Date-time has milliseconds. I need to have the output XML without milliseconds.
Format needs to be YYYY-MM-DDTHH:MM:SS
For example:
XML shows date as: 2012-12-341T09:26:53.132-0500
But this needs to be: 2012-12-341T09:26:53
If all of the values are dateTime and have a ., you could use substring-before():
substring-before('2012-12-341T09:26:53.132-0500', '.')
Of you could use substring() to select the first 20 characters:
substring('2012-12-341T09:26:53.132-0500', 0, 21)
If you are using XSLT2, see this function: http://www.w3.org/TR/xslt20/#function-format-dateTime. This picture string should give you what you want:
format-dateTime($dateTime,'[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')
This XPath expression produces the wanted result regardless whether the string contains a dot or a hyphen or both dot and hyphen, or none, and doesn't rely on the number of digits used for year, month, day:
substring-before(concat(substring-before(concat(substring-after(.,'T'),
'.'),
'.'),
'-'),
'-')
Here is a simple XSLT transformation that uses this XPath expression:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dt/text()">
<xsl:value-of select="substring-before(., 'T')"/>
<xsl:text>T</xsl:text>
<xsl:value-of select=
"substring-before(concat(substring-before(concat(substring-after(.,'T'),
'.'),
'.'),
'-'),
'-')
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on this test XML document:
<t>
<dt>2012-12-341T09:26:53.132-0500</dt>
<dt>2012-12-355T09:34:56</dt>
<dt>2012-12-355T09:34:56-0500</dt>
<dt>2012-12-13T9:34:5-0500</dt>
<dt>2012-12-344T09:12:34.378-0500</dt>
</t>
the wanted, correct result is produced:
<t>
<dt>2012-12-341T09:26:53</dt>
<dt>2012-12-355T09:34:56</dt>
<dt>2012-12-355T09:34:56</dt>
<dt>2012-12-13T9:34:5</dt>
<dt>2012-12-344T09:12:34</dt>
</t>
Explanation:
Proper application of sentinels.
Given a node, eg.
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="SP" elem8="MC" elem9="DS" elem10="DA" elem11="16"/>
I need my output to be "DA" if any attribute is "DA", or the value of the next attribute if any attribute is "BA" (i.e. if elem7="BA elem8="03" I want "03" output)
There is no danger of multiple matches, so if an attribute is "BA", there will be no "DA" attribute, but the values could occur in any element
I've looked into the attribute:: tag, but I'm not sure if this will fulfil my needs.
any help greatly appreciated
I made an assumption that your attributes has names in form of elemN where N = 1,2,3...,
and they are ordered accordingly.
The following XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="text" />
<xsl:template match="/SI">
<xsl:choose>
<xsl:when test="some $i in #* satisfies $i='DA'">
<xsl:text>DA</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="attr" select="concat('elem', xs:decimal(substring-after(#*[.='BA']/name(), 'elem')) + 1)" />
<xsl:value-of select="#*[name() = $attr]" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
applied to the following input XML:
<?xml version="1.0" encoding="UTF-8"?>
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="SP" elem8="MC" elem9="DS" elem10="DA" elem11="16" />
gives DA as the output.
And applied to the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="BA" elem8="03" elem9="DS" elem10="DAs" elem11="16" />
gives 03 as the output.
EDIT
Here's the XSLT 1.0 version (tested under Altova XMLSpy):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-templates select="SI/#*" />
</xsl:template>
<xsl:template match="#*">
<xsl:choose>
<xsl:when test=". = 'DA'">
<xsl:text>DA</xsl:text>
</xsl:when>
<xsl:when test=".='BA'">
<xsl:variable name="attr" select="concat('elem', substring-after(name(), 'elem') + 1)" />
<xsl:value-of select="/SI/#*[name() = $attr]" />
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I need my output to be "DA" if any attribute is "DA", or the value of
the next attribute if any attribute is "BA" (i.e. if elem7="BA
elem8="03" I want "03" output)
There is no danger of multiple matches, so if an attribute is "BA",
there will be no "DA" attribute, but the values could occur in any
element
This single XPath expression produces the wanted value:
string(/*/#*[. = 'DA']
|
/*/#*[name()
=
concat('elem', substring-after(name(/*/#*[.='BA']), 'elem') +1)]
)
And here is the complete transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:copy-of select=
"string(/*/#*[. = 'DA']
|
/*/#*[name()
=
concat('elem', substring-after(name(/*/#*[.='BA']), 'elem') +1)]
)"/>
</xsl:template>
</xsl:stylesheet>
As can be seen this transformation simply evaluates the XPath expression and copies the result of the evaluation to the output.
When the transformation is applied on this XML document (your 2nd case):
<SI elem1="TI"
elem2="FN"
elem3="4099450222"
elem4="TM"
elem5="4094110000"
elem6="MT"
elem7="BA"
elem8="03"
elem9="DS"
elem10="DD"
elem11="16"/>
the result is:
03
When the same transformation is applied on the originally provided XML document (your 1st case):
<SI elem1="TI"
elem2="FN"
elem3="4099450222"
elem4="TM"
elem5="4094110000"
elem6="MT"
elem7="SP"
elem8="MC"
elem9="DS"
elem10="DA"
elem11="16"/>
again the wanted, correct result is produced:
DA
Explanation:
Proper use of the XPath union operator |, and the functions string(), substring-after(), name() and `concat().
I have an xsl stylesheet giving just about what is needed, except there are values outputted outside the tags, . Is there a way to remove them? The scenario is that the desired output is a total invoice amount for invoices that appear more than once. Each time the xslt is executed the parameter p1 contains the InvoiceNumber to total. The code below shows that parameter, p1, hardcoded to '351510'.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Invoices/Invoice[InvoiceNumber=351510][1]/InvoiceNumber">
<xsl:copy>
<xsl:apply-templates select="/Invoices/Invoice[InvoiceNumber=351510][1]/InvoiceAmount"/>
</xsl:copy>
</xsl:template>
<xsl:param name="tempvar"/>
<xsl:template name="InvTotal" match="/Invoices/Invoice[InvoiceNumber=351510][1]/InvoiceNumber">
<xsl:variable name="p1" select="351510" />
<xsl:if test="/Invoices/Invoice/InvoiceNumber[. = $p1]">
<!--<xsl:if test="$test = $p1" >-->
<InvoiceAmount>
<xsl:value-of select="sum(../../Invoice[InvoiceNumber=351510]/InvoiceAmount)"/>
</InvoiceAmount>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Here is the input:
<Invoices>
- <Invoice>
<InvoiceNumber>351510</InvoiceNumber>
<InvoiceAmount>137.00</InvoiceAmount>
</Invoice>
- <Invoice>
<InvoiceNumber>351510</InvoiceNumber>
<InvoiceAmount>363.00</InvoiceAmount>
</Invoice>
- <Invoice>
<InvoiceNumber>351511</InvoiceNumber>
<InvoiceAmount>239.50</InvoiceAmount>
</Invoice>
</Invoices>
Here is the output:
<InvoiceAmount>500</InvoiceAmount>137.00351510363.00351511239.50
Here is desired output:
<InvoiceAmount>500</InvoiceAmount>
Also, thank you goes to lwburk who got me this far.
Adding
<xsl:template match="text()"/>
should help.
I do not get the same results as you posted (only 351510137.00351510363.00351511239.50, all the text nodes), and I do not know the purpose of tempvar (unused).
Since it appears that all you need is the sum of InvoiceAmount values for a specific InvoiceNumber, just keep it simple and ignore everything else:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="invoiceNumber"/>
<xsl:template match="/">
<InvoiceAmount>
<xsl:value-of select="sum(/Invoices/Invoice[InvoiceNumber=$invoiceNumber]/InvoiceAmount)"/>
</InvoiceAmount>
</xsl:template>
</xsl:stylesheet>
You can pass the InvoiceNumber to process via the parameter invoiceNumber, or you can hardcode it if you like (see version 1).
Note: should you prefer a number format like e.g. #.00 (fixed decimals) for the sum, then you can also use the format-number(…) function.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNum" select="351510"/>
<xsl:key name="kInvAmmtByNumber" match="InvoiceAmount"
use="../InvoiceNumber"/>
<xsl:variable name="vInvoiceAmounts" select=
"key('kInvAmmtByNumber', $pNum)"/>
<xsl:variable name="vIdInvAmount1" select=
"generate-id($vInvoiceAmounts[1])"/>
<xsl:template match="InvoiceAmount">
<xsl:if test="generate-id() = $vIdInvAmount1">
<InvoiceAmount>
<xsl:value-of select="sum($vInvoiceAmounts)"/>
</InvoiceAmount>
</xsl:if>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided XML file:
<Invoices>
<Invoice>
<InvoiceNumber>351510</InvoiceNumber>
<InvoiceAmount>137.50</InvoiceAmount>
</Invoice>
<Invoice>
<InvoiceNumber>351510</InvoiceNumber>
<InvoiceAmount>362.50</InvoiceAmount>
</Invoice>
<Invoice>
<InvoiceNumber>351511</InvoiceNumber>
<InvoiceAmount>239.50</InvoiceAmount>
</Invoice>
</Invoices>
produces exactly the wanted, correct result:
<InvoiceAmount>500</InvoiceAmount>
Explanation:
The wanted invoice number is passed to the transformation as the value of the external/global parameter $pNum .
We use a key that indexes all InvoiceAmount elements by their corresponding InvoiceNumber values.
Using that key we define the variable $vInvoiceAmounts that contains the node-set of all InvoiceAmount elements the value of whose corresponding InvoiceNumber element is the same as the value of the external parameter $pNum.
We also define a variable ($vIdInvAmount1) that contains a unique Id of the first such InvoiceAmount element.
There is a template that matches any InvoiceAmount element. It checks if the matched element is the first of the elements contained in the node-set $vInvoiceAmounts. If so, a InvoiceAmount element is generated with a single text-node child, whose value is the sum of all InvoiceAmount elements contained in $vInvoiceAmounts. Otherwise nothing is done.
Finally, there is a second template that matches any text node and does nothing (deletes it in the output), effectively overriding the unwanted side effect of the default XSLT processing -- the outputting of unwanted text.
In XSL is function like CONTAIN, that if i have number with simbol like "123112'+:" then doesn't take it.
to be more precise:
<Number>111111</Number>
<Number>123123+</Number>
<Number>222222</Number>
<Number>222222+</Number>
answer:
111111
222222
I'm stuck with xslt 1.0 version
Another approach, exploiting number to boolean conversion.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:apply-templates select="Number[boolean(number()) or . = 0]"/>
</xsl:template>
<xsl:template match="Number">
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
With input:
<Numbers>
<Number>111111</Number>
<Number>123123+</Number>
<Number>222222</Number>
<Number>222222+</Number>
</Numbers>
Correct result:
111111
222222
Quoting the spec:
The boolean function converts its
argument to a boolean as follows: a
number is true if and only if it is
neither positive or negative zero nor
NaN
Use the following XPath to select all the nodes that contains numbers. It will skip the ones with a plus sign in them.
Number[number(.)=number(.)]
Should work with XSLT 1.0
Yet another solution :)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Number[not(.*.+1)]"/>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<t>
<Number>111111</Number>
<Number>123123+</Number>
<Number>222222</Number>
<Number>222222+</Number>
</t>
the wanted, correct result is produced:
<t>
<Number>111111</Number>
<Number>222222</Number>
</t>
Explanation: All Number elements for wich the expression:
not(.*.+1)
is true() are filtered out by the simple template rule:
<xsl:template match="Number[not(.*.+1)]"/>
This is possible only if the string value of the Number element cannot be converted to a number. In this case .*.+1 evaluates to NaN and boolean(NaN) is false() by definition.
If the string value of the Number element can be converted to a number $num, then the above expression is equivalent to:
not($num*$num+1)
and $num*$num+1 >= 1 for any number $num, so, boolean(.*.+1) in this case is always true().