XPath test, jeśli wartość węzła to liczba

89

Jak mogę sprawdzić, czy wartość węzła jest liczbą przy użyciu XPath?

Jakieś pomysły?

Harold Sota
źródło

Odpowiedzi:

124

Przetestuj wartość względem NaN :

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

To jest krótsza wersja (dzięki @Alejandro ):

<xsl:if test="number(myNode) = myNode">
    <!-- myNode is a number -->
</xsl:if>
Oded
źródło
10
Ponieważ w XPath 1.0 NaNwartość typu danych liczba nie jest równa żadnej wartości liczbowej i dla porównania, jeśli co najmniej jeden argument to liczba wpisana, drugi jest rzutowany na liczbę, jest to test najkrótszej liczby:number(MyNode)=MyNode
10
Krótka wersja autorstwa @Alejandro całkowicie zawodzi z XPath 2.0 z powodu niezgodności typów w operatorze = ( Required item type of first operand of '=' is numeric; supplied value has item type xs:string;), rozwiązanie Dimitre działa jednak dobrze.
Lucero
61

Najkrótszym możliwym sposobem sprawdzenia, czy wartość zawarta w zmiennej $vmoże być użyta jako liczba, to :

number($v) = number($v)

Wystarczy zastąpić $vpowyższe wyrażenie, którego wartość chcesz przetestować.

Wyjaśnienie :

number($v) = number($v)jest oczywiście prawdą, jeśli $vjest liczbą lub łańcuchem reprezentującym liczbę.

Dotyczy to również wartości logicznej, ponieważ a number(true())wynosi 1 i number(false)wynosi 0.

Ilekroć $vnie można użyć jako liczby, number($v)oznacza to NaN

a NaN nie jest równe żadnej innej wartości, nawet sobie.

Zatem powyższe wyrażenie jest prawdziwe tylko dla $vktórego wartość może być użyta jako liczba, a fałsz w przeciwnym razie.

Dimitre Novatchev
źródło
1
+1 pomocne wyjaśnienie. Czy ktoś może skomentować przypadki, w których number($v) = number($v)daje inny wynik number($v) = $v?
LarsH
@LarsH: Już skomentowałem te przypadki. Czy możesz wskazać jeszcze nie omówiony przypadek?
Dimitre Novatchev
Chodziło mi o to, czy ktoś mógłby wymienić przypadki, w których number($v) = number($v)daje inny wynik number($v) = $v? Bez wątpienia można to wyprowadzić z tego, co napisałeś, ale nie widzę, gdzie bezpośrednio odniosłeś się do tego pytania. Przepraszam, jeśli jestem gęsty. IOW, czy Twoje rozwiązanie i rozwiązanie @ Oded / @ Alejandro zawsze dają takie same wyniki?
LarsH
@LarsH: Nie patrzyłem na rozwiązanie Odeda, ponieważ jest to oczywiście coś, czego nie chciałbym używać. Myślę, że rozwiązanie Al2jandro i moje rozwiązanie dają te same odpowiedzi dla dowolnej wartości $ v
Dimitre Novatchev
1
@EricS, Wygląda na to, że można uzyskać dostęp do standardu IEEE tylko poprzez jego zakup ... Byt spójrz tutaj: cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF . W szczególności ten akapit: „IEEE 754 przypisuje wartości do wszystkich wyrażeń relacyjnych zawierających NaN. W składni C predykat x! = Y jest True, ale wszystkie inne, x <y, x <= y, x == y, x> = y i x> y, są fałszywe, gdy x lub y lub oba są NaN "
Dimitre Novatchev
18

W XPath 2.0 jest niesamowity operator testu typu, którego możesz użyć:

<xsl:if test="$number castable as xs:double">
    <!-- implementation -->
</xsl:if>
kształtny
źródło
15

Nie próbuję przedstawić innego alternatywnego rozwiązania, ale „meta spojrzenie” na ten problem.

Odpowiedzi udzielone już przez Odeda i Dimitre Novatcheva są poprawne, ale to, co ludzie naprawdę mogliby mieć na myśli, mówiąc „wartość to liczba”, jest, jak bym to powiedział, otwarte na interpretację.

W pewnym sensie wszystko sprowadza się do tego dziwnie brzmiącego pytania: „jak chcesz wyrazić swoje wartości liczbowe?”

Funkcja XPath number()przetwarza liczby, które mają

  • możliwe początkowe lub końcowe spacje
  • znak poprzedzający tylko dla wartości ujemnych
  • kropka jako separator dziesiętny (opcjonalnie dla liczb całkowitych)
  • wszystkie inne znaki z zakresu [0–9]

Zauważ, że nie obejmuje to wyrażeń dla wartości liczbowych that

  • są wyrażone w formie wykładniczej (np. 12.3E45)
  • może zawierać znak dla wartości dodatnich
  • rozróżnia dodatnie i ujemne zero
  • zawiera wartość dodatniej lub ujemnej nieskończoności

To nie są tylko wymyślone kryteria. Element, którego treść jest zgodna ze schematem, ma prawidłową xs:floatwartość, może zawierać dowolną z wyżej wymienionych cech. Jednak number()zwróci wartość NaN.

Zatem odpowiedz na pytanie „Jak mogę sprawdzić za pomocą XPath, czy wartość węzła to liczba?” to „Użyj już wspomnianych rozwiązań używając number()” lub „z pojedynczym wyrażeniem XPath 1.0, nie możesz”. Pomyśl o możliwych formatach liczb, które możesz napotkać, i jeśli to konieczne, napisz jakąś logikę do walidacji / analizowania liczb. W ramach przetwarzania XSLT można to zrobić na przykład za pomocą kilku odpowiednich dodatkowych szablonów.

PS. Jeśli zależy Ci tylko na liczbach niezerowych, najkrótszy test to

<xsl:if test="number(myNode)">
    <!-- myNode is a non-zero number -->
</xsl:if>
jasso
źródło
1
+1 Dobre szczegółowe wyjaśnienie kwestii stojących za pytaniem: co OP mógł oznaczać lub miałby na myśli, gdyby wiedział, o co zapytać.
LarsH
9

Ten, który uznałem za bardzo przydatny, jest następujący:

<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
źródło
2

Zawsze możesz użyć czegoś takiego:

string(//Sesscode) castable as xs:decimal

castable jest udokumentowane przez W3C tutaj .

Martti
źródło
1

Miałem do czynienia z 01 - który jest liczbą.

string(number($v)) != string($v) dokonuje segregacji

Florimond
źródło