La sintassi XPath – come usare la posizione() in un complesso percorso

Sto scrivendo un algoritmo ricorsivo per generare un unico minimo di XPath per un determinato elemento.
L’idea principale è di consentire la scelta di un elemento in un documento (cioè un elemento html in chrome sul PC) e di essere in grado di trovare l’elemento corrispondente in documenti simili (ad esempio, sito in versione mobile).

Durante il processo, ho bisogno di generare un completo stringa XPath per un intero documento, vale a dire per un dato nodo, attraversano l’intero albero e aggiungere tutti i nodi con tutti i loro attributi stringa.

Per esempio, per il seguente documento (la volevo elemento è contrassegnato con “*”):

<?xml version="1.0" encoding="UTF-16"?>
<node>
    <node/>
    <node id="content">
        <node>
            <node>
                <node id="url_text_field"/>
                *<node id="go_button" text="Go">
                </node>*
                <node id="back_button" text="Back">
                </node>
            </node>
            <node id="webViewPlaceholder">
                <node/>
            </node>
        </node>
    </node>
</node>

XPath generato dal mio codice:

//*[@id='go_button' and @text='Go' and parent::*[child::*[@id='url_text_field'] and child::*[@id='back_button' and @text='Back'] and parent::*[child::*[@id='webViewPlaceholder'] and parent::*[@id='content']]]]

resa <node id="go_button" text="Go">
Perfettamente in linea con l’elemento.

Il mio problema è che in un caso particolare (che – quando si tratta di un sotto-albero che contiene l’elemento voluto identico al fratello: “(s)”), devo utilizzare l’elemento position()=SOME_NUMBER (o un “indice” nodo [SOME_NUMBER]) per identificare in modo univoco un elemento, e sto avendo problemi con la sintassi.

Per esempio, per il documento più complesso (di nuovo, un elemento è contrassegnato con “*”. indice attributo non è parte del documento originale, ed è stato aggiunto solo per riferimento):

<?xml version="1.0" encoding="UTF-16"?>
<node>
    <node/>
    <node id="content" index="a">
        <node>
            <node>
                <node id="url_text_field"/>
                <node id="go_button" text="Go" index="a1">
                </node>
                *<node id="go_button" text="Go" index="a2">
                </node>*
                <node id="back_button" text="Back">
                </node>
            </node>
            <node id="webViewPlaceholder">
                <node/>
            </node>
        </node>
    </node>
    <node id="content" index="b">
        <node>
            <node>
                <node id="url_text_field"/>
                <node id="go_button" text="Go" index="b1">
                </node>
                <node id="go_button" text="Go" index="b2">
                </node>
                <node id="back_button" text="Back">
                </node>
            </node>
            <node id="webViewPlaceholder">
                <node/>
            </node>
        </node>
    </node>
</node>

Naturalmente, il precedente XPath trova quattro elementi:

<node id="go_button" text="Go" index="a1"></node>
<node id="go_button" text="Go" index="a2"></node>
<node id="go_button" text="Go" index="b1"></node>
<node id="go_button" text="Go" index="b2"></node>

Ho provato ad aggiungere la posizione del nodo, in vari luoghi della XPath (per esempio //*[@id='go_button' and @text='Go' and position=2 and parent::*[child::*[@id='url_text_field'] and child::*[@id='back_button' and @text='Back'] and parent::*[child::*[@id='webViewPlaceholder'] and parent::*[@id='content'][1]]]] non funziona), ma non riusciva a trovare un modo per abbinare solo il secondo “fratello” sotto-albero sotto il primo “padre” sub-tree.

InformationsquelleAutor Elist | 2013-12-30



3 Replies
  1. 3

    Semplicemente aggiungere [postion()=1] al percorso di espressione – che restituirà i due nodi xml che abbinare il vostro percorso (indici a1 e b1). Se si desidera solo il primo, quindi non utilizzare il //, utilizzare /descendant:: invece. // spesso ha conseguenze inaspettate.

    • Grazie per la /descendant:: suggerimento, funziona davvero e posso filtrare th risultati dell’intera XPath da indice. Ma sto ancora cercando di capire come fare il filtraggio dei genitori livello (cioè dove posizionare il [position()=1] nodo in modo da ottenere solo a1 e a2). Ho bisogno di inserire più indici, uno per ogni livello dell’albero in cui più sotto-alberi sono identici.
    • Cosa ne dite…. /descendant::*[@id='content'][position()=1]/descendant::*[@id='go_button' and @text='Go']
    • E se si desidera solo a1 e poi aggiungere [position()=1] di nuovo – come… /descendant::*[@id='content'][position()=1]/descendant::*[@id='go_button' and @text='Go'][position()=1]
  2. 2

    La soluzione è utilizzare un nodo di indice invece di chiamare position.

    Avvolgere l’intera espressione xpath con giro di parentesi graffe, e aggiungere l’indice:

    (xpath_expression)[index]
  3. 1

    Non è possibile, con il genitore:: axis, perché questo sarà sempre restituire un solo elemento: il genitore. Quindi, l’aggiunta di una posizione di predicato poi altri [1] non tornerà mai più di un elemento.

    È possibile utilizzare http://xsltransform.net/jyyiVhj smanettare per trovare una soluzione, ma non la trovano.

    Dovrete creare una diversa strategia per creare un valido xpath che restituisce un unico elemento.

Lascia un commento