libxml2 XPath解析,无法按预期工作

libxml2 xpath parsing, doesn't work as expected

本文关键字:工作 XPath 解析 libxml2      更新时间:2023-10-16

我决定在qt应用程序中使用libxml2语法分析器,并坚持使用xpath表达式。我找到了一个示例类和方法,并根据需要对其进行了一些修改。代码

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) << "rn";
        valList->append(QString::fromLocal8Bit(str));
    }
    xmlXPathFreeObject(xpathObj);
    xmlXPathFreeContext(xpathCtx);
    xmlFreeDoc(doc);
    xmlCleanupParser();
    return valList;
}

例如,我请求http://yandex.ru/并尝试获得类为CCD_ 3的节点,该节点基本上是一个div.

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

问题是表达式CCD_ 4根本不起作用。我在firefox xpath ext.和opera开发工具xpath ext.中检查了它,在那里这个表达式可以完美地工作。

我还尝试获取其他具有属性的节点,但由于某种原因,ANY属性的xpath失败了。我的方法有问题吗?此外,当我使用xmlRecover加载树时,它在调试输出中会给我带来很多语法分析器错误。


好吧,我更多地使用了libxml2函数,并使用"//*"表达式来获取文档中的所有元素,但是!它只返回body标记的第一个子节点中的元素。这是yandex.ru dom树

因此,基本上它会获取第一个div "div class="b-line b-line_bar"中的所有元素,但由于某种原因,它不会在<body>的其他子节点中查找其他元素。

为什么会发生这种情况?也许xmlParseMemory由于某种原因没有构建完整的树?有什么可能的解决方案可以解决这个问题吗。

表达式在任何地方都能工作,这真的很奇怪,因为它不是一个有效的XPath表达式。在轴规范(//)之后,谓词(方括号中的条件)之前应该有一个nodetest(元素名称或*)。

//*[@class='bdomik__nojs']

好吧,如果我的错误是使用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);

等等。