2010-06-28 5 views
11

Я вставляю код здесь, который компилируется без предупреждения с использованием gcc file.c -lxml2, предполагая, что в вашей системе установлен libxml2.Ошибка libxml2 с пространствами имен и 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); 
} 

Моя проблема заключается в том, что я хочу, чтобы проанализировать следующие XML

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

книга элемент определяет пространство имен внутри этого элемента. Я хочу напечатать значение в xpath/book/section1 и он возвращает NULL. Когда я пытаюсь вернуть элемент под пространством имен, я также получаю ошибки, т. Е./New: book/section1

Я предполагаю, что мой код терпит неудачу, потому что я неправильно использую префиксы пространства имен. У меня не хватает времени. Не могли бы вы помочь?

ответ

2

Это проблема с пространством имен по умолчанию. Чтобы соответствовать пути, который вам нужен/new: tag/new: tag и т. Д.

3

Это досадный отказ библиотеки libXml. Как отметил cateof, проблема заключается в декларации пространства имен по умолчанию:

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

Два варианта:
(1) избавиться от этого заявления в ваш ярлык или (2) укажите ему имя и используйте его в своих тегах.

например.

XMLNS: новый = "http://www.example.com/new"

Тогда ваши теги все выглядят следующим образом:

новые: книги новых: section1

и так далее ,

+2

Можно сказать 'libxml', что некоторые пространства имен по умолчанию/неявное для всех элементов в документе, чтобы избежать повторения его и в запросах XPath? – SasQ

28

Оказывается, как я узнал от here, это на самом деле не провал Libxml, это проблема, потому что Libxml правильно следует спецификации XML/XPATH.

Решения, предложенные R Bourdeau, являются правильными, однако, если вы контролируете XML-документ, который вы разбираете.

Контекст для запроса XPATH: независимый классификаторов пространства имен в документе xml. По умолчанию пространство имен заставляет все дочерние теги в пространство имен; они не требуют квалификации в документе, но должен быть квалифицированным в запросе xpath. К счастью, вы зарегистрировали пространство имен как new с libXml, поэтому решение cateof должно работать.

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

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

Я встраивание XML-здесь для наглядности:

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

Это первый ответ, связанный с XPath и namespacing, который фактически объяснил, что происходит и как его решить. Моя искренняя благодарность вам, мой друг. –

Смежные вопросы