2010-10-13 13 views
15

Vorrei costruire una query XPath che restituisca un elemento "div" o "table", purché abbia un discendente contenente il testo "abc". L'unica avvertenza è che non può avere alcun div o discendenti della tabella.Query XPath con testo discendente e discendente() predicati

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

Quindi l'unico risultato corretto di questa query sarebbe:

/div/table/form/div 

mio miglior tentativo simile a questa:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)] 

ma non restituisce il risultato corretto.

Grazie per il vostro aiuto.

+0

Buona domanda, +1. Vedi la mia risposta per quella che è probabilmente la soluzione più breve. :) –

risposta

32

Qualcosa di diverso: :)

//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] 

Sembra molto più breve rispetto alle altre soluzioni, non è vero? :)

Tradotto in inglese semplice: Per ogni nodo di testo nel documento che contiene la stringa "abc" selezionare il suo primo antenato che è o un div o un table.

Questo è più efficiente, come solo una scansione completa dell'albero del documento (e non qualsiasi altro) è richiesto, e l'attraversamento ancestor::* è molto a buon mercato rispetto ad un (albero) scansione descendent::.

Per verificare che questa soluzione "funziona davvero":

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/> 
</xsl:template> 
</xsl:stylesheet> 

quando tale trasformazione viene effettuata sul documento XML fornito:

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

The Wanted, risultato corretto è prodotto:

<div> 
    <span> 
     <p>abcdefg</p> 
    </span> 
</div> 

Nota: Non è necessario utilizzare XSLT: qualsiasi host XPath 1.0, ad esempio DOM, deve ottenere lo stesso risultato.

+1

grazie per la risposta e grazie per il +1. Preferisco la compattezza di questa risposta, tuttavia non riesco a farlo funzionare nei miei test. Le altre due risposte a questa domanda funzionano per me. È possibile che ci sia un errore di battitura nella tua risposta? Non posso pretendere di capirlo tutto.Cosa fa [1]? Ancora una volta, se avete qualche idea sul motivo per cui questa risposta non funziona per me e gli altri, lo apprezzerei. Vorrei +1 per il tuo tempo, ma sono nuovo di questo sito e non ne ho ancora l'abilità. Grazie. – juan234

+0

@ juan234: Ho aggiunto alla mia risposta un codice di verifica che tutti possono eseguire e verificare la correttezza del risultato. Questa verifica mostra la correttezza dell'espressione - c'è * no * errore di battitura. Potresti avere problemi a causa di diversi motivi: dall'utilizzo di un motore XPath 1.0 non conforme ai problemi nel tuo codice - per individuare il motivo per cui è necessario vedere il tuo codice. '[1]' significa il primo nodo del nodeset selezionato dalla parte dell'espressione immediatamente a destra di '[1]' - negli assi inversi (come 'antenato ::' in realtà significa l'ultimo nodo nell'ordine del documento). –

+0

Sono convinto :) – juan234

1

si potrebbe provare:

//div[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] | 
//table[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] 

fa questo aiuto?

1
//*[self::div|self::table] 
    [descendant::text()[contains(.,"abc")]] 
    [not(descendant::div|descendant::table)] 

Il problema è che contains(//text(), "abc") funzioni espressi insiemi nodo prendendo il primo nodo.