Pregunta

¿Cómo puedo comprobar si un valor es nulo o vacío con XSL?

Por ejemplo, si categoryName está vacía?Estoy usando un cuando la elección de construir.

Por ejemplo:

<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>
¿Fue útil?

Solución

test="categoryName != ''"

Editar : Esto cubre la interpretación más probable, en mi opinión, de " [no] nulo o vacío " como se infiere de la pregunta, incluido su pseudocódigo y mi propia experiencia inicial con XSLT. Es decir, & Quot; ¿Cuál es el equivalente del siguiente Java? & Quot ;:

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

Para obtener más detalles, por ejemplo, identificar claramente nulo frente a vacío, consulte la respuesta de johnvey a continuación y / o el 'violín' XSLT que he adaptado de esa respuesta, que incluye la opción en el comentario de Michael Kay y la sexta posible interpretación.

Otros consejos

En ausencia de cualquier otra información, asumiré el siguiente 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>

Un ejemplo de caso de uso se vería así:

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

De Elemento vacío :

Para probar si el valor de un determinado nodo está vacío

Depende de lo que quieras decir con vacío.

  • No contiene nodos secundarios: not(node())
  • No contiene contenido de texto: not(string(.))
  • No contiene ningún texto que no sea espacio en blanco: not(normalize-space(.))
  • No contiene nada excepto comentarios: not(node()[not(self::comment())])

¿Qué pasa?

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

Los primeros dos tratan con un valor nulo y los segundos dos tratan con una cadena vacía.

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

En algunos casos, es posible que desee saber cuándo el valor es específicamente nulo, lo cual es particularmente necesario cuando se utiliza XML que se ha serializado a partir de objetos .NET. Si bien la respuesta aceptada funciona para esto, también devuelve el mismo resultado cuando la cadena está en blanco o vacía, es decir, '', por lo que no puede diferenciar.

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

Para que pueda simplemente probar el atributo.

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

A veces es necesario saber el estado exacto y no se puede simplemente verificar si se crea una instancia de CategoryName, porque a diferencia de decir Javascript

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

Devuelve verdadero para un elemento nulo.

Si existe la posibilidad de que el elemento no exista en el XML, probaría que el elemento está presente y que la longitud de la cadena es mayor que cero:

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

Sé que esta pregunta es antigua, pero entre todas las respuestas, echo de menos una que es un enfoque común para este caso de uso en el desarrollo de XSLT.

Me imagino que el código faltante del OP se parece a esto:

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

Y que la entrada se ve así:

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

Es decir, supongo que puede haber cero, elementos vacíos, únicos o múltiples categoryName. Tratar todos estos casos usando construcciones de estilo xsl:choose, o en otras palabras, imperativamente, se está volviendo desordenado rápidamente (¡más aún si los elementos pueden estar en diferentes niveles!). Un lenguaje de programación típico en XSLT es usar plantillas (de ahí la T en XSLT), que es programación declarativa, no imperativa (no le dices al procesador qué hacer, solo dices lo que quieres que salga si se cumplen ciertas condiciones). Para este caso de uso, puede tener un aspecto similar al siguiente:

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

Esto funciona (con cualquier versión XSLT), porque el primero de arriba tiene una precedencia más alta (tiene un predicado). El & Quot; fall-through & Quot; la plantilla coincidente, la segunda, captura cualquier cosa que no sea válida. El tercero se encarga de generar el valor categories de manera adecuada.

Tenga en cuenta que en este escenario no hay necesidad de hacer coincidir específicamente category o xsl:apply-templates, porque el procesador procesará automáticamente a todos los elementos secundarios, a menos que le indiquemos lo contrario (en este ejemplo, la segunda y tercera plantilla no siguen procesar a los hijos, porque no hay null en ellos).

Este enfoque es más fácil de extender que el enfoque imperativo, ya que trata automáticamente con múltiples categorías y puede expandirse para otros elementos o excepciones simplemente agregando otra plantilla coincidente. Programación sin ramas if .

Nota: no hay tal cosa como <=> en XML. Hay xsi: nil , pero eso rara vez se usa, especialmente raramente en sin tipo escenarios sin un esquema de algún tipo.

  

¿Cómo puedo verificar si un valor es nulo o está vacío con XSL?

     

Por ejemplo, si categoryName está vacío?

Esta es probablemente la expresión XPath más simple (la respuesta aceptada proporciona una prueba para lo contrario, y sería más larga, si se niega):

not(string(categoryName))

Explicación :

El argumento para la función not() anterior es false() exactamente cuando no hay <=> hijo (" nulo ") del elemento de contexto, o el (solo tal) < => child tiene un valor de cadena: la cadena vacía.

  

Estoy usando un al elegir construcción.

     

Por ejemplo:

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

En XSLT 2.0 use :

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

Aquí hay un ejemplo completo :

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

Cuando esta transformación se aplica en el siguiente documento XML:

<categoryName>X</categoryName>

se produce el resultado deseado y correcto :

X

Cuando se aplica en este documento XML :

<categoryName></categoryName>

o sobre esto:

<categoryName/>

o sobre esto

<somethingElse>Y</somethingElse>

se produce el resultado correcto :

Other

Del mismo modo, use esta transformación 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>

Nota : no se utilizan condicionales en absoluto. Obtenga más información sobre la importancia de evitar construcciones condicionales en este agradable curso de Pluralsight:

quot; Patrones de diseño táctico en .NET: Control Flow "

Si un nodo no tiene ningún valor disponible en la entrada xml como debajo de xpath,

<node>
    <ErrorCode/>
</node>
La función

string () se convierte en valor vacío. Entonces esto funciona bien:

string(/Node/ErrorCode) =''

Algo como esto funciona para mí:

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

O al revés:

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

Nota: Si no verifica valores nulos o maneja valores nulos, IE7 devuelve -2147483648 en lugar de NaN.

En realidad, lo encontré mejor solo probando la longitud de la cadena ya que muchas veces el campo no es nulo, solo está vacío

  

< xsl: when test = " string-length (field-you-want-to-test) < 1 " >

Según mi experiencia, la mejor manera es:

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

Uso simple nombrecategoría/text() esta prueba funciona bien en <categoryName/> y también <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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top