首页 > 其他分享 >Check if a string is null or empty in XSLT

Check if a string is null or empty in XSLT

时间:2022-09-06 14:02:26浏览次数:97  
标签:sheet XSLT share answer post null data Check se

多条件查询

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 323

How 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>
    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
  •   Can you expand the code example? – Nick Allen May 5 '09 at 16:48
  •   Depending on your use-case, you probably don't want to use 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 nested xsl:choose anymore. In many cases, using matching templates makes writing stylesheets easier. – Abel Jul 21 '14 at 2:01
add a comment

14 Answers

activeoldestvotes 318  
test="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
show 4 more comments <iframe data-google-container-id="2" data-is-safeframe="true" data-load-complete="true" frameborder="0" height="90" id="google_ads_iframe_/248424177/stackoverflow.com/mlb/question-pages_0" marginheight="0" marginwidth="0" scrolling="no" src="https://tpc.googlesyndication.com/safeframe/1-0-37/html/container.html" title="3rd party ad content" width="728"></iframe> 269

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
add a comment 67

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())])
shareimprove this answer edited Dec 8 '15 at 13:49 Mads Hansen 48k1111 gold badges100100 silver badges129129 bronze badges answered May 5 '09 at 16:53 Chris Doggett 16.6k44 gold badges5353 silver badges8484 bronze badges
  • 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 also not(.//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
add a comment 22

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 to true – rustyx Sep 15 '15 at 10:33 
add a comment 9

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
add a comment 7

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 6

I 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.

shareimprove this answer edited Jan 21 '16 at 2:56 Dimitre Novatchev 221k2626 gold badges262262 silver badges384384 bronze badges answered Jul 21 '14 at 2:27 Abel 49.8k1919 gold badges126126 silver badges207207 bronze badges
  • 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
add a comment 5

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 add a comment 4

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) &gt; 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 no categoryName 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 no categoryName elements. – Ian Roberts Jun 14 '13 at 16:25
add a comment 3

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 1

I actually found it better just testing for string length since many times the field is not null, just empty

<xsl:when test="string-length(field-you-want-to-test)<1">

shareimprove this answer answered Jun 23 '16 at 8:54 Pedro Pereira 44055 silver badges1212 bronze badges add a comment 0

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.

Not the answer you're looking for? Browse other questions tagged     or ask your own question.

标签:sheet,XSLT,share,answer,post,null,data,Check,se
From: https://www.cnblogs.com/ioriwellings/p/12420789.html

相关文章