2009-05-05 3 views
287

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

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

вы можете расширить пример кода? –

+0

В зависимости от вашего прецедента вы, вероятно, не хотите использовать 'xsl: when' для узлов-тестов. Рассмотрим ' ...' вместе с ' ...'. Затем процессор примет правильные решения для вас, и вам больше не нужно будет выписывать бизнес-логику в вложенном 'xsl: select'. Во многих случаях использование совпадающих шаблонов упрощает создание таблиц стилей. – Abel

ответ

291
test="categoryName != ''" 

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

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

Для получения более подробной информации, например, четко идентифицировать нуль против пустой, см johnvey's answer below и/или the XSLT 'fiddle' я адаптировано из этого ответа, который включает в себя в комментарии Майкла Кей, а также шестой возможной интерпретации.

+14

Детальная семантика этого теста: return true, если есть хотя бы один элемент categoryName, строковое значение которого является пустой строкой. – jelovirt

+14

@jelovirt вы имели в виду сказать, есть ли хотя бы одна категорияName, которая НЕ является пустой строкой? (Я новичок xsl, поэтому прошу простить любую потенциальную глупость на мой вопрос.) – joedevon

+7

Этот ответ, хотя он принят и очень проголосован, также очень вводит в заблуждение. Это действительно зависит от того, что вы подразумеваете под «пустым или пустым». Если вы хотите, чтобы тест прошел успешно, если categoryName либо отсутствует, либо присутствует с нулевым значением, вы должны использовать 'test = 'not (categoryName =' ')".Приведенный ответ вернет false, если элемент categoryName отсутствует, что в моей интерпретации вопроса делает неправильный ответ. –

56

От Empty Element:

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

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

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

+1. Некоторые заметки. Первая контрольная точка также тестирует текстовое содержимое, которое также является узлом. Вторая контрольная точка проверяет любой текстовый узел на любой глубине, если вы хотите знать, не содержит ли текущий узел текст, но может содержать другие узлы, вы можете использовать 'not (text())'. Альтернативой вашей второй пуле также является 'not (.// text())'. Как показывает ваша последняя марка: есть много способов рассмотреть «ничто»;). – Abel

+0

Очень практично: проверить, что строка * не * пуста, вы можете просто проверить сама строка! 'if ($ mystring) then ... else ...' –

242

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

Как вы проверяете экземпляры ''? , пустые тесты строк не работают для этого – raffian

+2

Понятно, что вы включили несколько примеров, чтобы показать, как получается каждое выражение. – doubleJ

+0

@raffian: в XSLT или связанных с ним технологиях (XQuery, DOM, XDM, Schema и т. Д.) Конечные теги не рассматриваются как отдельные объекты. Вместо этого вы имеете дело только с узлами или элементами в этом случае, что является целым между начальным тегом и конечным тегом. Короче говоря, нет способа проверить для '', и нет необходимости в этом. – Abel

5

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

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

2

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

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

17

А что?

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

Это отлично работает. Даже когда есть комментарий внутри '' и в противном случае нет значимого текста, это все равно оценивает значение 'true' – rustyx

8

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

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

Страшно. Что делать, если есть несколько пользователей или несколько первых имен? Используйте 'xsl: apply-templates' и соответствующие шаблоны, чтобы получить то, что вы хотите, намного проще. – Abel

2

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

Строковое значение пустого набора узлов (это то, что дает выражение XPath 'categoryName', когда нет дочерних элементов' categoryName' в текущем контексте) определяется как пустая строка, поэтому это избыточно - 'string -length (categoryName) 'равно нулю, если нет элементов' categoryName'. –

0

По моим опыт лучший путь:

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

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

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

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

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

+1

Поздравляем с упоминанием «* Программирование без if-ветвей *». Есть некоторые люди, которые не понимают важность этого. Для всех из них здесь есть ссылка на очень хороший курс Pluralsight по этой теме: «Шаблоны тактического дизайна в .NET: поток управления» от Zoran Horvat: https://app.pluralsight.com/library/courses/tactical -design-patterns-dot-net-control-flow/table-of-contents Обязательное чтение! –

2

Если узел не имеет значения доступного во входном XML, как показано ниже XPath, функция

<node> 
    <ErrorCode/> 
</node> 

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

string(/Node/ErrorCode) ='' 
0

Используйте простой CategoryName/текст() Такой тест отлично работает на <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> 
2

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

"Tactical Design Patterns in .NET: Control Flow"

+0

Привет, Dimitre, мне нужно ваше решение для версии 1.0, поэтому мне нужно закодировать его во всех тегах, которые у меня есть, или есть более простой способ импровизировать его для всего XML? – zyberjock

+0

@zyberjock. Непонятно, что вы просите. Пожалуйста, задайте вопрос и отправьте мне комментарий со ссылкой. Следуйте рекомендациям, как задать хороший вопрос. –

+0

Привет @Dimitre, я разместил вопрос здесь http://stackoverflow.com/questions/38150093/set-a-default-value-for-each-empty-xml-tags-in-xslt-1-0 – zyberjock

0

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

< XSL: когда тест = "строка длины (поле вы-хотите-на-тест) < 1">