【问题标题】:libxml split text nodes at spaceslibxml 在空格处拆分文本节点
【发布时间】:2014-01-04 15:39:04
【问题描述】:

我正在使用 libxml 的 HTML 解析器来创建一个 html 文档的 dom 树。 libxml 将每个节点的文本内容作为整体字符串(节点)提供,但我的要求是在空格处进一步拆分每个文本节点并创建尽可能多的单词节点。到目前为止,我还没有从 libxml 中找到任何选项,所以我创建了一个 cpu 昂贵的逻辑来分割文本节点。下面是递归方法的一部分。

void parse(xmlNodePtr cur, El*& parent) {

  if (!cur) {
    return;
  }

  string tagName = (const char*) cur->name;
  string content = node_text(cur); // function defined below

  Element* el = new Element(tagName, content);
  parent->childs.push_back(el);


  size_t pos;
  string text;
  cur = cur->children;
  while (cur != NULL) {
     if (xmlNodeIsText(cur) && (pos = node_text_find(cur, text, " ")) != string::npos) {

            string first = text.substr(0, pos);
        string second = text.substr(pos + 1);
            El *el1 = new Element("text", first);
            el->childs.push_back(el1);

            El *el2 = new Element("text", " ");
        el->childs.push_back(el2);

            xmlNodeSetContent(cur, BAD_CAST second.c_str());
        continue;
     }
     parse(cur, el);
     cur = cur->next;
  }
}

string node_text(xmlNodePtr cur) {
    string content;
    if (xmlNodeIsText(cur)) {
        xmlChar *buf = xmlNodeGetContent(cur);
        content = (const char*) buf;
    }
    return content;
}

size_t node_text_find(xmlNodePtr cur, string& text, string what){
    text = node_text(cur);
    return text.find_first_of(what);
}

上述代码的问题是它不适用于像中文这样的一些 UTF 字符串,而且这段代码在整个解析过程中增加了时间。

任何人都可以提出更好的方法,提前谢谢!

【问题讨论】:

    标签: html c libxml2


    【解决方案1】:

    我没有完整的答案,但我确实看到您将xmlChar 明确转换为char。这是一个不好的迹象,可能是它在 Unicode 上不起作用的原因。

    如果您正在处理 Unicode(可能是 xmlChar),则需要使用 Unicode 文本处理库。不是 std::string。

    你实际上有两个选择。查找以 UTF-8 处理的库或将 UTF-8 转换为 wchar(宽字符)。如果你转换为wchar,那么你可以使用wstring 及其函数来处理Unicode。

    libxml2 xmlChar * to std::wstring 看起来是个有用的答案。

    至于速度,是我的眼睛欺骗了我,还是你在一个空间上分割并创建一个新元素,然后再分割?这不是表现的方式。我认为如果您删除文本节点,将所有单词拆分出来并随时添加新节点会更好。

    减速很可能出现在对象的重复创建、复制和销毁中。努力减少这种情况。例如,如果 Element 有一个构造函数形式,它接受一个开始/结束迭代器对,或一个开始,长度对,这将比创建一个子字符串(复制!)和创建一个元素(复制!)然后销毁子字符串。

    使用文本字符串的后半部分(可能很大)重复调用 xmlNodeSetContent 会为您提供 O2 性能。不好。

    【讨论】:

    • 非常感谢,我正在落实您的建议,并会尽快回复您。我认为你指出了为什么我的代码很慢是正确的!
    • libxml 提供了我正在使用的 xmlUTF8Strlen、xmlUTF8Strloc 和 xmlUTF8Strsub 等 utf 方法,但在汉字中找不到空格的原始问题是因为在汉字中没有空格字符!
    • @treemonster19:没有空间可以分割是个问题。我认为中文确实有某种分隔,但这取决于使用的符号不是吗?有些概念是一个符号,但有些概念是两个或三个?
    • 我和我的中国朋友谈过,他说中文中没有分隔符这样的概念,每个单独的字符都有一些不同于拉丁文的含义,可以将汉字组合成更复杂的含义。对我来说的麻烦是在使用 libxml 的 utf 库后,我的程序中不应该有任何特定于语言的代码,但它似乎需要从页面检测语言环境设置并相应地进行处理。