Test XPath si la valeur du nœud est un nombre

89

Comment puis-je vérifier si une valeur de nœud est un nombre à l'aide de XPath?

Des idées?

Harold Sota
la source

Réponses:

124

Testez la valeur par rapport à NaN :

<xsl:if test="string(number(myNode)) != 'NaN'">
    <!-- myNode is a number -->
</xsl:if>

Ceci est une version plus courte (merci @Alejandro ):

<xsl:if test="number(myNode) = myNode">
    <!-- myNode is a number -->
</xsl:if>
Oded
la source
10
Parce que dans XPath 1.0, la NaNvaleur du type de données numérique n'est pas égale à une valeur numérique et, à des fins de comparaison, si au moins un argument est des données numériques tapées, l'autre est converti en nombre, c'est le test de nombre le plus court:number(MyNode)=MyNode
10
La version courte de @Alejandro échoue complètement avec XPath 2.0 en raison d'une incompatibilité de type sur l'opérateur = ( Required item type of first operand of '=' is numeric; supplied value has item type xs:string;), la solution de Dimitre fonctionne bien cependant.
Lucero
60

Le moyen le plus court possible de tester si la valeur contenue dans une variable $vpeut être utilisée comme un nombre est :

number($v) = number($v)

Il vous suffit de remplacer ce qui $vprécède par l'expression dont vous souhaitez tester la valeur.

Explication :

number($v) = number($v)est évidemment vrai, si $vest un nombre ou une chaîne qui représente un nombre.

C'est également vrai pour une valeur booléenne, car a number(true())vaut 1 et number(false)0.

Chaque fois $vqu'il ne peut pas être utilisé comme un nombre, number($v)NaN est

et NaN n'est égal à aucune autre valeur, même à lui-même.

Ainsi, l'expression ci-dessus n'est vraie que pour $vdont la valeur peut être utilisée comme un nombre, et fausse sinon.

Dimitre Novatchev
la source
1
+1 explication utile. Quelqu'un peut-il commenter des cas où number($v) = number($v)produit un résultat différent number($v) = $v?
LarsH
@LarsH: J'ai déjà commenté ces cas. Pouvez-vous signaler encore un cas non discuté?
Dimitre Novatchev
Je voulais dire que quelqu'un pourrait-il énumérer les cas où number($v) = number($v)produit un résultat différent number($v) = $v? Cela découle sans doute de ce que vous avez écrit, mais je ne vois pas où vous avez abordé cette question explicitement. Désolé si je suis dense. IOW, votre solution et celle de @ Oded / @ Alejandro donnent-elles toujours les mêmes résultats?
LarsH
@LarsH: Je n'ai pas regardé la solution d'Oded parce que c'est évidemment quelque chose que je n'aimerais pas utiliser. Je pense que la solution d'Al2jandro et la solution mienne donnent les mêmes réponses pour toute valeur de $ v
Dimitre Novatchev
1
@EricS, il semble que l'on ne puisse accéder au standard IEEE qu'en l'achetant ... Jetez un œil ici: cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF . En particulier, ce paragraphe: "IEEE 754 attribue des valeurs à toutes les expressions relationnelles impliquant NaN. Dans la syntaxe de C, le prédicat x! = Y est True mais tous les autres, x <y, x <= y, x == y, x> = y et x> y, sont faux chaque fois que x ou y ou les deux sont NaN "
Dimitre Novatchev
18

Il existe un opérateur de test de type incroyable dans XPath 2.0 que vous pouvez utiliser:

<xsl:if test="$number castable as xs:double">
    <!-- implementation -->
</xsl:if>
forme
la source
15

Je n'essaye pas de fournir une autre solution alternative, mais une "méta-vue" à ce problème.

Les réponses déjà fournies par Oded et Dimitre Novatchev sont correctes, mais ce que les gens pourraient vraiment vouloir dire par l'expression «la valeur est un nombre» est, comment dirais-je, ouvert à l'interprétation.

D'une certaine manière, tout se résume à cette question étrange: "comment voulez-vous exprimer vos valeurs numériques?"

La fonction XPath number()traite les nombres qui ont

  • espace blanc de début ou de fin possible
  • caractère de signe précédent uniquement sur les valeurs négatives
  • point comme séparateur décimal (facultatif pour les entiers)
  • tous les autres caractères de la plage [0-9]

Notez que cela n'inclut pas les expressions pour les valeurs numériques qui

  • sont exprimés sous forme exponentielle (par exemple 12.3E45)
  • peut contenir le caractère de signe pour les valeurs positives
  • avoir une distinction entre zéro positif et négatif
  • inclure une valeur pour l'infini positif ou négatif

Ce ne sont pas seulement des critères inventés. Un élément dont le contenu est selon le schéma une xs:floatvaleur valide peut contenir l'une des caractéristiques mentionnées ci-dessus. Pourtant number(), retournerait de la valeur NaN.

Alors répondez à votre question "Comment puis-je vérifier avec XPath si une valeur de nœud est un nombre?" est soit "Utiliser les solutions déjà mentionnées en utilisant number()" ou "avec une seule expression XPath 1.0, vous ne pouvez pas". Pensez aux formats de nombres possibles que vous pourriez rencontrer et, si nécessaire, écrivez une sorte de logique pour la validation / l'analyse des nombres. Dans le traitement XSLT, cela peut être fait avec quelques modèles supplémentaires appropriés, par exemple.

PS. Si vous ne vous souciez que des nombres non nuls, le test le plus court est

<xsl:if test="number(myNode)">
    <!-- myNode is a non-zero number -->
</xsl:if>
Jasso
la source
1
+1 Bonne explication détaillée des problèmes derrière la question: ce que le PO aurait pu signifier ou aurait signifié s'il avait su quoi demander.
LarsH
9

Celui que j'ai trouvé très utile est le suivant:

<xsl:choose>
  <xsl:when test="not(number(myNode))">
      <!-- myNode is a not a number or empty(NaN) or zero -->      
  </xsl:when>
  <xsl:otherwise>
      <!-- myNode is a number (!= zero) -->        
  </xsl:otherwise>
</xsl:choose>
jkpd
la source
2

Vous pouvez toujours utiliser quelque chose comme ceci:

string(//Sesscode) castable as xs:decimal

castable est documenté par le W3C ici .

Martti
la source
1

J'ai eu affaire à 01 - qui est un numérique.

string(number($v)) != string($v) fait la ségrégation

Florimond
la source