1

我决定libxml2为我的 qt 应用程序使用解析器,但我坚持使用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) << "\r\n";
        valList->append(QString::fromLocal8Bit(str));
    }

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

举个例子,我向http://yandex.ru/发出请求并尝试获取具有b-domik__nojs基本上是一个 div 的类的节点。

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

问题是表达式//[@class='b-domik__nojs']根本不起作用。我在 firefox xpathext. 和 opera developer tools xpathext. 中检查了它。在那里,这个表达完美。

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


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

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

为什么会这样?也许xmlParseMemory由于某种原因没有建立一棵完整的树?是否有任何可能的解决方案来解决这个问题。

4

2 回答 2

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);

等等

于 2013-08-22T14:52:40.660 回答
1

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

//*[@class='bdomik__nojs']
于 2013-08-08T14:38:08.500 回答