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

StackOverflow https://stackoverflow.com/questions/825831

  •  05-07-2019
  •  | 
  •  

Вопрос

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

Решение

test="categoryName != ''"

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

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

Для получения более подробной информации, например, для четкой идентификации пустого и пустого, см. ответ Джонви ниже и / или 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)='')"

Первые два имеют дело со значением NULL, а вторые два имеют дело с пустой строкой.

<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, сериализованного из объектов .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, потому что, в отличие от, скажем, Javascript

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

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

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

Я знаю, что этот вопрос старый, но между всеми ответами мне не хватает одного, который является общим подходом для этого варианта использования при разработке 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 - использование шаблонов (отсюда и 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), потому что первая выше имеет более высокий приоритет (у нее есть предикат). & Quot; сбой & Quot; соответствующий шаблон, второй, ловит все, что не является допустимым. Затем третий заботится о правильном выводе значения categories.

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

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

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

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

Например, если 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:

"Тактические шаблоны проектирования в .NET:Поток управления"

Если узел не имеет значения, доступного во входном 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>

Примечание. Если вы не проверяете нулевые значения или не обрабатываете нулевые значения, IE7 возвращает -2147483648 вместо NaN.

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

  

< xsl: when test = " длина строки (поле, которое вы хотите проверить) < 1 " >

По моему опыту лучший способ:

<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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top