Проверьте, является ли строка null или пустой в XSLT

Как я могу проверить, является ли значение null или пустым с 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>

14 ответов


test="categoryName != ''"

редактировать: это охватывает наиболее вероятную интерпретацию, на мой взгляд, "[not] null или empty", как следует из вопроса, включая его псевдо-код и мой собственный ранний опыт работы с XSLT. То есть, "Что эквивалентно следующей Java?":

!(categoryName == null || categoryName.equals(""))

для получения более подробной информации, например, отчетливо идентифицируя null против empty, см. ответ джонви ниже и/или XSLT 'скрипка' я адаптировался из этого ответа, который включает в себя вариант в комментарии Майкла Кея, а также шестая возможная интерпретация.


отсутствие какой-либо другой информации, я предположу следующий 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>

С Пустой Элемент:

чтобы проверить, является ли значение определенного узла пустым

Это зависит от того, что вы подразумеваете под пустой.

  • не содержит дочерних узлов: not(node())
  • не содержит текстового содержимого:not(string(.))
  • не содержит текста, кроме пробелов:not(normalize-space(.))
  • не содержит ничего, кроме комментариев: not(node()[not(self::comment())])

о чем?

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>

в некоторых случаях вы можете узнать, когда значение конкретно null, что особенно необходимо при использовании XML, который был сериализован из объектов .NET. Хотя принятый ответ работает для этого, он также возвращает тот же результат, когда строка пуста или пуста, т. е.", поэтому вы не можете различать.

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

таким образом, вы можете просто проверить атрибут.

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

иногда необходимо знать точное состояние и вы не можете просто проверить, если CategoryName создается, потому что в отличие от Say Javascript

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

вернет true для нулевого элемента.


Я знаю, что этот вопрос старый, но между всеми ответами я пропускаю один, который является общим подходом для этого варианта использования в разработке 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-style конструкции, или в другом слова, императивно, быстро становятся грязными (тем более, если элементы могут быть на разных уровнях!). Типичная идиома программирования в XSLT использует шаблоны (следовательно, T в XSLT), что является декларативным программированием, а не императивным (вы не говорите процессору, что делать, вы просто говорите, что хотите выводить, если выполнены определенные условия). Для этого случая использования это может выглядеть примерно так:

<!-- 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 значение надлежащим образом.

обратите внимание, что в этом сценарии нет необходимости конкретно соответствовать categories или category, потому что процессор будет автоматически обрабатывать всех детей, если мы не скажем ему иначе (в этом примере второй и третий шаблон не обрабатывают детей, потому что нет xsl:apply-templates в них).

этот подход легче расширить, чем императивный подход, потому что он автоматически имеет дело с несколькими категориями, и его можно расширить для других элементов или исключений, просто добавив другой соответствующий шаблон. Программирование без if-ветвей.

Примечание: нет такой вещи, как null в XML. Есть xsi: nil, но это редко используется, особенно редко в нетипизированных сценариях без какой-либо схемы.


Если есть возможность, что элемент не существует в 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>

Если узел не имеет значения, доступного во входном xml, как показано ниже xpath,

<node>
    <ErrorCode/>
</node>

функция string () преобразуется в пустое значение. Так что это отлично работает:

string(/Node/ErrorCode) =''

что-то вроде этого работает для меня:

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


как я могу проверить, является ли значение null или пустым с XSL?

, если categoryName пусто?

это, вероятно, самое простое выражение XPath (один в принятом ответе дает тест на противоположное и будет длиннее, если отрицается):

not(string(categoryName))

объяснение:

аргумент


по моему опыту, лучший способ-это:

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

используйте простой 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>

Я действительно нашел, что лучше просто проверить длину строки, так как много раз поле не равно нулю, просто пустое

элемент