Formatting numbers, excluding trailing zeroes - formatting

first time SO user :)
I know that I can format a number like this:
format-number($value, '###,###.00')
But I would like to remove the dot and the zeroes if $value is zero.
So,
37368 -> 37,368
2.666667 -> 2.66
Is this possible using just number formatting (doesn't seem like it) or do I have to do something along the lines of
if (int(value) == value ) {...}

format-number($value, '###,###.##')

xpath 2.0 contains conditional logic if..then..else but in the more likely case that you're in xpath 1.0 I'm afraid you'll have to either rely on XSLT to do this for you, i.e:
<xsl:variable name="myvar">
<xsl:choose>
<xsl:when test="$value > 0">
<xsl:select="format-number($value, '###,###.00')"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>>
</xsl:variable>
..or mixin an extension (.NET can do this natively, EXSLT exists otherwise, probably more options available)
To the best of my knowledge no xpath functions exist to get you out of this, but I could be missing something exotic.

Related

XSLT error when getting variable [duplicate]

When using XSLT how do you test to see if a locally scoped variable exists, or is this even possible?
Considering the XSLT stylesheet as an XML DOM, a variable declaration element makes the variable visible to all following siblings and their descendants. This allows XSLT processors to statically analyze any XPath containing a variable reference to see if the variable exists; if the variable declaration exists on the preceding-sibling or ancestor axis, the variable reference is legal, otherwise it's not.
Note that this is entirely dependent on the structure of the XSLT, not the structure of the XML it's processing. The XSLT processor can and should produce an error if an XPath expression uses a variable that doesn't exist.
There's no way to check for this condition inside XSLT because this condition isn't legal within XSLT. The sitauation you described in your comment - "The idea is to set a flag variable if something is output and later on display a different message if nothing was output." - actually should result in a syntax error. For instance, if you do something like this:
<xsl:if test="some_condition">
<!-- produce output here -->
<xsl:variable name="flag">true</xsl:variable>
</xsl:if>
<!-- time passes -->
<xsl:if test="$flag='true'>
<!-- wouldn't it be nice? -->
</xsl:if>
you'll get a syntax error: the second xsl:if element is neither a following sibling of the variable declaration nor one of their descendants.
Here's a technique I use a fair amount - this produces variable output based on a variety of different conditions that you don't want to re-check later:
<xsl:variable name="output">
<xsl:if test="$condition1='true'">
<p>condition1 is true</p>
</xsl:if>
<xsl:if test="$condition2='true'">
<p>condition2 is true</p>
</xsl:if>
<xsl:if test="$condition3='true'">
<p>condition3 is true</p>
</xsl:if>
</xsl:variable>
<!-- we've produced the output, now let's actually *output* the output -->
<xsl:copy-of select="$output"/>
<!-- time passes -->
<xsl:if test="normalize-space($output) != ''">
<p>This only gets emitted if $output got set to some non-empty value.</p>
</xsl:if>
Asking this question indicates that you did not fully grasp the key point of XSLT. :-)
It's declarative: nothing can exist unless you declare it. You declare a variable, then it's there, you don't, then it's not.
Not once will there be the point where you have to wonder, while coding, if a certain variable exists.
XSLT has strict scoping rules, variables exist only within the scope of their parent element, (and not all elements can contain variables to begin with). Once you leave the parent element, the variable is gone.
So unless you specify your question/intent some more, the only valid answer is that the question is wrong. You cannot and do not need to check if a variable exists at run-time.
XSL variables are strictly scoped, so you can't access them in sibling nodes, only in children.
If you are dealing with params, you can use a global <xsl:param />.
See: http://www.stylusstudio.com/xsllist/199911/post30020.html
Best and fast idea to check value if it's exist is to check it length
<xsl:if test="string-length(value/to/check)=0">
</xsl:if>
I don't think it's possible, but you're not likely to ever need it, because the variable doesn't exist unless you've declared it.
If you have a variable, you can check it has something, or it "exists" by doing something like the following:
<xsl:choose>
<xsl:when test="$myvar">
This variable exists!
</xsl:when>
<xsl:otherwise>
The variable doesn't exist :(
</xsl:otherwise>
</xsl:choose>
As for its validity I cannot be certain. I will tell you however, that I do this in some of our systems at work ;)

Using concat with number values

The problem is I want to present two numbers that are stored as strings nicely in a file I generate.
The following code works just fine, but the formatting is not really the one I would like it to be:
<xsl:call-template name="create-cell">
<xsl:with-param name="value" select="concat($value_one,' or ',$value_two)" />
So I thought that I'll add a format-number function and give the numbers the format I want them to have. In order to do so I cast the string to number, use the function and then cast back to string, like this:
<xsl:call-template name="create-cell">
<xsl:with-param name="value" select="concat(string(format-number(number($value_one), "###,###.00"),' or ',$value_two)" />
But the transformation ends without results (an error occurs). What exactly am I doing wrong when changing the type?
EDIT:
The error that occurs is:
Element type "xsl:with-param" must be followed by either attribute specifications, ">" or "/>"
I guess the solution is to escape the double quotas with &quot ...
This part :
<xsl:with-param name="value" select="concat(string(format-number(number($value_one), "###,###.00"),' or ',$value_two)" />
should be written as:
<xsl:with-param name="value" select="concat(format-number($value_one, '#,###.00'), ' or ', $value_two)"/>
Whether that's a good approach to solve the actual problem (of which we know practically nothing) is another question.
But the transformation ends with result -
My guess is that $value_one is not a number. Perhaps it is formatted as 12,345.00? If the conversion to an xs:double fails, it will return NaN, which is a valid number, but not really. Using the format-number function, it should return NaN, regardless the picture string.
If your variable holds the empty sequence, format-number will return the empty sequence.
Since format-number already returns a string, using string() on the result will have no effect.
If the - in your question meant a literal minus-sign, then perhaps update your question with what your first snippet and second snippet return exactly, and what processor (exact version) you use.
Update (after you posted the error)
Your XSLT is not valid XML. All XSLT must be valid XML to begin with. Michael's answer shows where it goes wrong: an attribute value must be enclosed in quotes, and yours wasn't.

Variables in XSLT how to declare , assign value and use that variable in a different location in the same XSLT

Please consider my "A/B" xPath expression returns the following node
<Q ID="12345">
----
----
</Q>
This is my variable
This is how I’m trying to assign a value to my tempVariable variable
<xsl:for-each select="A/B">
<xsl:variable name="tempVariable"><xsl:value-of select="#ID"/></xsl:variable>
</xsl:for-each>
And after all I’m trying to use this variable
<xsl:if test="$tempVariable='12345'">
....
....
</xsl:if>
but here as I understand I’m getting $tempVariable ="" which is not correct.
Can someone please tell me where I’m doing wrong or how can I do this in proper way.
Thank you.
Why would a path like A/B select a Q element? If you want to use a variable you need to make sure it is in scope. The variable you show in your sample is in scope inside the xsl:for-each, after the xsl:variable element.
If you want to use the variable outside the for-each you would need to declare it outside the for-each.
However I think you can simply do
<xsl:variable name="v1" select="A/B/#ID"/>
<xsl:if test="$v1 = '12345'">..</xsl:if>
there is no need for the for-each.

Getting wrong answer from a comparison XSL

So this is fairly simple I think, it could be more involved then I understand though.
Anyways, at the moment I'll just include the code I believe to be relevant, if someone thinks that more would be relevant then I will try to include more.
I've got two statements:
<xsl:value-of select="$isOnlineColumnEmpty" />
<xsl:value-of select="not($isOnlineColumnEmpty = 'false')" />
The first one outputs false. However, the second one is outputting true, which is the opposite of what I expect.
In addition to this, These two statements get repeated multiple times, and I only get this result in one section. However, there is absolutely no code in between these two statements, so nothing could be changing the value of the variable.
Just wondering if there is something I could be overlooking?
Instead of:
<xsl:value-of select="not($isOnlineColumnEmpty = 'false')" />
use:
<xsl:value-of select="not($isOnlineColumnEmpty = false())" />
Explanation:
The boolean value false() is something different from the string "false".
When a boolean is compared to another value, the second value is converted to a boolean and then the comparisson is performed. To quote the XPath 1.0 W3C Specification:
"If at least one object to be compared is a boolean, then each object
to be compared is converted to a boolean as if by applying the boolean
function."
So, in this concrete case the string "false" is converted to boolean. By definition boolean($someString) is true() for any non-empty string.
Therefore, after the conversion the two boolean values false() and true() are compared and the result is false(). Because in the original expression this result is argument to the not() function, the final result is not(false()) , that is true().
Here is the chain of calculations:
not($isOnlineColumnEmpty = 'false') ==> not(false() = 'false') ==>
not(false() = boolean(false())) ==> not(false() = true()) ==>
not(false()) ==> true()
So, I figured this out later.
Changing the statement to:
<xsl:value-of select="$isOnlineColumnEmpty != false" />
Fixed the issue for me.

How to output ${expression} in Freemarker without it being interpreted?

I'm trying to use Freemarker in conjunction with jQuery Templates.
Both frameworks use dollar sign/curly brackets to identify expressions for substitution (or as they're called in freemarker, "interpolations") , e.g. ${person.name} .
So when I define a jQuery Template with expressions in that syntax, Freemarker tries to interpret them (and fails).
I've tried various combinations of escaping the ${ sequence to pass it through Freemarker to no avail - \${, \$\{, $\{, etc.
Inserting a freemarker comment in between the dollar and the curly (e.g. $<#-- -->{expression}) DOES work - but I'm looking for a more concise and elegant solution.
Is there a simpler way to get a Freemarker template to output the character sequence ${?
This should print ${person.name}:
${r"${person.name}"}
From the freemarker docs
A special kind of string literals is the raw string literals. In raw string literals, backslash and ${ have no special meaning, they are considered as plain characters. To indicate that a string literal is a raw string literal, you have to put an r directly before the opening quotation mark or apostrophe-quote
For longer sections without FreeMarker markup, use <#noparse>...</#noparse>.
Starting with FreeMarker 2.3.28, configure FreeMarker to use square bracket syntax ([=exp]) instead of brace syntax (${exp}) by setting the interpolation_syntax configuration option to square_bracket.
Note that unlike the tag syntax, the interpolation syntax cannot be specified inside the template. Changing the interpolation syntax requires calling the Java API:
Configuration cfg;
// ...
cfg.setInterpolationSyntax(SQUARE_BRACKET_INTERPOLATION_SYNTAX);
Then FreeMarker will consider ${exp} to be static text.
Do not confuse interpolation syntax with tag syntax, which also can have square_bracket value, but is independent of the interpolation syntax.
When using FreeMarker-based file PreProcessor (FMPP), either configure the setting via config.fmpp or on the command-line, such as:
fmpp --verbose --interpolation-syntax squareBracket ...
This will call the appropriate Java API prior to processing the file.
See also:
https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html
http://fmpp.sourceforge.net/settings.html#templateSyntax
Another option is to use #include with parse=false option. That is, put your jQuery Templates into the separate include page and use parse=false so that freemarker doesn't try and parse it.
This would be a good option when the templates are larger and contain double quotes.
I had to spent some time to figure out the following scenarios to escape ${expression} -
In Freemarker assignment:
<#assign var = r"${expression}">
In html attribute:
Some link
In Freemarker concatenation:
<#assign x = "something&"+r"${expression}"/>
If ${ is your only problem, then you could use the alternate syntax in the jQuery Templates plugin like this: {{= person.name}}
Maybe a little cleaner than escaping it.
Did you try $$?
I found from the Freemarker manual that ${r"${person.name}"} will print out ${person.name} without attempting to render it.
Perhaps you should also take a look at Freemarker escaping freemarker
I can confirm that the
${r"${item.id}"}
is the correct way as an example.
So I kinda full example will look like
<span> Remove </span>
and the output will be :
<span> Remove </span>
In the case when you want to use non-raw strings so that you can escape double quotes, apostrophes, etc, you can do the following:
Imagine that you want to use the string ${Hello}-"My friend's friend" inside of a string. You cannot do that with raw strings. What I have used that works is:
${"\x0024{Hello}-\"My friend's friend\""}
I have not escaped the apostrophe since I used double quotes.