2010-06-28 9 views
11

Ich bin hier Einfügen von Code, der kompiliert ohne Warnung mit gcc file.c -lxml2, vorausgesetzt, dass libxml2 in Ihrem System installiert ist.libxml2 Fehler mit Namespaces und 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); 
} 

Mein Problem ist, dass ich die folgenden XML-

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

das Buch-Element definiert einen Namespace in diesem Element analysieren möchten. Ich möchte den Wert in dem xpath/book/section1 drucken, und es gibt NULL zurück. Wenn ich versuche, das Element unter einem Namespace zurückzugeben, erhalte ich auch Fehler, dh/new: book/section1

Ich nehme an, dass mein Code fehlschlägt, weil ich die Namespacepräfixe nicht richtig verwende. Ich habe keine Zeit mehr. Kannst du bitte helfen?

Antwort

2

ist es ein Problem mit dem Standardnamespace. Um einen Pfad zu finden, benötigen Sie/new: tag/new: tag und so weiter

3

Dies ist ein ärgerlicher Fehler der Bibliothek libXml. Wie durch cateof erwähnt, ist das Problem der Standard-Namespace-Deklaration:

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

zwei Möglichkeiten:
(1) dieser Erklärung loswerden in Ihr book tag oder (2) geben Sie ihm einen Namen und verwenden Sie diesen Namen in Ihren Tags.

z.B.

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

Dann werden alle Ihre Tags wie folgt aussehen:

neu: Buch neu: section1

und so weiter .

+2

Ist es möglich, 'libxml' zu sagen, dass einige Namespace default/implizit für alle Elemente in einem Dokument, um es über zu vermeiden, ist zu wiederholen und in XPath-Abfragen? – SasQ

28

Es stellte sich heraus, wie ich aus here fand heraus, es nicht wirklich ein Fehler von LibXML ist, es ist ein Problem, weil LibXML richtig die Spezifikationen XML/XPATH folgt.

Die von R Bourdeau vorgeschlagenen Lösungen sind jedoch korrekt, wenn Sie die Kontrolle über das zu analysierende XML-Dokument haben.

Der Kontext für die XPATH-Abfrage ist unabhängig der Namespacequalifikatoren im XML-Dokument. Der Standardnamespace erzwingt alle untergeordneten Tags in einem Namespace; Sie benötigen keine Qualifizierung in dem Dokument, aber müssen in der Xpath-Abfrage qualifiziert werden. Glücklicherweise haben Sie den Namespace mit libXml als new registriert, daher sollte die Lösung von cateof funktionieren.

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

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

Ich inlining die xml hier für Sichtbarkeit:

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

Dies ist die erste Antwort in Bezug auf XPath und Namespacing, die tatsächlich erklärt, was vor sich geht und wie es zu lösen ist. Mein aufrichtiger Dank an dich, mein Freund. –