[ djordjeno @ 23.09.2008. 09:28 ] @
Pozdrav,

Imam problem sa XPath-om kada mi je potrebno da vrati sve nodove koji sa odredjenim imenom. Nodovi sa imenom "node_name" se nalaze na razlicitim dubinama u XML-u.
Znam da vratim sve nodove sa odredjenim imenom preko rekurzivnih poziva, ali me interesuje da li postoji elegantno resenje kroz jedan XPath poziv.

Npr evo XML-a:
Code:

<root>
  <node_name>First name</node_name>
  <level1>
    <node_name>Second name</node_name>
  </level1>
  <level1>
    <level2>
      <node_name>Third name</node_name>
      <node_name>Fourth name</node_name>
    </level2>
    <node_name>Fourth name</node_name>
  </level1>
  <level1>
    <level2>
      <node_name>Fifth name</node_name>
      <level3>
        <node_name>Sixth name</node_name>
        <node_name>Seventh name</node_name>
      </level3>
    </level2>
    <node_name>Eigth name</node_name>
  </level1>
</root>

Znaci zeljeni XPath bi trebao da vrati 8 stringova sa vrednostima nodova.
[ jablan @ 23.09.2008. 10:45 ] @
Mislim da ne može elegantnije od ovog:
Code:

//node_name

[ djordjeno @ 23.09.2008. 12:51 ] @
Citat:
jablan: Mislim da ne može elegantnije od ovog:
Code:

//node_name

;)


Stvarno radi :) ali izgleda da nisam dobro napisao primer.
XML fajl koji treba da isparsiram je poveliki pa cu pokusati da napravim bolju kopiju na kome ne radi ova sintaksa (//node_name).


Evo popravljenog primera:
Code:

<?xml version="1.0"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <levels>
    <level0 xmlns="http://www.someurl.com/api/data">
      <level1>
        <node_name att1="1">
          <selection>as - 1</selection>
        </node_name>
      </level1>
    </level0>
    <level0 xmlns="http://www.someurl.com/api/data">
      <level1>
        <level2>
          <node_name>Third name</node_name>
          <node_name>Fourth name</node_name>
        </level2>
        <node_name att1="2">
          <selection>as - 2</selection>
        </node_name>
      </level1>
      <level1>
        <level2>
          <node_name>Fifth name</node_name>
          <level3>
            <node_name>Sixth name</node_name>
            <node_name>Seventh name</node_name>
          </level3>
        </level2>
        <node_name>Eighth name</node_name>
      </level1>
    </level0>
  </levels>
</root>


Kad na ovaj XML pustite "//node_name" nece naci nijedan element.

Dosao sam do zakljucka da kada se na level# nodu izbrise "xmlns" atribut pomenuta sintaksa sa "//" radi kako treba. Da li nekako moze da se naznaci u XPath-u da se ignorise xmlns attribut.

Hvala.
[ jablan @ 23.09.2008. 14:27 ] @
Da bi XPath mečovao nod, mora da bude u istom nejmspesu. Iskreno, ne znam da li postoji način da specificiraš nejmspejs u XPath-u, proguglaj malo, a možda i ovde nađeš odgovor:

http://bobcat.webappcabaret.ne...ina/faq/xpath_01.htm#xpath_Q15

BTW, kad radiš sa velikim dokumentima, lakše je da koristiš neki parser SAX tipa (umesto DOM), pogotovu za ovaj tvoj slučaj kad ti je bitno ime noda, a ne putanja do njega.
[ mmix @ 23.09.2008. 16:01 ] @
Zapravo postoji resenje, ako hoces da vratis node odredjenog imena bez obzira na namespace u kojem je koristis * kao ime namespace-a u XPath-u:

Code:

//*:node_name


Ono sto je malo zeznuto je da vratis npr sve nodove istog imena koji pripadaju pod dva od 5 namespace-ova.
[ gonadarian @ 24.09.2008. 10:09 ] @
Ako imaš uticaj na strukturu XML fajla, pokušaj da izbegneš inline namespace definicije i prebaci ih u root element XMLa. Tu postavi namespace prefix i koristi ga dosledno u celom fajlu. Ako ne možeš da menjaš XML, a to ti je jedini namespace ignoriši ga pomoću metode iz prethodnog posta ili pomoću XPath funkcije local-name(). Ako ti je bitno da mečuješ taj konkretni namespace pogledaj upotrebu XPath funkcije namespace-uri(). Testirani primer:

Code:
//*[local-name()='node_name' and namespace-uri()='http://www.someurl.com/api/data']
[ djordjeno @ 24.09.2008. 11:12 ] @

Citat:
gonadarian: Ako imaš uticaj na strukturu XML fajla, pokušaj da izbegneš inline namespace definicije i prebaci ih u root element XMLa. Tu postavi namespace prefix i koristi ga dosledno u celom fajlu. Ako ne možeš da menjaš XML, a to ti je jedini namespace ignoriši ga pomoću metode iz prethodnog posta ili pomoću XPath funkcije local-name(). Ako ti je bitno da mečuješ taj konkretni namespace pogledaj upotrebu XPath funkcije namespace-uri(). Testirani primer:

Code:
//*[local-name()='node_name' and namespace-uri()='http://www.someurl.com/api/data']


Nazalost nemam uticaj, a da imam sigurno ne bih inline stavljao namespace definicije.

Hvala svima na prethodnim odgovorima. Now it works :)
[ mmix @ 24.09.2008. 18:58 ] @
Citat:
djordjeno: Nazalost nemam uticaj, a da imam sigurno ne bih inline stavljao namespace definicije.


Nema potrebe za bezanjem od online namespace-ova, oni su veoma efikasan mehanizam za injekciju dodatnog sadrzaja u XML bez pravljenja problema xpath logici koja radi sa default namespace-om iz roota, sto je vrlo verovatno i razlog zasto ti je XML tako formiran, mozda ces u nekoj sledecoj iteraciji dobijati xml sa level0 tagovima iz mesovitih namespace-ova sa razlicitim podformatima.