2010-06-28 4 views
11

Je colle ici du code qui compile sans avertissement en utilisant gcc file.c -lxml2, en supposant que libxml2 est installé sur votre système.erreur libxml2 avec les espaces de noms et 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); 
} 

Mon problème est que je veux analyser le code XML suivant

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

l'élément livre définit un espace de noms dans cet élément. Je veux imprimer la valeur dans le xpath/book/section1 et il renvoie NULL. Quand j'essaye de renvoyer l'élément sous un espace de noms j'obtiens aussi des erreurs, ie/new: book/section1

Je suppose que mon code échoue parce que je n'utilise pas correctement les préfixes d'espace de noms. Je n'ai plus de temps. S'il te plait peux-tu aider?

Répondre

2

C'est un problème avec l'espace de noms par défaut. Pour correspondre à un chemin, vous devez/new: tag/new: tag et ainsi de suite

3

Ceci est un échec gênant de la bibliothèque libXml. Comme l'a noté cateof, le problème est la déclaration d'espace de noms par défaut:

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

Deux choix:
(1) se débarrasser de cette déclaration votre étiquette de livre ou (2) donnez-lui un nom et utilisez ce nom dans vos tags.

par exemple.

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

Ensuite, vos balises ressemblent toutes:

nouveau: livre nouveau: Section1

et ainsi de suite .

+2

Est-il possible de dire 'libxml' que certains espace de noms est par défaut/implicite pour tous les éléments d'un document pour éviter de répéter encore et dans les requêtes XPath? – SasQ

28

Turns, comme je l'ai découvert de here, ce n'est pas vraiment un échec de Libxml, c'est un problème parce Libxml correctement suit les spécifications XML/XPath.

Les solutions proposées par R Bourdeau sont correctes, cependant, si vous avez le contrôle du document XML que vous analysez.

Le contexte de la requête XPATH est indépendant des qualificatifs d'espace de noms dans le document xml. L'espace de noms par défaut force toutes les balises enfant dans un espace de noms; ils ne requièrent pas de qualification dans le document mais doit être qualifié dans la requête xpath. Heureusement, vous avez enregistré l'espace de noms en tant que new avec libXml, donc la solution de cateof devrait fonctionner.

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

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

Je suis inline xml ici pour une meilleure 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

C'est la première réponse liée à XPath et à l'espace de noms qui expliquait ce qui se passait et comment le résoudre. Mes sincères remerciements à vous mon ami. –

Questions connexes