Vérifiez 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 unlors 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>
14 réponses
test="categoryName != ''"
Edit : cela couvre l'interprétation la plus probable, à mon avis, de "[not] null or empty" comme déduit de la question, y compris son pseudo-code et ma propre expérience avec XSLT. C'est-à-dire " quel est L'équivalent de Java suivant?":
!(categoryName == null || categoryName.equals(""))
Pour plus de détails, par exemple, identifier distinctement null vs. empty, voir la réponse de johnvey ci-dessous et / ou le XSLT 'fiddle' j'ai adapté de cette réponse, qui inclut L'option dans Michael Kay commentaire ainsi que la sixième interprétation possible.
En L'absence de toute autre information, je suppose que le 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 serait:
<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 Élément Vide:
Pour tester si la valeur d'un certain nœud est vide
Cela dépend de ce que vous entendez par vide.
- ne contient pas de nœuds enfants:
not(node())
- ne contient pas de texte:
not(string(.))
- ne contient aucun texte autre que des espaces:
not(normalize-space(.))
- ne contient que des commentaires:
not(node()[not(self::comment())])
Les deux premiers traitent la valeur null et les deux seconds traitent 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>
Dans certains cas, vous voudrez peut-être savoir quand la valeur est spécifiquement null, ce qui est particulièrement nécessaire lors de l'utilisation de XML qui a été sérialisé à partir d'objets.net. Bien 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", donc vous ne pouvez pas différencier.
<group>
<item>
<id>item 1</id>
<CategoryName xsi:nil="true" />
</item>
</group>
Vous pouvez donc 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 à say Javascript
<xsl:if test="CategoryName">
Hello World.
</xsl:if>
Retourne true pour un élément null.
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 de 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, je suppose qu'il peut y avoir zéro, vide, unique ou multiple categoryName
éléments. Traiter tous ces cas en utilisant des constructions de style xsl:choose
, ou en d'autres termes, impérativement, est rapidement se salir (encore plus si les éléments peuvent être à différents niveaux!). Un idiome de programmation typique dans XSLT utilise des modèles (d'où le T dans XSLT), qui est une programmation déclarative, pas impérative(vous ne dites pas au processeur quoi faire, vous dites simplement ce que vous voulez sortir si certaines conditions sont remplies). Pour ce cas d'utilisation, cela peut ressembler à ce qui suit:
<!-- 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 (elle a un prédicat). Le modèle de correspondance" fall-through", le second, attrape tout ce qui n'est pas valide. Le troisième prend alors soin de sortir la valeur categoryName
de manière appropriée.
Notez que dans ce scénario, il n'est pas nécessaire de faire correspondre spécifiquement categories
ou category
, car le processeur traitera automatiquement tous les enfants, sauf si nous lui disons le contraire (dans cet exemple, les deuxième et troisième modèles ne traitent pas les enfants, car il n'y a pas de xsl:apply-templates
).
Ce l'approche est plus facilement extensible que l'approche impérative, car elle traite automatiquement de plusieurs catégories et peut être étendue pour d'autres éléments ou exceptions en ajoutant simplement un autre modèle correspondant. Programmation sans si-branches.
Note: il n'y a pas de null
en XML. Il y a xsi: nil , mais cela est rarement utilisé, surtout rarement dans les scénarios non typés sans un schéma quelconque.
S'il y a une possibilité que l'élément n'existe pas dans le XML, je testerais à 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) > 0">
<xsl:value-of select="categoryName " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other" />
</xsl:otherwise>
</xsl:choose>
Si un nœud n'a pas de valeur disponible dans le xml d'entrée comme ci-dessous xpath,
<node>
<ErrorCode/>
</node>
La fonction String() se convertit en valeur vide. Donc, cela fonctionne bien:
string(/Node/ErrorCode) =''
Quelque chose comme ça fonctionne 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 Vérifiez pas les valeurs null ou ne gérez pas les valeurs null, IE7 renvoie -2147483648 au lieu de NaN.
Comment puis-je vérifier si une valeur est nulle ou vide avec XSL?
Par exemple, si
categoryName
est vide?
C'est probablement L'expression XPath la plus simple (celle de la réponse acceptée fournit un test pour le contraire, et serait plus longue, si elle est 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 tel) categoryName
enfant a une valeur de chaîne - la chaîne vide.
J'utilise unlors 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
Lorsqu'il est appliqué sur ce XML document :
<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 joli cours Pluralsight:
"modèles de conception tactique dans. NET: flux de contrôle"
Par mon expérience, le meilleur moyen est:
<xsl:when test="not(string(categoryName))">
<xsl:value-of select="other" />
</xsl:when>
<otherwise>
<xsl:value-of select="categoryName" />
</otherwise>
Utilisez simple categoryName / text() tel test fonctionne bien sur <categoryName/>
et aussi <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>
En fait, je l'ai trouvé mieux que de tester la longueur de la chaîne car plusieurs fois le champ n'est pas null, juste vide