XPATHS și numere implicite

Care este povestea din spatele XPath și sprijinul pentru spațiile de nume? XPath ca specificație precede spațiile de nume? Dacă am un document în care elemente au fost date un spațiu de nume implicit:


Se pare că unele dintre bibliotecile de procesoare XPath nu vor recunoaște //foo din cauza spațiului de nume, în timp ce altele vor. Opțiunea pe care echipa mea a crezut-o este să adăugați un prefix de nume spațiu utilizând expresii regulate în XPath (puteți adăuga un prefix de nume spațiu prin XmlNameTable), dar acest lucru pare fragil, deoarece XPath este un limbaj atât de flexibil atunci când vine vorba de testele nodurilor.

Există un standard care se aplică în acest sens?

Abordarea mea este un pic hackish, dar se pare că funcționează bine; Am eliminat declarația xmlns cu o căutare/înlocuire și apoi aplicați XPath.

string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );

Este o abordare corectă sau cineva a rezolvat acest lucru în mod diferit?

0
fr hi bn

5 răspunsuri

Dacă încercați să utilizați xslt, puteți adăuga spațiul de nume în declarația foii de stil. Dacă faceți asta, trebuie să vă asigurați că există un prefix sau nu va funcționa. Dacă XML-ul sursă nu are un prefix, acesta este încă bine, adăugați propriul prefix în foaia de stil.

Stylesheet



    
        <!--  do stuff here -->
    

Sau asa ceva.

0
adăugat

Am încercat ceva asemănător cu ceea ce mi-a propus și nu am reușit să lucrez. Din moment ce primesc date dintr-un serviciu publicat nu am putut schimba xml-ul. Am ajuns folosind XmlDocument și XmlNamespaceManager cum ar fi:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithBogusNamespace);            
XmlNamespaceManager nSpace = new XmlNamespaceManager(doc.NameTable);
nSpace.AddNamespace("myNs", "http://theirUri");

XmlNodeList nodes = doc.SelectNodes("//myNs:NodesIWant",nSpace);
//etc
0
adăugat
Dacă doriți să selectați folosind noduri la mai multe adâncimi, veți sfârși prin a face ceva de genul: xml.SelectNodes ("kml: kml/kml: Document/kml: Folder"
adăugat autor Drew Noakes, sursa

Aveți nevoie de numele local ():

http://www.w3.org/TR/xpath#function-local-name

Pentru a păcăli de la http://jcooney.net/archive/2005/08/09/ 6517.aspx :


  
    
              

Această expresie se va potrivi cu bara? element:

  //*[local-name()='bar'] 

Acesta nu va:

 //bar
0
adăugat
Dacă documentul dvs. are un alt bar dintr-un spațiu de nume diferit, atunci soluția dvs. va selecta ambele.
adăugat autor Micha Wiedenmann, sursa
Corect, dar cred că este mai bine decât regexarea spațiilor de nume ca pe care OP intenționa să o facă.
adăugat autor Stu, sursa

Problema este că un element fără un spațiu de nume este declarat a fi în spațiul de nume NULL - prin urmare, dacă//foo potrivită cu spațiul de nume pe care îl considerați "implicit", nu ar exista nicio modalitate de a se referi la un element din spațiul de nume null.

Amintiți-vă de asemenea că prefixul pentru un spațiu de nume este doar o convenție de prescurtare, numele elementului real (numele calificat sau QName pentru scurt) constă în spațiul de nume complet și numele local. Modificarea prefixului pentru un spațiu de nume nu modifică identitatea unui element - dacă este în același spațiu de nume și același nume local, atunci este același tip de element, chiar dacă prefixul este diferit.

XPath 2.0 (sau mai degrabă XSLT 2.0) are conceptul de "spațiu de nume implicit xpath". Puteți seta atributul xpath-default-namespace pe elementul xsl: stylesheet.

0
adăugat

Folosind libxml se pare că funcționează:

http://xmlsoft.org/examples/xpath1.c

 int 
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
    xmlChar* nsListDup;
    xmlChar* prefix;
    xmlChar* href;
    xmlChar* next;

    assert(xpathCtx);
    assert(nsList);

    nsListDup = xmlStrdup(nsList);
    if(nsListDup == NULL) {
    fprintf(stderr, "Error: unable to strdup namespaces list\n");
    return(-1); 
    }

    next = nsListDup; 
    while(next != NULL) {
    /* skip spaces */
    while((*next) == ' ') next++;
    if((*next) == '\0') break;

    /* find prefix */
    prefix = next;
    next = (xmlChar*)xmlStrchr(next, '=');
    if(next == NULL) {
        fprintf(stderr,"Error: invalid namespaces list format\n");
        xmlFree(nsListDup);
        return(-1); 
    }
    *(next++) = '\0';   

    /* find href */
    href = next;
    next = (xmlChar*)xmlStrchr(next, ' ');
    if(next != NULL) {
        *(next++) = '\0';   
    }

    /* do register namespace */
    if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
        fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
        xmlFree(nsListDup);
        return(-1); 
    }
    }

    xmlFree(nsListDup);
    return(0);
}
0
adăugat