2009-04-06 24 views
89

Dato questo semplificata formato dati:XPath per selezionare più tag

<a> 
    <b> 
     <c>C1</c> 
     <d>D1</d> 
     <e>E1</e> 
     <f>don't select this one</f> 
    </b> 
    <b> 
     <c>C2</c> 
     <d>D2</d> 
     <e>E1</e> 
     <g>don't select me</g> 
    </b> 
    <c>not this one</c> 
    <d>nor this one</d> 
    <e>definitely not this one</e> 
</a> 

Come ti selezionare tutti i C s, D s e E s che sono figli di B elementi?

In sostanza, qualcosa di simile:

a/b/(c|d|e) 

Nella mia situazione, invece di a/b/, la query che portano alla selezione coloro C, D, E nodi è in realtà abbastanza complesso quindi vorrei evitare facendo questo:

a/b/c|a/b/d|a/b/e 

È possibile?

risposta

150

One risposta corretta è:

/a/b/*[self::c or self::d or self::e] 

Do nota t hat questo

a/b/*[local-name()='c' or local-name()='d' or local-name()='e'] 

è sia troppo lungo e non corretta. Questa espressione XPath selezionerà i nodi come:

OhMy:c 

NotWanted:d 

QuiteDifferent:e 
+0

'o' non funziona su una for-each, avresti bisogno di usare una linea verticale invece '|' –

+5

@ Guasqueño, 'or' è un operatore logico - opera su due valori booleani. L'operatore XPath ** union ** '|' opera su due gruppi di nodi. Questi sono abbastanza diversi e ci sono casi d'uso specifici per ciascuno di essi. L'uso di '|' ** può ** risolvere il problema originale, ma risulta più lungo e complesso e difficile da comprendere per l'espressione XPath. L'espressione più semplice in questa risposta, che usa l'operatore 'or' produce il set di nodi desiderato e * può * essere specificato nell'attributo" select "di un'operazione' 'XSLT. Provalo. –

40

si può evitare la ripetizione con una prova di attributo invece:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e'] 

Contrariamente all'opinione antagonista di Dimitre, quanto sopra è non corretta in un vuoto in cui il PO non ha specificato l'interazione con gli spazi dei nomi. L'asse self:: è uno spazio dei nomi restrittivo, local-name() no. Se l'OP intende catturare c|d|e indipendentemente dallo spazio dei nomi (che suggerirei sia anche uno scenario probabile data la natura OR del problema), allora è "un'altra risposta che ha ancora voti positivi" che è errata.

Non si può essere definitivi senza definizione, anche se sono abbastanza felice di cancellare la mia risposta come genuinamente errata se l'OP chiarisce la sua domanda in modo tale da non essere corretto.

+0

mio * molto chiaramente fatto * punto è che né tu né io possiamo essere definitiva, e che la tua downvote è fuori luogo dato che la mia risposta non è a titolo definitivo sbagliato. Il fatto che l'OP accetti una risposta è irrilevante, dal momento che non può accettarli entrambi, entrambi funzioneranno nella maggior parte dei casi, e il mio è stato cancellato in quel momento. – annakata

+3

Inoltre, sto dicendo che contestiamo i tuoi cosiddetti "fatti", ed è * mia * opinione che tu sia trasparente in modo antagonistico. Qual è lo scopo dei tuoi commenti "ha ancora voti positivi" e "Spiego perché quello che è più votato al momento non è corretto" serve? – annakata

+0

No, no, non può essere determinato con precisione - Ho detto più volte ora: entrambi potrebbero essere corretti, entrambi sono funzionali su un semplice documento, dipende interamente da ciò che l'OP vuole dal namespace. Sembri volutamente ignorante di questo, forse perché potrebbe metterti nel torto? – annakata

-2

Non sono sicuro se questo aiuta, ma con XSL, mi piacerebbe fare qualcosa di simile:

<xsl:for-each select="a/b"> 
    <xsl:value-of select="c"/> 
    <xsl:value-of select="d"/> 
    <xsl:value-of select="e"/> 
</xsl:for-each> 

e questo XPath non voglio selezionare tutti i figli dei nodi B:

a/b/* 
+0

Grazie Calvin, ma non sto usando XSL, e ci sono in realtà più elementi sotto B che non voglio selezionare. Aggiornerò il mio esempio per essere più chiaro. – nickf

+0

Oh, beh in quel caso annakata sembra avere la soluzione. – Calvin

11

Perché non a/b/(c|d|e)? Ho appena provato con Saxon XML library (racchiuso bene con un po 'di qualità Clojure), e sembra funzionare. abc.xml è il documento descritto da OP.

(require '[saxon :as xml]) 
(def abc-doc (xml/compile-xml (slurp "abc.xml"))) 
(xml/query "a/b/(c|d|e)" abc-doc) 
=> (#<XdmNode <c>C1</c>> 
    #<XdmNode <d>D1</d>> 
    #<XdmNode <e>E1</e>> 
    #<XdmNode <c>C2</c>> 
    #<XdmNode <d>D2</d>> 
    #<XdmNode <e>E1</e>>) 
+4

Sì, ma è XPath 2.0 –

+1

@ Alejandro, bello! Sono stato via (beatamente) dal mondo XML per 4 anni, sembra che XPath sia passato a 2.0 :) –

+0

Questo ha funzionato bene per me. Sembra che XPath 2.0 sia l'impostazione predefinita per l'analisi HTML in lxml su Python 2. –

Problemi correlati