2010-06-28 11 views
11

Sto incollando del codice qui che compila senza avviso utilizzando gcc file.c -lxml2, assumendo che libxml2 sia installato nel sistema.errore libxml2 con spazi dei nomi e xpath

#include <libxml/parser.h> 
#include <libxml/xpath.h> 
#include <assert.h> 
#include <libxml/tree.h> 
#include <libxml/xpathInternals.h> 

xmlDocPtr 
getdoc (char *docname) { 
    xmlDocPtr doc; 
    doc = xmlParseFile(docname); 

    if (doc == NULL) { 
     fprintf(stderr,"Document not parsed successfully. \n"); 
     return NULL; 
    } 

    return doc; 
} 

xmlXPathObjectPtr 
getnodeset (xmlDocPtr doc, xmlChar *xpath){ 

    xmlXPathContextPtr context; 
    xmlXPathObjectPtr result; 

    context = xmlXPathNewContext(doc); 
    if (context == NULL) { 
     printf("Error in xmlXPathNewContext\n"); 
     return NULL; 
    } 

    if(xmlXPathRegisterNs(context, BAD_CAST "new", BAD_CAST "http://www.example.com/new") != 0) { 
     fprintf(stderr,"Error: unable to register NS with prefix"); 
     return NULL; 
    } 

    result = xmlXPathEvalExpression(xpath, context); 
    xmlXPathFreeContext(context); 
    if (result == NULL) { 
     printf("Error in xmlXPathEvalExpression\n"); 
     return NULL; 
    } 
    if(xmlXPathNodeSetIsEmpty(result->nodesetval)){ 
     xmlXPathFreeObject(result); 
       printf("No result\n"); 
     return NULL; 
    } 
    return result; 
} 

int 
main(int argc, char **argv) { 

    char *docname; 
    xmlDocPtr doc; 
    xmlChar *xpath = (xmlChar*) "/new:book/section1"; 
    xmlNodeSetPtr nodeset; 
    xmlXPathObjectPtr result; 
    int i; 
    xmlChar *keyword; 

    if (argc <= 1) { 
     printf("Usage: %s docname\n", argv[0]); 
     return(0); 
    } 

    docname = argv[1]; 
    doc = getdoc(docname); 
    result = getnodeset (doc, xpath); 
    if (result) { 
     nodeset = result->nodesetval; 
     for (i=0; i < nodeset->nodeNr; i++) { 
      keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1); 
     printf("keyword: %s\n", keyword); 
     xmlFree(keyword); 
     } 
     xmlXPathFreeObject (result); 
    } 

    xmlFreeDoc(doc); 
    xmlCleanupParser(); 
    return (1); 
} 

Il mio problema è che voglio analizzare il seguente codice XML

<?xml version="1.0" encoding="UTF-8"?> 
<book xmlns="http://www.example.com/new"> 
    <section1>Sec_1</section1> 
    <section2>Sec_2</section2> 
</book> 

l'elemento book definisce uno spazio dei nomi all'interno di tale elemento. Voglio stampare il valore in xpath/book/section1 e restituisce NULL. Quando sto cercando di restituire l'elemento in un namespace, ricevo anche degli errori, cioè/nuovo: book/section1

Suppongo che il mio codice non funzioni perché non sto utilizzando correttamente i prefissi dei namespace. Ho finito il tempo. Potresti per favore aiutare?

risposta

2

Si tratta di un problema con lo spazio dei nomi predefinito. Per abbinare un percorso necessario/nuovo: tag/nuovo: tag e così via

3

Questo è un fastidioso errore della libreria libXml. Come notato da cateof, il problema è la dichiarazione di spazio dei nomi predefinito:

xmlns = "" http://www.example.com/new

Due scelte:
(1) sbarazzarsi di quella dichiarazione il tag del tuo libro o (2) dagli un nome e usa quel nome nei tuoi tag.

ad es.

xmlns: nuovo = "http://www.example.com/new"

Poi i tag tutti assomigliano:

nuovo: libro nuova: section1

e così via .

+2

E 'possibile dire 'libxml' che qualche spazio dei nomi è default/implicito per tutti gli elementi di un documento per evitare di ripetere più e oltre nelle query XPath? – SasQ

28

risulta, come ho scoperto da here, in realtà non è un fallimento di libxml, è un problema perché LibXML correttamente segue le specifiche XML/XPath.

Le soluzioni proposte da R Bourdeau sono corrette, tuttavia, se si ha il controllo del documento xml che si sta analizzando.

Il contesto per la query XPATH è indipendente dei qualificatori di spazio dei nomi nel documento xml. Lo spazio dei nomi predefinito forza tutti i tag figlio in uno spazio dei nomi; non richiedono la qualifica nel documento ma deve essere qualificato nella query xpath nella versione. Fortunatamente, hai registrato lo spazio dei nomi come new con libXml, quindi la soluzione di cateof dovrebbe funzionare.

xmlXPathRegisterNs(context, BAD_CAST "new", BAD_CAST "http://www.example.com/new" 

xmlChar *xpath = (xmlChar*) "/new:book/new:section1"; 

che sto inline XML qui per la visibilità:

<?xml version="1.0" encoding="UTF-8"?> 
<book xmlns="http://www.example.com/new"> 
    <section1>Sec_1</section1> 
    <section2>Sec_2</section2> 
</book> 
+2

Questa è la prima risposta relativa a XPath e namespace che in realtà spiegava cosa stava succedendo e come risolverlo. I miei sinceri ringraziamenti a te, amico mio. –