检查XSLT中的字符串是空还是空

如何用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>
604093 次浏览
test="categoryName != ''"

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

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

有关更多详细信息,例如,明确识别null和empty,请参见下面是Johnvey的回答和/或XSLT“小提琴”我已经从这个答案中改编,其中包括Michael Kay的评论中的选项以及第六种可能的解释。

空元素:

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

这取决于你对空的定义。

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

在没有任何其他信息的情况下,我将假设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>

在某些情况下,您可能想知道值什么时候具体为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>

对于空元素将返回true。

这对我来说很管用:

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

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

关于什么?

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

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

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

如果有可能元素在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>

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

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

我知道这个问题已经很老了,但是在所有的答案中,我忽略了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>

也就是说,我假设可以有0个、空的、单个或多个categoryName元素。使用__abc1风格的构造来处理所有这些情况,换句话说,命令式地处理,很快就会变得混乱(如果元素可以处于不同的级别,情况就更糟了!)。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版本),因为上面的第一个具有更高的优先级(它有一个谓词)。“fall-through”匹配模板(第二个)捕获任何无效的内容。第三个函数负责以适当的方式输出categoryName值。

注意,在这种情况下,不需要特别匹配categoriescategory,因为处理器将自动处理所有子对象,除非我们另有说明(在本例中,第二个和第三个模板不会进一步处理子对象,因为其中没有xsl:apply-templates)。

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

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

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

<node>
<ErrorCode/>
</node>

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

string(/Node/ErrorCode) =''

使用简单的categoryName/text()这样的测试在<categoryName/><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>

如何用XSL检查一个值是空还是空?

例如,如果categoryName为空?

这可能是最简单的XPath表达式 (accept answer中的一个提供了相反的测试,如果否定,则会更长):

not(string(categoryName))

解释:

当上下文项没有categoryName子元素("null")时,上面的not()函数的实参为false(),或者(单个这样的)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课程中了解更多关于避免条件结构的重要性:

" .NET中的战术设计模式:控制流" .NET

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

& lt; xsl:当测试= " - length (field-you-want-to-test) & lt; 1”>