2009-05-05 18 views
287

Come posso verificare se un valore è nullo o vuoto con XSL?Verifica se una stringa è nullo o vuota in XSLT

Ad esempio, se categoryName è vuoto? Sto usando un quando si sceglie il costrutto.

Ad esempio:

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

si può ampliare l'esempio di codice? –

+0

A seconda del caso d'uso, probabilmente non si vuole usare 'xsl: when' per i test del nodo. Considera ' ...' insieme a ' ...'. Il processore prenderà quindi le decisioni corrette per te e non avrai più bisogno di scrivere la logica di business in nidificato 'xsl: choose'. In molti casi, l'uso di modelli corrispondenti semplifica la scrittura di fogli di stile. – Abel

risposta

291
test="categoryName != ''" 

Edit: Questo copre l'interpretazione più probabile, a mio parere, di "[non] nullo o vuoto", come dedotto dalla questione, tra cui è pseudo -code e la mia esperienza iniziale con XSLT. Per esempio, "Che è l'equivalente dei seguenti Java?":

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

Per ulteriori dettagli EG, distintamente identificando nullo vs. vuoto, vedi johnvey's answer below e/o the XSLT 'fiddle' Ho adattato da quella risposta, che comprende la opzione nel commento di Michael Kay e nella sesta interpretazione possibile.

+14

La semantica dettagliata di questo test è: restituisce true se esiste almeno un elemento categoryName il cui valore di stringa è una stringa vuota. – jelovirt

+14

@jelovirt intendevi dire se esiste almeno un categoryName che NON è una stringa vuota? (Sono un principiante xsl, quindi perdona ogni potenziale stupidità alla mia domanda.) – joedevon

+7

Questa risposta, pur accettata e molto votata, è anche molto fuorviante. Dipende davvero da cosa intendi per "nullo o vuoto". Se vuoi un test che riesce se categoryName è assente o presente con un valore di lunghezza zero, dovresti usare 'test =" not (categoryName = '') "'.La risposta fornita restituirà false se l'elemento categoryName è assente, che nella mia interpretazione della domanda lo rende una risposta errata. –

56

Da Empty Element:

Per testare se il valore di un certo nodo è vuoto

Dipende cosa si intende per vuoto.

  • Non contiene nodi figlio: not(node())
  • non contiene alcun contenuto testuale: not(string(.))
  • non contiene alcun testo diverso dallo spazio: not(normalize-space(.))
  • non contiene nulla, tranne commenti: not(node()[not(self::comment())])
+2

+1. Alcune note Il primo punto elenco verifica anche il contenuto di testo, che è anche un nodo. Il secondo punto elenco verifica qualsiasi nodo di testo a qualsiasi profondità, se si desidera sapere se il nodo corrente non contiene testo, ma può contenere altri nodi, è possibile utilizzare 'not (text())'. Un'alternativa alla tua seconda pallottola è anche 'not (.// text())'. Come mostra il tuo ultimo proiettile: ci sono molti modi per considerare il "nulla";). – Abel

+0

Molto pratico: per verificare se una stringa è * non * vuota, puoi semplicemente testare la stringa stessa! 'if ($ mystring) then ... else ...' –

242

Assente di qualsiasi altre informazioni, assumerò il seguente codice XML:

<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 caso d'uso del campione sarebbe simile:

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

Come testare per istanze di ''? , test delle stringhe vuoti non funzionano per questo – raffian

+2

Apprezzato che hai incluso più esempi per mostrare come ogni espressione risulta. – doubleJ

+0

@raffian: in XSLT, o tecnologie correlate (XQuery, DOM, XDM, Schema ecc.), I tag finali non sono considerati entità separate. Invece, si tratta solo di nodi o elementi in questo caso, che è l'intero tra tag di inizio e tag di fine. In breve, non c'è modo di testare '', né è necessario. – Abel

5

In alcuni casi, si potrebbe desiderare di sapere quando il valore è specificamente nullo, che è particolarmente necessario quando si utilizza XML che è stato serializzato dal .NET oggetti. Sebbene la risposta accettata funzioni per questo, restituisce lo stesso risultato anche quando la stringa è vuota o vuota, cioè "", quindi non è possibile differenziare.

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

Così si può semplicemente provare l'attributo.

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

A volte è necessario conoscere l'esatto stato e non si può semplicemente verificare se NomeCategoria è istanziato, perché a differenza di dire Javascript

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

restituirà true per un elemento nullo.

2

Qualcosa di simile a questo funziona per me:

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

O viceversa:

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

Nota: se non si seleziona i valori nulli o gestire i valori nulli, IE7 restituisce -2147483648 invece di NaN.

17

Che dire?

test="not(normalize-space(categoryName)='')" 
+0

Funziona alla grande. Anche quando c'è un commento all'interno di '' e in caso contrario nessun testo significativo, questo vale ancora come 'true' – rustyx

8

Primi due accordi con valore null e secondo due con stringa vuota.

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

Scary. Cosa succede se ci sono più utenti o più nomi? Usa 'xsl: apply-templates' e i modelli corrispondenti per ottenere quello che vuoi, molto più facile. – Abel

2

Se c'è una possibilità che l'elemento non esiste nel codice XML ho iniziato ad esaminare sia che l'elemento è presente e che la stringa di lunghezza è maggiore di zero:

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

Il valore di stringa di un set di nodi vuoto (che è ciò che l'espressione XPath 'categoryName' fornisce quando non ci sono elementi figlio' categoryName' nel contesto corrente) è definito come stringa vuota, quindi è ridondante - 'stringa -length (categoryName) 'è zero se non ci sono elementi' categoryName'. –

0

Con la mia sperimentare il modo migliore è:

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

so che questa domanda è vecchio, ma tra tutte le risposte, mi manca uno che è un approccio comune per questo caso d'uso in fase di sviluppo XSLT.

sto immaginando che il codice mancante dalla OP simile a questa:

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

E che l'ingresso simile a questa:

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

Ie, suppongo non ci può essere pari a zero , vuoto, singolo o multiplo categoryName elementi. Affrontare tutti questi casi usando i costrutti dello stile xsl:choose o, in altre parole, imperativamente, diventa rapidamente disordinato (ancor più se gli elementi possono essere a livelli diversi!). Un tipico linguaggio di programmazione in XSLT è l'uso di modelli (da cui la T in XSLT), che è una programmazione dichiarativa, non imperativa (non si dice al processore cosa fare, basta dire quello che si vuole produrre se sono soddisfatte determinate condizioni). Per questo caso d'uso, che può essere simile a quanto segue:

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

questo funziona (con qualsiasi versione XSLT), perché il primo ha una precedenza più alta (ha un predicato) di cui sopra. Il modello di corrispondenza "fall-through", il secondo, prende tutto ciò che non è valido. Il terzo quindi si occupa di emettere il valore categoryName in modo corretto.

Si noti che in questo scenario non v'è alcuna necessità di abbinare specifially categories o category, perché il processore elabora automaticamente tutti i bambini, a meno che non diciamo altrimenti (in questo esempio, il secondo e il terzo modello di non elaborare ulteriormente i bambini , perché non c'è xsl:apply-templates in loro).

Questo approccio è più facilmente estendibile dell'approccio imperativo, poiché gestisce automaticamente più categorie e può essere espanso per altri elementi o eccezioni semplicemente aggiungendo un altro modello corrispondente. Programmazione senza if-branches.

Nota: non esiste una cosa come null in XML.C'è xsi:nil, ma questo è usato raramente, specialmente raramente in scenari non tipizzati senza uno schema di qualche tipo.

+1

Congratulazioni per aver menzionato "* Programmazione senza if-branch *". Ci sono alcune persone che non riescono a capire l'importanza di questo. Per tutti loro c'è un link a un corso Pluralsight molto bello su questo argomento: "* Modelli di progettazione tattica in .NET: Flusso di controllo *" di Zoran Horvat: https://app.pluralsight.com/library/courses/tactical -design-patterns-dot-net-control-flow/table-of-contents Una lettura obbligata! –

2

Se un nodo non ha alcun valore disponibile nel XML di input come sotto xpath, funzione

<node> 
    <ErrorCode/> 
</node> 

stringa() converte in valore vuoto. Quindi, questo funziona bene:

string(/Node/ErrorCode) ='' 
0

Utilizzo semplice categoryName/text() Tale test funziona bene su <categoryName/> e anche <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> 
2

Come si può verificare se un valore è nullo o vuoto con XSL?

Ad esempio, se categoryName è vuoto?

Questo è probabilmente l'espressione XPath più semplice (quello in risposta accettata prevede un test per l'opposto, e sarebbe più lungo, se negato):

not(string(categoryName)) 

Spiegazione:

L'argomento della funzione not() in alto è false() esattamente quando non c'è categoryName figlio ("null") dell'elemento di contesto o (singolo) categoryName figlio ha valore stringa - la stringa vuota.

sto usando un quando si sceglie costrutto.

Ad esempio:

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

In XSLT 2.0 uso:

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

Ecco un esempio completo:

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

Quando questa trasformazione viene applicata sul seguente documento XML:

<categoryName>X</categoryName> 

The Wanted, il risultato corretto viene prodotto:

X 

Quando applicato su questo documento XML:

<categoryName></categoryName> 

o su questo:

<categoryName/> 

o su questo

<somethingElse>Y</somethingElse> 

t egli risultato corretto è prodotto:

Other 

Allo stesso modo, utilizzare questo XSLT 1.0 trasformazione:

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

Do atto: Nessun condizionali vengono utilizzati affatto. Per saperne di più circa l'importanza di evitare costrutti condizionali in questo bel corso Pluralsight:

"Tactical Design Patterns in .NET: Control Flow"

+0

Ciao Dimitre, ho bisogno della tua soluzione per 1.0, quindi devo codificarlo in tutti i tag che ho o c'è un modo più semplice per implementarlo per l'intero XML? – zyberjock

+0

@zyberjock, Non è chiaro cosa stai chiedendo. Per favore, posta una domanda e mandami un commento con un link. Segui le linee guida su come fare una buona domanda. –

+0

Ciao @Dimitre, ho postato una domanda qui http://stackoverflow.com/questions/38150093/set-a-default-value-for-each-empty-xml-tags-in-xslt-1-0 – zyberjock

0

in realtà ho trovato meglio solo test per la lunghezza della corda dal momento che molte volte il campo non è nulla, solo vuoto

< xsl: quando la prova = "stringa di lunghezza (campo-you-want-to-test) < 1">

Problemi correlati