2012-04-24 13 views
11

Voglio creare un contatore in xquery. Il mio primo tentativo sembrava il seguente: risultatoAggiornamento contatore in XQuery

let $count := 0 
for $prod in $collection 
let $count := $count + 1 
return 
<counter>{$count }</counter> 

atteso:

<counter>1</counter> 
<counter>2</counter> 
<counter>3</counter> 

Risultato effettivo:

<counter>1</counter> 
<counter>1</counter> 
<counter>1</counter> 

Il $count sia omettendo di aggiornare o il reset variabile. Perché non posso riassegnare una variabile esistente? Quale sarebbe un modo migliore per ottenere il risultato desiderato?

risposta

6

variabili immutabili

XQuery è un functional programming language, che coinvolge tra gli altri variabili immutabili, in modo da Non è possibile modificare il valore di una variabile. D'altra parte, è disponibile una potente raccolta di funzioni, che risolve molti problemi di programmazione quotidiana.

let $count := 0 
for $prod in $collection] 
    let $count := $count + 1 
return 
<counter>{$count }</counter> 

let $count in linea 1 definisce questa variabile in ciascuno portata, che sono tutti seguendo le linee in questo caso. let $count nella riga 3 definisce un nuovo $count che è 0+1, valido in tutte le righe seguenti all'interno di questo blocco di codice - che non è definito. Quindi in effetti incrementi lo $count tre volte per uno, ma scarti immediatamente il risultato.

BaseX 'informazioni query mostra la versione ottimizzata di questa domanda che è

for $prod in $collection 
    return element { "counter" } { 1 } 

La soluzione

Per ottenere il numero totale di elementi in $collection, si può semplicemente utilizzare

return count($collection) 

Per un elenco delle funzioni XQuery, potresti dare un'occhiata allo XQuery part of functx che contiene sia un elenco di XQuery fun ctions e anche alcune altre utili funzioni che possono essere incluse come modulo.

19

Provare a utilizzare 'a':

for $d at $p in $collection 
return 
element counter { $p } 

Questo vi darà la posizione di ogni '$ d'. Se si desidera utilizzare questo insieme alla clausola order by, questo non funzionerà poiché la posizione è basata sull'ordine iniziale, non sul risultato di ordinamento. Per ovviare a ciò, basta salvare il risultato ordinato dell'espressione FLWOR in una variabile e utilizzare la clausola at in un secondo FLWOR che esegue semplicemente un'iterazione sul primo risultato ordinato.

let $sortResult := for $item in $collection 
        order by $item/id 
        return $item 

for $sortItem at $position in $sortResult 
return <item position="{$position}"> ... </item> 
+0

Grazie mille. Funziona bene per me. –

+0

Funziona anche per me Grazie amico! tu salvi il giorno! – axy108

6

Come ha detto @Ranon, tutti XQuery valori sono immutabili, quindi non è possibile aggiornare una variabile. Ma se si ha realmente bisogno di un numero aggiornabile (non dovrebbe essere troppo spesso), è possibile utilizzare la ricorsione:

declare function local:loop($seq, $count) { 
    if(empty($seq)) then() 
    else 
    let $prod := $seq[1], 
     $count := $count + 1 
    return (
     <count>{ $count }</count>, 
     local:loop($seq[position() > 1], $count) 
    ) 
}; 

local:loop($collection, 0) 

Questo si comporta esattamente come previsto con il vostro esempio.

In XQuery 3.0 una versione più generale di questa funzione è anche definita nella libreria standard: fn:fold-right($f, $zero, $seq)

che ha detto, nel tuo esempio si dovrebbe assolutamente utilizzare at $count come mostrato da @tohuwawohu.

6

Tutta la soluzione di cui sopra sono validi, ma vorrei ricordare che è possibile utilizzare l'estensione XQuery script per impostare i valori delle variabili:

variable $count := 0; 

for $prod in (1 to 10) 
return { 
    $count := $count + 1; 
    <counter>{$count}</counter> 
} 

Si può provare questo esempio, vivono a http://www.zorba-xquery.com/html/demo#twh+3sJfRpHhZR8pHhOdsmqOTvQ=

+1

È una cosa di XQuery 3.0? Probabilmente buono da menzionare. – derickson

+2

XQuery Scripting è un'estensione offerta da alcune implementazioni di XQuery. È particolarmente utile se si desidera eseguire contemporaneamente gli aggiornamenti e gli elementi di restituzione (ad esempio per i servizi Web), ma si evitano molte ottimizzazioni possibili. Dovresti attenersi a XQuery di base quando possibile. –

+0

L'esempio live è scaduto (404) :( –

2

Penso che si sta cercando qualcosa di simile:

XQUERY:

for $x in (1 to 10) 
return 
    <counter>{$x}</counter> 

USCITA:

<counter>1</counter> 
<counter>2</counter> 
<counter>3</counter> 
<counter>4</counter> 
<counter>5</counter> 
<counter>6</counter> 
<counter>7</counter> 
<counter>8</counter> 
<counter>9</counter> 
<counter>10</counter> 
4

Uso xdmp:set anziché la query di seguito

let $count := 0 
for $prod in (1 to 4) 
return (xdmp:set($count,number($count+1)) ,<counter>{$count }</counter>