多条件查询
string.Format("/root/deviceList//item/guid[{0}]", strBuilder.ToString()) "/root/deviceList//item/guid[text()=\"h\" or text()=\"a\" or text()=\"c\"]"
Check if a string is null or empty in XSLT
Ask Question Asked 10 years, 10 months ago Active 2 years, 1 month ago Viewed 506k times 323How can I check if a value is null or empty with XSL?
For example, if categoryName
is empty? I'm using a when choosing construct.
For example:
<xsl:choose>
<xsl:when test="categoryName !=null">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
xslt null xslt-1.0 xslt-2.0
shareimprove this question
edited Jul 25 '14 at 17:35
Isaac G Sivaa
1,15133 gold badges1313 silver badges3232 bronze badges
asked May 5 '09 at 16:45
raklos
24.8k5252 gold badges165165 silver badges267267 bronze badges
add a comment
14 Answers
activeoldestvotes 318test="categoryName != ''"
Edit: This covers the most likely interpretation, in my opinion, of "[not] null or empty" as inferred from the question, including it's pseudo-code and my own early experience with XSLT. I.e., "What is the equivalent of the following Java?":
!(categoryName == null || categoryName.equals(""))
For more details e.g., distinctly identifying null vs. empty, see johnvey's answer below and/or the XSLT 'fiddle' I've adapted from that answer, which includes the option in Michael Kay's comment as well as the sixth possible interpretation.
shareimprove this answer edited Jan 10 '18 at 10:33 bluish 20.9k2121 gold badges103103 silver badges158158 bronze badges answered May 5 '09 at 16:53 steamer25 7,75011 gold badge2323 silver badges3232 bronze badges- 14 The detailed semantics of this test is: return true if there is at least one categoryName element whose string value is an empty string. – jelovirt May 11 '09 at 6:08
- 14 @jelovirt did you mean to say if there is at least one categoryName that's NOT an empty string? (I'm an xsl newbie, so forgive any potential stupidity to my question.) – joedevon Nov 4 '11 at 23:39
-
10
This answer, while accepted and highly voted, is also very misleading. It really depends what you mean by "null or empty". If you want a test that succeeds if categoryName is either absent, or present with a zero-length value, you should use
test="not(categoryName = '')"
. The supplied answer will return false if the categoryName element is absent, which in my interpretation of the question makes it a wrong answer. – Michael Kay Aug 12 '15 at 14:55 - 2 @MichaelKay: I've updated the answer to provide more details. Thanks for the comment and for the Saxon XSLT processor! – steamer25 Aug 26 '15 at 22:53
-
How can I translate
<xsl:for-each select="root/*[matches(name(.), 'grp')]">
so it can be used in VS2010? – Si8 Oct 28 '15 at 17:21
Absent of any other information, I'll assume the following XML:
<group>
<item>
<id>item 1</id>
<CategoryName>blue</CategoryName>
</item>
<item>
<id>item 2</id>
<CategoryName></CategoryName>
</item>
<item>
<id>item 3</id>
</item>
...
</group>
A sample use case would look like:
<xsl:for-each select="/group/item">
<xsl:if test="CategoryName">
<!-- will be instantiated for item #1 and item #2 -->
</xsl:if>
<xsl:if test="not(CategoryName)">
<!-- will be instantiated for item #3 -->
</xsl:if>
<xsl:if test="CategoryName != ''">
<!-- will be instantiated for item #1 -->
</xsl:if>
<xsl:if test="CategoryName = ''">
<!-- will be instantiated for item #2 -->
</xsl:if>
</xsl:for-each>
shareimprove this answer
edited May 6 '09 at 18:01
Dirk Vollmar
153k5151 gold badges238238 silver badges293293 bronze badges
answered May 5 '09 at 17:06
johnvey
4,72811 gold badge1515 silver badges1313 bronze badges
-
How do you test for instances of
</CategoryName>
? , empty string tests don't work for this – raffian Feb 14 '12 at 17:22 - 3 It's appreciated that you included multiple examples to show how each expression results. – doubleJ Nov 7 '13 at 20:13
-
1
@raffian: in XSLT, or related technologies (XQuery, DOM, XDM, Schema etc), end-tags are not considered as separate entities. Instead, you only deal with nodes, or elements in this case, which is the whole between start-tag and end-tag. In short, there is no way to test for
</CategoryName>
, nor is there any need for. – Abel Jul 21 '14 at 1:51 - 4 I starred the question specifically for this answer, and while the question is pretty old, this one seems much more deserving of being the selected answer – Patrick Aug 1 '14 at 13:28
From Empty Element:
To test if the value of a certain node is empty
It depends on what you mean by empty.
- Contains no child nodes:
not(node())
- Contains no text content:
not(string(.))
- Contains no text other than whitespace:
not(normalize-space(.))
- Contains nothing except comments:
not(node()[not(self::comment())])
-
2
+1. Some notes. The first bulletpoint also tests for text-content, which is also a node. The second bulletpoint tests for any text node at any depth, if you want to know if the current node does not contain text, but can contain other nodes, you can use
not(text())
. An alternative to your 2nd bullet is alsonot(.//text())
. As your last bullet shows: there are many ways to consider "nothingness" ;). – Abel Jul 21 '14 at 1:56 -
Very practical: To test if a string is not empty, you can just test the string itself!
if ($mystring) then ... else ...
– Felix Dombek Feb 14 '17 at 2:33
What about?
test="not(normalize-space(categoryName)='')"
shareimprove this answer
answered Dec 2 '11 at 15:05
helcim
71099 silver badges2525 bronze badges
-
1
This works great. Even when there is a comment inside
<categoryName> <!-- some comment --> </categoryName>
and otherwise no meaningful text, this still evaluates totrue
– rustyx Sep 15 '15 at 10:33
First two deal with null value and second two deal with empty string.
<xsl:if test="USER/FIRSTNAME">
USERNAME is not null
</xsl:if>
<xsl:if test="not(USER/FIRSTNAME)">
USERNAME is null
</xsl:if>
<xsl:if test="USER/FIRSTNAME=''">
USERNAME is empty string
</xsl:if>
<xsl:if test="USER/FIRSTNAME!=''">
USERNAME is not empty string
</xsl:if>
shareimprove this answer
answered Aug 10 '12 at 12:58
Aleksandar Borkovac
13333 silver badges88 bronze badges
-
1
Scary. What if there are multiple users or multiple firstnames? Use
xsl:apply-templates
and matching templates to get what you want, much easier. – Abel Jul 21 '14 at 2:06
In some cases, you might want to know when the value is specifically null, which is particularly necessary when using XML which has been serialized from .NET objects. While the accepted answer works for this, it also returns the same result when the string is blank or empty, i.e. '', so you can't differentiate.
<group>
<item>
<id>item 1</id>
<CategoryName xsi:nil="true" />
</item>
</group>
So you can simply test the attribute.
<xsl:if test="CategoryName/@xsi:nil='true'">
Hello World.
</xsl:if>
Sometimes it's necessary to know the exact state and you can't simply check if CategoryName is instantiated, because unlike say Javascript
<xsl:if test="CategoryName">
Hello World.
</xsl:if>
Will return true for a null element.
shareimprove this answer answered Aug 12 '11 at 8:26 DustJones 7111 silver badge22 bronze badges add a comment 6I know this question is old, but between all the answers, I miss one that is a common approach for this use-case in XSLT development.
I am imagining that the missing code from the OP looks something like this:
<xsl:template match="category">
<xsl:choose>
<xsl:when test="categoryName !=null">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
</category>
And that the input looks something like this:
<categories>
<category>
<categoryName>Books</categoryName>
</category>
<category>
<categoryName>Magazines</categoryName>
<categoryName>Periodicals</categoryName>
<categoryName>Journals</categoryName>
</category>
<category>
<categoryName><!-- please fill in category --></categoryName>
</category>
<category>
<categoryName />
</category>
<category />
</categories>
I.e., I assume there can be zero, empty, single or multiple categoryName
elements. To deal with all these cases using xsl:choose
-style constructs, or in other words, imperatively, is quickly getting messy (even more so if elements can be at different levels!). A typical programming idiom in XSLT is using templates (hence the T in XSLT), which is declarative programming, not imperative (you don't tell the processor what to do, you just tell what you want output if certain conditions are met). For this use-case, that can look something like the following:
<!-- positive test, any category with a valid categoryName -->
<xsl:template match="category[categoryName[text()]]">
<xsl:apply-templates />
</xsl:template>
<!-- any other category (without categoryName, "null", with comments etc) -->
<xsl:template match="category">
<xsl:text>Category: Other</xsl:text>
</xsl:template>
<!-- matching the categoryName itself for easy handling of multiple names -->
<xsl:template match="categoryName">
<xsl:text>Category: </xsl:text>
<xsl:value-of select="." />
</xsl:template>
This works (with any XSLT version), because the first one above has a higher precedence (it has a predicate). The "fall-through" matching template, the second one, catches anything that is not valid. The third one then takes care of outputting the categoryName
value in a proper way.
Note that in this scenario there is no need to specifially match categories
or category
, because the processor will automatically process all children, unless we tell it otherwise (in this example, the second and third template do not further process the children, because there is no xsl:apply-templates
in them).
This approach is more easily extendible then the imperative approach, because it automically deals with multiple categories and it can be expanded for other elements or exceptions by just adding another matching template. Programming without if-branches.
Note: there is no such thing as null
in XML. There is xsi:nil, but that is rarely used, especially rarely in untyped scenarios without a schema of some sort.
- 1 Congrats on mentioning "Programming without if-branches". There are some people who fail to understand the importance of this. For all of them here is a link to a very nice Pluralsight course on this topic: "Tactical Design Patterns in .NET: Control Flow" by Zoran Horvat: app.pluralsight.com/library/courses/… A must-read! – Dimitre Novatchev Jan 21 '16 at 3:00
How can I check if a value is null or empty with XSL?
For example, if
categoryName
is empty?
This is probably the simplest XPath expression (the one in accepted answer provides a test for the opposite, and would be longer, if negated):
not(string(categoryName))
Explanation:
The argument to the not()
function above is false()
exactly when there is no categoryName
child ("null") of the context item, or the (single such) categoryName
child has string value -- the empty string.
I'm using a when choosing construct.
For example:
<xsl:choose> <xsl:when test="categoryName !=null"> <xsl:value-of select="categoryName " /> </xsl:when> <xsl:otherwise> <xsl:value-of select="other" /> </xsl:otherwise> </xsl:choose>
In XSLT 2.0 use:
<xsl:copy-of select="concat(categoryName, $vOther[not(string(current()/categoryName))])"/>
Here is a complete example:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vOther" select="'Other'"/>
<xsl:template match="/">
<xsl:copy-of select="concat(categoryName,$vOther[not(string(current()/categoryName))])"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<categoryName>X</categoryName>
the wanted, correct result is produced:
X
When applied on this XML document:
<categoryName></categoryName>
or on this:
<categoryName/>
or on this
<somethingElse>Y</somethingElse>
the correct result is produced:
Other
Similarly, use this XSLT 1.0 transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vOther" select="'Other'"/>
<xsl:template match="/">
<xsl:copy-of select=
"concat(categoryName, substring($vOther, 1 div not(string(categoryName))))"/>
</xsl:template>
</xsl:stylesheet>
Do note: No conditionals are used at all. Learn more about the importance of avoiding conditional constructs in this nice Pluralsight course:
"Tactical Design Patterns in .NET: Control Flow"
shareimprove this answer edited Jan 21 '16 at 3:02 answered Jan 1 '16 at 1:16 Dimitre Novatchev 221k2626 gold badges262262 silver badges384384 bronze badges- Hi Dimitre, i need your solution for 1.0, so do I need to code it in every tags that I have or is there a simpler way to impement it for the whole XML? – zyberjock Jul 1 '16 at 7:38
- @zyberjock, It is unclear what you are asking. Please, post a question and send me a comment with a link. Follow the guidelines how to ask a good question. – Dimitre Novatchev Jul 1 '16 at 14:20
- Hi @Dimitre, I posted a question here stackoverflow.com/questions/38150093/… – zyberjock Jul 1 '16 at 16:30
If there is a possibility that the element does not exist in the XML I would test both that the element is present and that the string-length is greater than zero:
<xsl:choose>
<xsl:when test="categoryName and string-length(categoryName) > 0">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
shareimprove this answer
answered Jun 14 '13 at 15:47
Marie Taylor
4111 bronze badge
-
3
The string value of an empty node set (which is what the XPath expression
categoryName
gives you when there are nocategoryName
child elements in the current context) is defined to be the empty string, so this is redundant -string-length(categoryName)
is zero if there are nocategoryName
elements. – Ian Roberts Jun 14 '13 at 16:25
If a node has no value available in the input xml like below xpath,
<node>
<ErrorCode/>
</node>
string() function converts into empty value. So this works fine:
string(/Node/ErrorCode) =''
shareimprove this answer
answered Apr 23 '15 at 9:35
Sanjeev Singh
3,53022 gold badges2626 silver badges3838 bronze badges
add a comment
2
Something like this works for me:
<xsl:choose>
<xsl:when test="string(number(categoryName)) = 'NaN'"> - </xsl:when>
<xsl:otherwise>
<xsl:number value="categoryName" />
</xsl:otherwise>
</xsl:choose>
Or the other way around:
<xsl:choose>
<xsl:when test="string(number(categoryName)) != 'NaN'">
<xsl:number value="categoryName" />
</xsl:when>
<xsl:otherwise> - </xsl:otherwise>
</xsl:choose>
Note: If you don't check null values or handle null values, IE7 returns -2147483648 instead of NaN.
shareimprove this answer edited Apr 23 '15 at 10:10 Sanjeev Singh 3,53022 gold badges2626 silver badges3838 bronze badges answered Aug 18 '11 at 10:12 HSol 2111 bronze badge add a comment 1I actually found it better just testing for string length since many times the field is not null, just empty
shareimprove this answer answered Jun 23 '16 at 8:54 Pedro Pereira 44055 silver badges1212 bronze badges add a comment 0<xsl:when test="string-length(field-you-want-to-test)<1">
By my experience the best way is:
<xsl:when test="not(string(categoryName))">
<xsl:value-of select="other" />
</xsl:when>
<otherwise>
<xsl:value-of select="categoryName" />
</otherwise>
shareimprove this answer
edited Jul 29 '13 at 7:46
answered Jul 29 '13 at 7:40
dr_leevsey
15722 silver badges88 bronze badges
add a comment
0
Use simple categoryName/text() Such test works fine on <categoryName/>
and also <categoryName></categoryName>
.
<xsl:choose>
<xsl:when test="categoryName/text()">
<xsl:value-of select="categoryName" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
shareimprove this answer
answered Sep 10 '15 at 13:00
Jaroslav Kubacek
1,1791414 silver badges2323 bronze badges
add a comment
Highly active question. Earn 10 reputation in order to answer this question. The reputation requirement helps protect this question from spam and non-answer activity.
xsl:when
for node-tests. Consider<xsl:template match="Category[categoryName[not(node())]]">...
together with a<xsl:template match="Category">...
. The processor will then make the correct decisions for you and you do not need to write out the business logic in nestedxsl:choose
anymore. In many cases, using matching templates makes writing stylesheets easier. – Abel Jul 21 '14 at 2:01