Teste XPath se o valor do nó é um número

89

Como posso verificar se um valor de nó é um número usando XPath?

Alguma ideia?

Harold Sota
fonte

Respostas:

124

Teste o valor contra NaN :

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

Esta é uma versão mais curta (obrigado @Alejandro ):

<xsl:if test="number(myNode) = myNode">
    <!-- myNode is a number -->
</xsl:if>
Oded
fonte
10
Como no XPath 1.0 o NaNvalor do tipo de dados numéricos não é igual a nenhum valor numérico e, para comparação, se pelo menos um argumento for dado numérico digitado, o outro é convertido em número, este é o teste de número mais curto:number(MyNode)=MyNode
10
A versão curta de @Alejandro falha completamente com XPath 2.0 devido à incompatibilidade de tipo no operador = ( Required item type of first operand of '=' is numeric; supplied value has item type xs:string;), a solução de Dimitre funciona bem, entretanto.
Lucero
60

A maneira mais curta possível de testar se o valor contido em uma variável $vpode ser usado como um número é :

number($v) = number($v)

Você só precisa substituir o $vacima pela expressão cujo valor você deseja testar.

Explicação :

number($v) = number($v)é obviamente verdadeiro, se $vfor um número ou uma string que representa um número.

Isso também vale para um valor booleano, porque a number(true())é 1 e number(false)é 0.

Sempre $vque não puder ser usado como um número, number($v)será NaN

e NaN não é igual a nenhum outro valor, nem mesmo a si mesmo.

Assim, a expressão acima é verdadeira apenas para $vcujo valor pode ser usado como um número, e falsa caso contrário.

Dimitre Novatchev
fonte
1
1 explicação útil. Alguém pode comentar sobre os casos em que number($v) = number($v)produz um resultado diferente number($v) = $v?
LarsH
@LarsH: Eu já comentei esses casos. Você pode apontar um caso ainda não discutido?
Dimitre Novatchev,
Eu quis dizer que alguém poderia listar os casos em que number($v) = number($v)produz um resultado diferente de number($v) = $v? Sem dúvida, isso pode ser derivado do que você escreveu, mas não estou vendo onde você abordou essa questão explicitamente. Desculpe se estou sendo estúpido. IOW, sua solução e a solução de @Oded's / @Alejandro sempre produzem os mesmos resultados?
LarsH
@LarsH: Eu não olhei para a solução do Oded porque obviamente é algo que eu não gostaria de usar. Acho que a solução do Al2jandro e a solução da mina dão as mesmas respostas para qualquer valor de $ v
Dimitre Novatchev
1
@EricS, Parece que só se pode acessar o padrão IEEE comprando-o ... Mas dê uma olhada aqui: cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF . Em particular, este parágrafo: "IEEE 754 atribui valores a todas as expressões relacionais envolvendo NaN. Na sintaxe de C, o predicado x! = Y é Verdadeiro, mas todos os outros, x <y, x <= y, x == y, x> = y e x> y, são falsos sempre que x ou y ou ambos são NaN "
Dimitre Novatchev
18

Há um operador de teste de tipo incrível no XPath 2.0 que você pode usar:

<xsl:if test="$number castable as xs:double">
    <!-- implementation -->
</xsl:if>
shapiy
fonte
15

Não estou tentando fornecer outra solução alternativa, mas uma "metavisualização" para esse problema.

As respostas já fornecidas por Oded e Dimitre Novatchev estão corretas, mas o que as pessoas realmente querem dizer com a frase "valor é um número" está, como eu diria, aberto à interpretação.

De certa forma, tudo se resume a esta pergunta que soa bizarra: "como você deseja expressar seus valores numéricos?"

A função XPath number()processa números que têm

  • possível espaço em branco à esquerda ou à direita
  • caractere de sinal precedente apenas em valores negativos
  • ponto como separador decimal (opcional para inteiros)
  • todos os outros caracteres do intervalo [0-9]

Observe que isso não inclui expressões para valores numéricos que

  • são expressos na forma exponencial (por exemplo, 12.3E45)
  • pode conter caractere de sinal para valores positivos
  • tem uma distinção entre zero positivo e negativo
  • incluir valor para infinito positivo ou negativo

Estes não são apenas critérios inventados. Um elemento com conteúdo que está de acordo com o esquema um xs:floatvalor válido pode conter qualquer uma das características mencionadas acima. No entanto number(), retornaria valor NaN.

Portanto, responda à sua pergunta "Como posso verificar com XPath se um valor de nó é um número?" é "Usar soluções já mencionadas usando number()" ou "com uma única expressão XPath 1.0, você não pode". Pense nos possíveis formatos de número que você pode encontrar e, se necessário, escreva algum tipo de lógica para validação / análise de número. No processamento XSLT, isso pode ser feito com alguns modelos extras adequados, por exemplo.

PS. Se você só se preocupa com números diferentes de zero, o teste mais curto é

<xsl:if test="number(myNode)">
    <!-- myNode is a non-zero number -->
</xsl:if>
jasso
fonte
1
+1 Boa explicação detalhada das questões por trás da pergunta: o que o OP poderia ter significado ou teria significado se ele soubesse o que perguntar.
LarsH
9

O que achei muito útil é o seguinte:

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

Você sempre pode usar algo assim:

string(//Sesscode) castable as xs:decimal

O castable é documentado pelo W3C aqui .

Martti
fonte
1

Tenho lidado com 01 - que é um numérico.

string(number($v)) != string($v) faz a segregação

Florimond
fonte