在 XSLT 中检查字符串是不是为空或空

Posted

技术标签:

【中文标题】在 XSLT 中检查字符串是不是为空或空【英文标题】:Check if a string is null or empty in XSLT在 XSLT 中检查字符串是否为空或空 【发布时间】:2010-10-23 23:22:26 【问题描述】:

如何使用XSL 检查值是否为空或空?

例如,如果categoryName 为空?我在选择时使用了 构造。

例如:

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

【问题讨论】:

可以扩展代码示例吗? 根据您的用例,您可能不想使用xsl:when 进行节点测试。考虑&lt;xsl:template match="Category[categoryName[not(node())]]"&gt;...&lt;xsl:template match="Category"&gt;...。然后处理器将为您做出正确的决定,您不再需要在嵌套的xsl:choose 中写出业务逻辑。在许多情况下,使用匹配的模板可以更轻松地编写样式表。 【参考方案1】:
test="categoryName != ''"

编辑:在我看来,这涵盖了从问题中推断出的“[not] null or empty”最可能的解释,包括它的伪代码和我自己早期使用 XSLT 的经验.即,“以下 Java 的等价物是什么?”:

// Equivalent Java, NOT XSLT
!(categoryName == null || categoryName.equals(""))

有关更多详细信息,例如,明确识别 null 与空,请参阅 johnvey's answer below 和/或 the XSLT 'fiddle' 我已改编自该答案,其中包括 Michael Kay 评论中的选项以及第六种可能的解释。

【讨论】:

这个测试的详细语义是:如果至少有一个categoryName元素的字符串值为空字符串,则返回true。 @jelovirt 你的意思是说是否至少有一个 categoryName 不是空字符串? (我是 xsl 新手,请原谅我的问题可能存在的愚蠢问题。) 这个答案虽然被接受并被高度评价,但也非常具有误导性。这真的取决于你所说的“空或空”是什么意思。如果您希望在 categoryName 不存在或以零长度值存在时成功的测试,您应该使用test="not(categoryName = '')"。如果 categoryName 元素不存在,则提供的答案将返回 false,在我对问题的解释中,这使其成为错误答案。 @MichaelKay:我已经更新了答案以提供更多详细信息。感谢您的评论和 Saxon XSLT 处理器! 如何翻译&lt;xsl:for-each select="root/*[matches(name(.), 'grp')]"&gt;以便在VS2010中使用?【参考方案2】:

来自Empty Element

测试某个节点的值是否为空

这取决于你所说的空是什么意思。

不包含子节点:not(node()) 不包含文本内容:not(string(.)) 除空格外不包含任何文本:not(normalize-space(.)) 除了 cmets 不包含任何内容:not(node()[not(self::comment())])

【讨论】:

+1。一些笔记。第一个要点还测试文本内容,它也是一个节点。第二个要点测试任意深度的任意文本节点,如果想知道当前节点是否不包含文本,但可以包含其他节点,可以使用not(text())。你的第二个子弹的替代品也是not(.//text())。正如您的最后一个项目符号所示:有很多方法可以考虑“虚无”;)。 非常实用:要测试一个字符串是否为空,你可以只测试字符串本身! if ($mystring) then ... else ...【参考方案3】:

如果没有任何其他信息,我将假设以下 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>

示例用例如下所示:

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

【讨论】:

如何测试 &lt;/CategoryName&gt; 的实例? , 空字符串测试不适用于此 感谢您提供了多个示例来展示每个表达式的结果。 @raffian:在 XSLT 或相关技术(XQuery、DOM、XDM、Schema 等)中,结束标签不被视为单独的实体。相反,在这种情况下,您只处理节点或元素,即开始标记和结束标记之间的整体。总之,没有办法测试&lt;/CategoryName&gt;,也没有必要。 我专门为这个答案加了星标,虽然这个问题已经很老了,但这个问题似乎更值得成为选择的答案【参考方案4】:

在某些情况下,您可能想知道该值何时具体为 null,这在使用从 .NET 对象序列化的 XML 时尤其必要。虽然接受的答案适用于此,但当字符串为空白或空时,它也会返回相同的结果,即'',因此您无法区分。

<group>
    <item>
        <id>item 1</id>
        <CategoryName xsi:nil="true" />
    </item>
</group>

所以你可以简单地测试属性。

<xsl:if test="CategoryName/@xsi:nil='true'">
   Hello World.
</xsl:if>

有时需要知道确切的状态,你不能简单地检查 CategoryName 是否被实例化,因为不像 javascript

<xsl:if test="CategoryName">
   Hello World.
</xsl:if>

将为 null 元素返回 true。

【讨论】:

【参考方案5】:

这样的东西对我有用:

<xsl:choose>
  <xsl:when test="string(number(categoryName)) = 'NaN'"> - </xsl:when> 
  <xsl:otherwise> 
    <xsl:number value="categoryName" />
  </xsl:otherwise>
</xsl:choose>

或者反过来:

<xsl:choose>
  <xsl:when test="string(number(categoryName)) != 'NaN'">
    <xsl:number value="categoryName" />
  </xsl:when> 
  <xsl:otherwise> - </xsl:otherwise>
</xsl:choose>

注意:如果不检查 null 值或不处理 null 值,IE7 将返回 -2147483648 而不是 NaN。

【讨论】:

【参考方案6】:

怎么样?

test="not(normalize-space(categoryName)='')"

【讨论】:

这很好用。即使&lt;categoryName&gt; &lt;!-- some comment --&gt; &lt;/categoryName&gt; 内有评论并且没有有意义的文本,这仍然评估为true【参考方案7】:

前两个处理空值,后两个处理空字符串。

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

【讨论】:

可怕。如果有多个用户或多个名字怎么办?使用xsl:apply-templates 和匹配的模板来获得你想要的,更容易。【参考方案8】:

如果 XML 中可能不存在该元素,我将测试该元素是否存在以及字符串长度是否大于零:

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

【讨论】:

空节点集的字符串值(当当前上下文中没有categoryName 子元素时,XPath 表达式categoryName 为您提供)被定义为空字符串,所以这是多余的 - 如果没有 categoryName 元素,string-length(categoryName) 为零。【参考方案9】:

根据我的经验,最好的方法是:

<xsl:when test="not(string(categoryName))">
    <xsl:value-of select="other" />
</xsl:when>
<otherwise>
    <xsl:value-of select="categoryName" />
</otherwise>

【讨论】:

【参考方案10】:

我知道这个问题很老,但在所有答案中,我错过了一个在 XSLT 开发中这个用例的常用方法。

我想象 OP 中缺少的代码看起来像这样:

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

输入看起来像这样:

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

也就是说,我假设可以有零个、空的、单个或多个 categoryName 元素。使用xsl:choose 样式的构造来处理所有这些情况,或者换句话说,命令式的,很快就会变得混乱(如果元素可以处于不同的级别,那就更糟了!)。 XSLT 中的一个典型编程习惯是使用模板(因此在 XSLT 中使用 T),它是声明式编程,而不是命令式编程(你不告诉处理器要做什么,你只告诉在满足某些条件时你想要输出什么)。对于这个用例,可能如下所示:

<!-- 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>

这可行(适用于任何 XSLT 版本),因为上面的第一个具有更高的优先级(它有一个谓词)。第二个“失败”匹配模板捕获任何无效的内容。然后第三个负责以适当的方式输出categoryName 值。

请注意,在这种情况下,无需专门匹配categoriescategory,因为处理器将自动处理所有孩子,除非我们另有说明(在此示例中,第二个和第三个模板不会进一步处理孩子,因为他们没有xsl:apply-templates)。

这种方法比命令式方法更容易扩展,因为它自动处理多个类别,并且可以通过添加另一个匹配模板来扩展其他元素或异常。 没有 if 分支的编程

注意:在 XML 中没有 null 这样的东西。有xsi:nil,但很少使用,尤其是在没有某种模式的无类型场景中。

【讨论】:

恭喜您提到“没有 if 分支的编程”。有些人不明白这一点的重要性。对于他们所有人来说,这里有一个关于这个主题的非常好的 Pluralsight 课程的链接:Zoran Horvat 的“Tactical Design Patterns in .NET: Control Flow”:app.pluralsight.com/library/courses/… 必读!跨度> 【参考方案11】:

如果一个节点在输入 xml 中没有可用的值,如下面的 xpath,

<node>
    <ErrorCode/>
</node>

string() 函数转换为空值。所以这很好用:

string(/Node/ErrorCode) =''

【讨论】:

【参考方案12】:

使用简单的 categoryName/text() 这样的测试可以在 &lt;categoryName/&gt;&lt;categoryName&gt;&lt;/categoryName&gt; 上正常工作。

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

【讨论】:

【参考方案13】:

如何使用 XSL 检查值是 null 还是空?

例如,如果categoryName 为空?

这可能是最简单的 XPath 表达式(接受答案中的表达式提供了相反的测试,如果否定,会更长):

not(string(categoryName))

解释

上面not()函数的参数是false(),恰好当上下文项没有categoryName子(“null”),或者(单个这样的)categoryName子有字符串值——空字符串。

我在选择时使用了一个 构造。

例如:

<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 2.0 中使用

<xsl:copy-of select="concat(categoryName,  $vOther[not(string(current()/categoryName))])"/>

这是一个完整的例子

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

当此转换应用于以下 XML 文档时:

<categoryName>X</categoryName>

产生想要的正确结果

X

应用于此 XML 文档时

<categoryName></categoryName>

或者关于这个:

<categoryName/>

或在此

<somethingElse>Y</somethingElse>

产生正确的结果

Other

同样,使用这个 XSLT 1.0 转换:

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

注意:根本不使用条件句。在这门精彩的 Pluralsight 课程中详细了解避免条件结构的重要性:

"Tactical Design Patterns in .NET: Control Flow"

【讨论】:

嗨 Dimitre,我需要你的 1.0 解决方案,所以我需要在我拥有的每个标签中对其进行编码,还是有更简单的方法来为整个 XML 实现它? @zyberjock,不清楚你在问什么。请发表一个问题,并给我一个带有链接的评论。遵循如何提出好问题的指南。 嗨@Dimitre,我在这里发布了一个问题***.com/questions/38150093/…【参考方案14】:

实际上我发现只测试字符串长度更好,因为很多时候该字段不是空的,只是空的

【讨论】:

以上是关于在 XSLT 中检查字符串是不是为空或空的主要内容,如果未能解决你的问题,请参考以下文章

检查字符串是不是为空或为空的最简单方法

Python Django 模板和测试变量是不是为空或空字符串

jQuery - 检查数组是不是为空或具有属性

当变量有时为空或空字符串时,如何使用 CONTAINS()?

sql 检查字符串为空或为空

javascript检查空字符串或空字符串[重复]