I have the below template as shown..
<xsl:for-each select="/abc/def">
<xsl:if test=".Id='xxx' and ./Role='yyy' ">
<xsl:value-of select=" 'true'"/>
</xsl:if>
Now I want to put an or condition in an xsl:if condition such that let say condition 1 is true then also result should be true or if condition 2 is true then also the result is true , now please advise how to put the or condition
I have come up with this solution please advise is it correct ....
<xsl:if test=".Id='xxx' and ./Role='yyy' or test=".Id='ttt' and ./Role='ccc' ">
Everytime I'm not sure about priorities I use brackets, so e.g. test="(Id='xxx' and Role='yyy') or (Id='ttt' and Role='ccc')".
Btw, there is only one "test" attribute in "if", you don't need to repeat it for second condition.
Related
I don't have an approach for this, since I'm not able to change values of variables in XSLT.
Hopefully you could provide a proper approach for the following problem:
This is an example xml-node, to which I'll quote to explain the problem:
<information>
<uselessNode1></uselessNode1>
<uselessNode2></uselessNode2>
<importantNode></importantNode>
</information>
What I essentially need here is to go through all the child nodes of the information node.
The importantNode is optional and the thing what I've to detect is whether this node is there or not.
If the importantNode is there it'll processed within the for-each loop and everything is fine.
In case of not having the importandNode, I've to show it's absence outside of the for-each loop.
So, if having following for-each loop in a template for the information node:
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="not( name() = 'importantNode')">
USELESS
</xsl:when>
<xsl:otherwise>
IMPORTANT
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
The output is "USELESS USELESS IMPORTANT". And if the important node is not there the output is
"USELESS USELESS". What I actually need to have instead of "USELESS USELESS" is a prompt, which shows that the important node is not there, e.g. "USELESS USELESS IMPORTANT_MISSING".
I tried to set a variable in the for-each loop if going in the -case and trying to
check this outside of the for-each loop throws an error, that the variable $importantFound is not declared or out of it's scope. I though declaring it before the for-each loop would help. Since I can't declare the variable before the for-each loop and change it's value in the otherwise case inside of the loop, I don't know how to solve this dilemma.
I hope the explanation of my problem was clear enough to understand.
Thank You all in advance.
In case of not having the importandNode, I've to show it's absence outside of the for-each loop.
So why can't you do exactly that - for example:
<xsl:template match="information">
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="not(self::importantNode)">USELESS </xsl:when>
<xsl:otherwise>IMPORTANT </xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="not(importantNode)">IMPORTANT_MISSING</xsl:if>
</xsl:template>
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 a condition where I need to loop atleast once and so I have the following xsl code. However, this doesnt work as it always gets the last iterations value. How can I tweak this so it gets the right iteration on each loop?
<xsl:variable name='count0'>
<xsl:choose>
<xsl:when test='count($_BoolCheck/BoolCheck[1]/CheckBoolType) = 0'>
<xsl:value-of select="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='count($_BoolCheck/BoolCheck[1]/CheckBoolType)'/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="1 to $count0">
<xsl:variable name='_LoopVar_2_0' select='$_BoolCheck/BoolCheck[1]/CheckBoolType[position()=$count0]'/>
<e>
<xsl:attribute name="n">ValueIsTrue</xsl:attribute>
<xsl:attribute name="m">f</xsl:attribute>
<xsl:attribute name="d">f</xsl:attribute>
<xsl:if test="(ctvf:isTrue($_LoopVar_2_0/CheckBoolType[1]))">
<xsl:value-of select=""Value True""/>
</xsl:if>
</e>
</xsl:for-each>
The xml file is as follows:
<BoolCheck>
<CheckBoolType>true</CheckBoolType>
<CheckBoolType>false</CheckBoolType>
<CheckBoolType>1</CheckBoolType>
<CheckBoolType>0</CheckBoolType>
<CheckBoolType>True</CheckBoolType>
<CheckBoolType>False</CheckBoolType>
<CheckBoolType>TRUE</CheckBoolType>
<CheckBoolType>FALSE</CheckBoolType>
</BoolCheck>
In this case I need to iterate through each iteration of CheckBoolType and produce a corresponding number of values. However, in the above example if there were no CheckBoolType iterations I would still like the iterations to enter the for-each loop atleast once. i hope that clarifies it a little more.
First observation: your declaration of $count0 can be replaced by
<xsl:variable name="temp" select="count($_BoolCheck/BoolCheck[1]/CheckBoolType)"/>
<xsl:variable name="count0" select="if ($temp=0) then 1 else $temp"/>
(Sorry if that seems irrelevant, but my first step in debugging code is always to simplify it. It makes the bugs much easier to find).
When you do this you can safely replace the predicate [position()=$count0] by [$count0], because $count0 is now an integer rather than a document node. (Even better, declare it as an integer using as='xs:integer' on the xsl:variable declaration.)
But hang on, $count0 is the number of elements being processed, so CheckBoolType[$count] will always select the last one. That's surely not what you want.
This brings us to another bug in your code. The value of the variable $_LoopVar_2_0 is an element node named CheckBoolType. The expression $_LoopVar_2_0/CheckBoolType[1] is looking for children of this element that are also named CheckBoolType. There are no such children, so the expression selects an empty sequence, so the boolean test is always false.
At this stage I would like to show you some correct code to achieve your desired output. Unfortunately you haven't shown us the desired output. I can't reverse engineer the requirement from (a) your incorrect code, and (b) your prose description of the algorithm you are trying to implement.
I simply can't find this anywhere. How can I write an if statement in xslt to show the words 'YES' if a div with an id of 'cat' also has a class assigned to it which is called 'true'?
If the div in question is the current node, and you don't currently know whether it has an ID of 'cat' or a class attribute, then you might write
<xsl:if test=".[#id='cat' and contains(#class,'true')]">
YES
</xsl:if>
If you're in a template that matches on div[#id='cat'], then you can use the simpler test test="contains(#class,'true')". (And conversely.)
Note that the test as just formulated will succeed for divs with class="untrue" -- if that's an issue for your situation, the solution becomes a bit messier.
In XSLT 1.0, the simplest way is to write something like this:
<xsl:if test=".[#id='cat'
and
contains(concat(' ', #class, ' '),' true ')]">
YES
</xsl:if>
In XSLT 2.0, I'd write something like:
<xsl:if test=".[#id='cat'
and
tokenize(#class, '\s') = 'true')]">
YES
</xsl:if>
How-to break a for-each loop in XSLT?
XSLT is written in a very functional style, and in this style there is no equivalent of a break statement. What you can do is something like this:
<xsl:for-each select="...nodes...">
<xsl:if test="...some condition...">
...body of loop...
</xsl:if>
</xsl:for-each>
That way the for-each will still iterate through all the nodes, but the body of the loop will only be executed if the condition is true.
Put the condition for stopping the "loop" in the select attribute of the for-each element. For instance, to "break" after four elements:
<xsl:for-each select="nodes[position()<=4]">
To iterate up to but not including a node that satisfied some particular condition:
<xsl:for-each select="preceding-sibling::node[condition]">
XSLT isn't a procedural language; don't think of for-each as being a "loop" in the way you have a loop in Java. For-each is a way to apply a template to each of a bunch of items. It doesn't necessarily happen in a particular order, so you can't think of it as "apply this template to each of a bunch of items until such-and-such happens, then stop".
That said, you can use the select attribute to filter the results, so it becomes more like "apply a template to each of a bunch of items, but only if such-and-such is true of them".
If what you really want is "apply a template to each of a bunch of items, where such-and-such is true of them, but only to the first one this is true of", you can combine the select attribute with the position() function.
A "break" from the body of an <xsl:for-each> XSLT instruction cannot be specified using a syntactic construct, however it can be simulated.
Essentially two techniques are discussed:
Performing something inside the body of <xsl:for-each> only if a specific condition is satisfied. This can be improved if the condition can be specified in the select attribute of <xsl:for-each> -- in this case only the necessary nodes will be processed. See for example: https://stackoverflow.com/a/7532602/36305
Specifying the processing not using <xsl:for-each> but with recursion. There are many examples of recursive processing with XSLT. See the code at: https://fxsl.sf.net/
The second method has the benefit of being able to perform the exit immediately, contrasted with the first method having to still perform many "empty cycles" even after the exit-condition has been satisfied.
I had a similar situation and here is the code I had written. For logical reasons, I couldn't fit in the other conditions with condition01.
<xsl:for-each select="msxsl:node-set($DATA6)[condition01]">
<xsl:choose>
<xsl:when test="not((condtion02 or condition03) and condition04)">
--body of for loop
</xsl:when>
</xsl:choose>
</xsl:for-each>
Hello I kwow this is an old post but maybe it can help other developers. I have found a way to break a for each in XSLT it is not litteraly a break but if you see the code you will get it. As you know or not know you can use inline C# code in xslt. In this example i want to loop al the nodes and take the first NTE node with Value RC But if I get a node that differs from the NTE node i want to stop looking at the condition. So I set a global variable in C# code and I ask the value each time I go through a node:
<xsl:value-of select="userCSharp:SetStopForeach('true')" />
<xsl:for-each select="following-sibling::node()">
<xsl:if test="local-name()='NTE_NotesAndComments_3' and userCSharp:GetStopForeach()" >
<xsl:for-each select="NTE_4_CommentType">
<xsl:if test="(CE_0364_0_IdentifierSt)[text()="RC"]">
<ns0:RESULTAAT_COMMENTAAR>
<xsl:for-each select="../NTE_3_Comment">
<xsl:value-of select="./text()" />
</xsl:for-each>
</ns0:RESULTAAT_COMMENTAAR>
</xsl:if>
</xsl:for-each>
</xsl:if>
<xsl:if test="local-name()='ORC_CommonOrder'" >
<xsl:value-of select="userCSharp:SetStopForeach('false')" />
</xsl:if>
</xsl:for-each>
.....
<msxsl:script language="C#" implements-prefix="userCSharp">
<![CDATA[
public bool StopForeach=false;
public bool GetStopForeach() {
return StopForeach;
}
public string SetStopForeach(bool aValue) {
StopForeach=aValue;
return "";
}
]]>
</msxsl:script>