web-dev-qa-db-fra.com

Vérifier si une chaîne est nulle ou vide dans XSLT

Comment puis-je vérifier si une valeur est nulle ou vide avec XSL ?

Par exemple, si categoryName est vide? J'utilise un lors du choix de la construction .

Par exemple:

<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>
315
raklos
test="categoryName != ''"

Edit : Ceci couvre l'interprétation la plus probable, à mon avis, de "[pas] null ou vide" comme déduit de la question, y compris son pseudo- code et ma propre première expérience avec XSLT. Par exemple, "Quel est l'équivalent du Java suivant?":

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

Pour plus de détails, par exemple, identifiant distinctement null vs vide, voir réponse de johnvey ci-dessous et/ou le 'violon' XSLT J'ai adapté cette réponse, qui inclut l'option dans le commentaire de Michael Kay ainsi que la sixième interprétation possible.

315
steamer25

En l'absence de toute autre information, je supposerai le code XML suivant:

<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 exemple de cas d'utilisation ressemblerait à ceci:

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

De élément vide:

Pour tester si la valeur d'un certain noeud est vide

Cela dépend de ce que vous entendez par vide.

  • Ne contient aucun nœud enfant: not(node())
  • Ne contient pas de contenu textuel: not(string(.))
  • Ne contient pas de texte autre que des espaces: not(normalize-space(.))
  • Ne contient rien sauf des commentaires: not(node()[not(self::comment())])
63
Chris Doggett

Qu'en est-il de?

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

Les deux premiers traitent de la valeur null et les deux autres de la chaîne vide.

<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>
9
Aleksandar Borkovac

Dans certains cas, vous voudrez peut-être savoir quand la valeur est spécifiquement nulle, ce qui est particulièrement nécessaire lors de l'utilisation de XML sérialisé à partir d'objets .NET. Alors que la réponse acceptée fonctionne pour cela, elle renvoie également le même résultat lorsque la chaîne est vide ou vide, c'est-à-dire '', de sorte que vous ne pouvez pas différencier.

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

Ainsi, vous pouvez simplement tester l'attribut.

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

Parfois, il est nécessaire de connaître l'état exact et vous ne pouvez pas simplement vérifier si CategoryName est instancié, car contrairement à Javascript

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

Reviendra true pour un élément null.

6
DustJones

Comment puis-je vérifier si une valeur est nulle ou vide avec XSL?

Par exemple, si categoryName est vide?

Ceci est probablement l'expression XPath la plus simple (celle dans la réponse acceptée fournit un test pour le contraire, et serait plus longue si elle était annulée):

not(string(categoryName))

Explication :

L'argument de la fonction not() ci-dessus est false() exactement quand il n'y a pas categoryName enfant ("null") de l'élément de contexte, ou le (unique) categoryName enfant a une valeur de chaîne - la chaîne vide.

J'utilise un lors du choix de la construction .

Par exemple:

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

Dans XSLT 2.0, utilisez :

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

Voici un exemple complet :

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

Lorsque cette transformation est appliquée sur le document XML suivant:

<categoryName>X</categoryName>

le résultat voulu et correct est produit :

X

Appliqué à ce document XML :

<categoryName></categoryName>

ou sur ceci:

<categoryName/>

ou sur ce

<somethingElse>Y</somethingElse>

le résultat correct est produit :

Other

De même, utilisez cette transformation 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>

Remarque : Aucune condition n'est utilisée. En savoir plus sur l'importance d'éviter les constructions conditionnelles dans ce cours Nice Pluralsight:

"( Modèles de conception tactiques dans .NET: Flux de contrôle "

4
Dimitre Novatchev

Je sais que cette question est ancienne, mais entre toutes les réponses, il me manque une approche commune pour ce cas d'utilisation dans le développement XSLT.

J'imagine que le code manquant dans l'OP ressemble à ceci:

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

Et que l'entrée ressemble à ceci:

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

C'est-à-dire que je suppose qu'il peut y avoir zéro, vide, un ou plusieurs éléments categoryName. Traiter tous ces cas en utilisant des constructions de style xsl:choose-, ou en d'autres termes, impérativement, devient vite compliqué (encore plus si les éléments peuvent être à différents niveaux!). Un langage de programmation typique dans XSLT utilise des modèles (d'où le T dans XSLT), qui est une programmation déclarative et non impérative (vous ne dites pas au processeur quoi faire, vous dites simplement ce que vous voulez obtenir si certaines conditions sont remplies). Pour ce cas d'utilisation, cela peut ressembler à ceci:

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

Cela fonctionne (avec n'importe quelle version XSLT), car la première ci-dessus a une priorité plus élevée (il a un prédicat). Le modèle correspondant "tombant à travers", le second, capture tout ce qui n'est pas valide. Le troisième prend ensuite en charge la sortie de la valeur categoryName de manière appropriée.

Notez que dans ce scénario, il n’est pas nécessaire de faire une correspondance spécifique categories ou category, car le processeur traite automatiquement tous les enfants, sauf indication contraire de notre part (dans cet exemple, les deuxième et troisième modèles ne traiter ensuite les enfants, car il n’ya pas de xsl:apply-templates).

Cette approche est plus facilement extensible que l’approche impérative, car elle traite automatiquement plusieurs catégories et elle peut être étendue à d’autres éléments ou exceptions en ajoutant simplement un autre modèle correspondant. Programmation sans if-branches .

Remarque: null n'existe pas en XML. Il existe xsi: nil , mais cela est rarement utilisé, en particulier dans des scénarios non typés sans schéma quelconque.

4
Abel

S'il existe une possibilité que l'élément n'existe pas dans le XML, je vérifierais à la fois que l'élément est présent et que la longueur de chaîne est supérieure à zéro:

<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>
4
Marie Taylor

Si un noeud n'a pas de valeur disponible dans l'entrée XML comme ci-dessous xpath,

<node>
    <ErrorCode/>
</node>

la fonction string () est convertie en valeur vide. Donc ça marche bien:

string(/Node/ErrorCode) =''
3
Sanjeev Singh

Quelque chose comme ça marche pour moi:

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

Ou l'inverse:

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

Remarque: Si vous ne cochez pas les valeurs NULL et ne les gérez pas, IE7 renvoie -2147483648 au lieu de NaN.

2
HSol

En fait, je l'ai trouvé mieux en testant la longueur de la chaîne, car plusieurs fois le champ n'est pas nul, mais vide

<xsl: when test = "longueur de chaîne (champ que vous voulez tester) <1">

1
Pedro Pereira

D'après mon expérience, le meilleur moyen est de:

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

Utilisez simple categoryName/text () Ce test fonctionne très bien sur <categoryName/> ainsi que <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>
0
Jaroslav Kubacek