I have the following XSL:
<xsl:variable name="PriorityCall">
<xsl:choose>
<xsl:when test="$PriorityFlag = 1 or $PriorityFlag = 2 or $PriorityFlag =3">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
and I want to pass the value of PriorityCall into a .Net Extension Object as follows:
<xsl:value-of select="UCInterface:InsertNewGroup($UserRef, $SiteCode, $PriorityCall)" />
Signature of the .Net method:
public string InsertNewGroup(string userRef, string siteCode, bool prioritySite)
the value in .Net is always true. However I can pass false if I call the extension method like this:
<xsl:value-of select="UCInterface:InsertNewGroup($UserRef, $SiteCode, false())" />
How can I pass a bool value by getting the value out of $PriorityCall?
Define the variable as <xsl:variable name="PriorityCall" select="$PriorityFlag = 1 or $PriorityFlag = 2 or $PriorityFlag =3"/>.
With your current setup your variable is (in XSLT 1.0) of type result tree fragment, a result tree fragment which contains a single, non empty text node which happens to contain the representation of a boolean value. But that will always be converted to true. If you simply use the select attribute with a boolean XPath expression, as shown above, then the value is of type boolean.
Related
I have problem with my code in XSLT with if. I am using key function and there I find out if something is in the key or not.
<xsl:key name="hlp" match="help" use="#id" />
...
<xsl:if test="key('hlp', #some_id) !=''">
...
</xsl:if>
That is correct it gives me what I want but how I can make opposite condition that #some_id isn´t in key hlp... I mean:
<xsl:if test="key('hlp', #some_id) <!--is equal--> ''">
...
</xsl:if>
Is there something like that in XSLT/XPath?
When you call key('x', 'y'), the result is the set of nodes in which the key is equal to 'y'. You can test whether a node-set is empty using the empty() function (in XSLT 2.0) or the not() function in XSLT 1.0:
<xsl:if test="not(key('x', 'y'))" version="1.0">...</xsl:if>
<xsl:if test="empty(key('x', 'y'))" version="2.0">...</xsl:if>
or for the inverse test (to test if something was found):
<xsl:if test="key('x', 'y')" version="1.0">...</xsl:if>
<xsl:if test="exists(key('x', 'y'))" version="2.0">...</xsl:if>
Testing by comparing the result against a string is wrong. The tests key('x','y')='' and key('x','y')!='' will both return false if the result of the key() function is an empty node-set; conversely, if the key() function selects two nodes, one with content and the other without, then both tests will return true.
<xsl:key name="hlp" match="help" use="#id" />
...
<xsl:if test="key('hlp', #some_id) !=''">
...
</xsl:if>
As already pointed by Michael Kay, avoid using the != operator unless truly knowing what it does.
This aside (and the fact that the key() function returns a node-set), it is more in the spirit of XSLT to write the above as:
<xsl:apply-templates select="key('hlp', #some_id)"/>
but how I can make opposite condition that #some_id isn´t in key
hlp... I mean:
<xsl:if test="key('hlp', #some_id) <!--is equal--> ''">
...
</xsl:if> ```
Is there something like that in XSLT/XPath?
Again, in the spirit of XSLT I recommend using code like this:
<xsl:apply-templates select="/*[not(key('hlp', #some_id))]" mode="not-found"/>
In the select expression above one can substitute /* with any existing node in the document -- if this really matters.
I have an XML with top-level elements in this vein:
<chapter template="one"/>
<chapter template="two"/>
<chapter template="one"/>
<chapter template="one"/>
<chapter template="two"/>
<chapter template="one"/>
I'm processing these elements by looping through them with a choose statement:
<xsl:variable name="layout" select="#template"/>
<xsl:choose>
<xsl:when test="contains($layout, 'one')">
<xsl:call-template name="processChapterOne"/>
</xsl:when>
<xsl:when test="contains($layout, 'two')">
<xsl:call-template name="processChaptertwo"/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
This works correctly. But now I'm trying to do some conditional processing, so I'm trying to find the first chapter in the list:
<xsl:when test="count(preceding-sibling::*[($layout = 'one')]) = '0'">
<xsl:call-template name="processChapterOne"/>
</xsl:when>
Here's when things get weird. My test never becomes true: the value of count(...) is 4 for the first chapter in the list, and increments from there. It looks like it counts all of the top-level elements, and not just the ones named 'chapter'.
When I change the code to this:
<xsl:when test="count(preceding-sibling::*[(#template = 'one')]) = '0'">
<xsl:call-template name="processChapterOne"/>
</xsl:when>
it works correctly. So I've replaced a variable with a direct reference. I can't figure out why this would make a difference. What could cause this?
The not working and working cases are actually very different:
Not working: In preceding-sibling::*[$layout = 'one'], $layout is always the same value of one as it was when originally set in the <xsl:variable name="layout" select="#template"/> statement.
Working: In preceding-sibling::*[#template = 'one'], #template varies per the #template attribute value of the varying preceding-sibling context nodes.
*[(#template = 'one')]
Above means: count all nodes where attribute template equals the text one.
*[($layout = 'one')]
Above means: count all nodes where variable layout equals the text one.
I think with the question you raised $layout is not filled with the text one, but it does a xsl:call-template. Maybe something is going wrong here?
Besides that if you don't want to count all nodes but only the chapter nodes. Do this:
chapter[($layout = 'one')]
chapter[(#template = 'one')]
Is there any way to put more then one value in the right part of equation?
<xsl:choose>
<xsl:when test="Properties/LabeledProperty[Label='Category Code']/Value = 600,605,610">
This code above returns:
XPath error : Invalid expression
Properties/LabeledProperty[Label='Category Code']/Value = 600,605,610
^
compilation error: file adsml2adpay.xsl line 107 element when
The reason I don't want to use 'OR' is because there are around 20 numbers should be in the right part for each 'when' test.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:config="http://tempuri.org/config"
exclude-result-prefixes="config"
>
<config:categories>
<value>600</value>
<value>605</value>
<value>610</value>
</config:categories>
<xsl:variable
name = "vCategories"
select = "document('')/*/config:categories/value"
/>
<xsl:key
name = "kPropertyByLabel"
match = "Properties/LabeledProperty/Value"
use = "../Label"
/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="key('kPropertyByLabel', 'Category Code') = $vCategories">
<!-- ... -->
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This works because the XPath = operator compares every node from the left hand side to every node on the right hand side when working on node sets (comparable to an SQL INNER JOIN).
Hence all you need to do is create a node set from your individual values. Using a temporary namespace you can do that right in your XSLT file.
Also note that I've introduced an <xsl:key> to make selecting property values by their label more efficient.
EDIT: You could also create an external config.xml file and do this:
<xsl:variable name="vConfig" select="document('config.xml')" />
<!-- ... -->
<xsl:when test="key('kPropertyByLabel', 'Category Code') = $vConfig/categories/value">
With XSLT 2.0 the concept of sequences has been added. It's simpler to do the same thing there:
<xsl:when test="key('kPropertyByLabel', 'Category Code') = tokenize('600,605,610', ',')">
This means you could easily pass in the string '600,605,610' as an external parameter.
<xsl:variable name="a">20</xsl:variable>
<xsl:variable name="b">10</xsl:variable>
<xsl:if test="($a) > ($b)">
------
</xsl:if>
I getting error in the if condion..
Try the following :
<xsl:if test="$a > $b">
Try using the character entities for > (>) and < (<) operators in expressions, otherwise some parsers think you are closing the tag early, or opening another.
The example you posted should work. However, you should not that in your case both variables are of type string which could give surprising results where their length differs. The behaviour of the comparison operator on different datatypes is specified in the xpath spec on booleans.
To avoid this you could declare the variables using the select attribute or manually convert them to number for the comparison:
<xsl:variable name="a" select="20"/>
<xsl:variable name="b" select="10"/>
...
<xsl:if test="number($a) > number($b)">
</xsl:if>
<xsl:variable name="date1" select="2011-10-05"/>
<xsl:variable name="date2" select="2011-10-05"/>
<xsl:variable name="date3" select="2011-10-06"/>
<xsl:if test="$date2 = $date1 or $date2 < $date1">
..do something
</xsl:if>
<xsl:if test="$date3 = $date1 or $date3 > $date1">
.. do something
</xsl:if>
Both should evaluate true, but the second if doesn't. For the life of me I can't comprehended why!
In the actual transform the dates themselves are being drawn from an XML document but debugging through VS2010 i can see the values are as above.
Must be something fairly fundamental i'm doing wrong - any help would be brilliant!
I tried this in Oxygen/XML... select="2011-10-05 is being interpreted as an arithmetic expression, giving the value 1996 (2011 minus 10 minus 5) and "2011-10-06" is intrepreted as 1995.
What you want is
<xsl:variable name="date1" select="'2011-10-05'"/>
<xsl:variable name="date2" select="'2011-10-05'"/>
<xsl:variable name="date3" select="'2011-10-06'"/>
Note the extra single quotes.
From the XSLT 1.0 Specification:
If the variable-binding element has a select attribute, then the value
of the attribute must be an expression and the value of the variable
is the object that results from evaluating the expression.