2013-08-08 4 views
1

Я решил использовать парсер libxml2 для моего приложения qt и im застрял в выражениях xpath. Я нашел примерный класс и методы и немного изменил его для своих нужд. Кодlibxml2 xpath parsing, не работает должным образом

QStringList* LibXml2Reader::XPathParsing(QXmlInputSource input) 
{ 
    xmlInitParser(); 

    xmlDocPtr doc; 
    xmlXPathContextPtr xpathCtx; 
    xmlXPathObjectPtr xpathObj; 
    QStringList *valList =NULL; 

    QByteArray arr = input.data().toUtf8(); //convert input data to utf8 
    int length = arr.length(); 
    const char* data = arr.data(); 

    doc = xmlRecoverMemory(data,length); // build a tree, ignoring the errors 
    if(doc == NULL) { return NULL;} 

    xpathCtx = xmlXPathNewContext(doc); 
    if(xpathCtx == NULL) 
    { 
     xmlFreeDoc(doc); 
     xmlCleanupParser(); 
     return NULL; 
    } 

    xpathObj = xmlXPathEvalExpression(BAD_CAST "//[@class='b-domik__nojs']", xpathCtx); //heres the parsing fails 
    if(xpathObj == NULL) 
    { 
     xmlXPathFreeContext(xpathCtx); 
     xmlFreeDoc(doc); 
     xmlCleanupParser(); 
     return NULL; 
    } 

    xmlNodeSetPtr nodes = xpathObj->nodesetval; 
    int size = (nodes) ? nodes->nodeNr : 0; 
    if(size==0) 
    { 

     xmlXPathFreeContext(xpathCtx); 
     xmlFreeDoc(doc); 
     xmlCleanupParser(); 
     return NULL; 
    } 
    valList = new QStringList(); 
    for (int i = 0; i < size; i++) 
    { 
     xmlNodePtr current = nodes->nodeTab[i]; 
     const char* str = (const char*)current->content; 
     qDebug() << "name: " << QString::fromLocal8Bit((const char*)current->name); 
     qDebug() << "content: " << QString::fromLocal8Bit((const char*)current->content) << "\r\n"; 
     valList->append(QString::fromLocal8Bit(str)); 
    } 

    xmlXPathFreeObject(xpathObj); 
    xmlXPathFreeContext(xpathCtx); 
    xmlFreeDoc(doc); 
    xmlCleanupParser(); 
    return valList; 
} 

В качестве примера им сделать запрос на http://yandex.ru/ и пытаются получить узел с классом «B-domik__nojs», который является в основном один Див.

xpathObj = xmlXPathEvalExpression(BAD_CAST "//[@class='b-domik__nojs']", xpathCtx); //heres the parsing fails 

проблема выражение // [@ класс = 'б-domik__nojs'] не работает. Я проверил его в firefox xpath ext., А также в опере разработки инструментов xpath ext. там это выражение работает отлично. Я также пытался получить другие узлы с атрибутами, но по какой-то причине xpath для ANY-атрибута терпит неудачу. Что-то не так в моем методе? Также, когда я загружаю дерево с помощью xmlRecover, он дает мне много ошибок парсера в отладочном выходе.


Ok я играл немного с моей функцией libxml2 больше и используются «// *» выражение, чтобы получить все элементы документа, но! Он возвращает мне только элементы в первом дочернем узле тега body. This is the yandex.ru dom tree

так что в основном он получает ВСЕ элементы в первом div «div class =« b-line b-line_bar », но по каким-то причинам не ищет другие элементы в других дочерних узлах. Почему это может произойти Возможно, xmlParseMemory по какой-то причине не строит полное дерево? Существует ли какое-либо возможное решение для исправления этого вопроса.

+0

Ok. Небольшое обновление, я прошел дерево, и я понял, что он НЕ МОЖЕТ полностью построить функцию 'xmlRecoverMemory'. Он создает только html, head, body и first 'div' в дереве. Так что мой вопрос в том, что теперь, как я могу построить валидное дерево, игнорируя все ошибки ??? – SirLanceloaaat

ответ

1

Теперь это работает, если моя ошибка заключалась в использовании функций xml для превращения html-документов в дерево. Я использовал htmlReadMemory, и дерево теперь полностью построено. Некоторый код снова

xmlInitParser(); 


xmlDocPtr doc; 
xmlXPathContextPtr xpathCtx; 
xmlXPathObjectPtr xpathObj; 


QByteArray arr = input.data().toUtf8(); 
int length = arr.length(); 
const char* data = arr.data(); 

doc = htmlReadMemory(data,length,"",NULL,HTML_PARSE_RECOVER); 

if(doc == NULL) { return NULL;} 


xpathCtx = xmlXPathNewContext(doc); 
if(xpathCtx == NULL) 
{ 
    xmlFreeDoc(doc); 
    xmlCleanupParser(); 
    return NULL; 
} 
xpathObj = xmlXPathEvalExpression(BAD_CAST "//*[@class='b-domik__nojs']", xpathCtx); 

и т.д.

0

Действительно странно, что выражение работает в любом месте, поскольку оно не является допустимым выражением XPath. После спецификации оси (//), перед предикатом должен быть nodetest (имя элемента или *).

//*[@class='bdomik__nojs'] 
+0

Я попробовал это так: 'xpathObj = xmlXPathEvalExpression (BAD_CAST" // * [@ class = 'b-domik__nojs'] ", xpathCtx);' теперь я получаю xpathObj-> nodesetval length = 0 ... – SirLanceloaaat

+0

по длине i средний nodeetval-> nodeNr; – SirLanceloaaat

+0

Есть ли альтернатива на qt для libxml2? Можно использовать QXmlQuery в QDomDocument? Я попытался установить только одно содержимое страницы, например 'query.setFocus (resp-> response); query.setQuery ("html [@ xmlns = 'http: //www.w3.org/1999/xhtml']/head/title/text()") ;, но query.isValid() возвращает false. – SirLanceloaaat

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