c - 无法使用 libtidy 获取 HTML 文本
问题描述
每个人 - 长期倾听者,第一次来电者。
我一直在 macOS 10.13 上使用 C 语言中的 libtidy。我从这里的示例代码开始,并将其修改为读取本地 html 文件,而不是使用 curl。除了文本之外,一切似乎都正常。它会在我的测试文件中找到并输出每个标签,但似乎根本无法获取文本,这让我发疯了。
有问题的代码出现在DumpNode
tree-walking 函数中。我的破解版:
#include <stdio.h>
#include <tidy.h>
#include <tidybuffio.h>
/* Wrapper functions for file i/o */
int w_getc(void* ptr)
{
return getc((FILE *)ptr);
}
void w_ungetc(void *ptr, unsigned char bv)
{
ungetc((int)bv, (FILE *)ptr);
}
Bool w_feof(void *ptr)
{
return (Bool)feof((FILE *)ptr);
}
/* Traverse the document tree */
void dumpNode(TidyDoc doc, TidyNode tnod, int indent)
{
TidyNode child;
for(child = tidyGetChild(tnod); child; child = tidyGetNext(child) ) {
ctmbstr name = tidyNodeGetName(child);
if (!name) {
/* if it doesn't have a name, then it's probably text, cdata, etc... */
TidyBuffer buf;
tidyBufInit(&buf);
if (tidyNodeHasText(doc, child) && tidyNodeGetText(doc, child, &buf)) {
printf("%u, %u, %u\n", buf.size, buf.allocated, buf.next);
printf("%*.*s\n", indent, indent, (buf.bp && buf.size > 0)?(char *)buf.bp:"");
}
tidyBufFree(&buf);
}
dumpNode(doc, child, indent + 4); /* recursive */
}
}
int main(int argc, char **argv)
{
if(argc == 2) {
TidyDoc tdoc;
int err;
FILE *fp;
TidyInputSource insrc;
tdoc = tidyCreate();
fp = fopen(argv[1], "r");
if (!fp) return -1;
if (tidyInitSource(&insrc, fp, &w_getc, &w_ungetc, &w_feof)) {
err = tidyParseSource(tdoc, &insrc); /* parse the input */
if(err >= 0) dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */
}
/* clean-up */
fclose(fp);
tidyRelease(tdoc);
return err;
}
return 0;
}
还有我的编译器字符串:gcc -o TidyExample tidyexample.c -ltidy -DENABLE_DEBUG_LOG -DDEBUG_PPRINT -DDEBUG_INDENT
以下是我到目前为止的推断:
- 遇到文本节点时,
tidyNodeHasText(doc, child);
都tidyNodeGetText(doc, child, &buf);
返回yes
. - 这告诉我
tidyNodeGetText
正在调用漂亮的打印函数。我已经验证了两者都没有TidyXmlOut
或TidyXhtmlOut
没有设置doc
,所以TY_(PPrintTree)
应该开火。 - 由于我使用
-DENABLE_DEBUG_LOG
and-DDEBUG_PPRINT
,TY_(PPrintTree)
应该调用dbg_show_node
,但似乎没有。这可能是因为node == NULL
条件提示立即返回,但我断言节点的存在,如果它不存在tidyNodeGetText
就会返回no
,所以这不可能是正在发生的事情。 - 我还尝试设置一个进度回调来更好地了解那里发生的事情,但奇怪的是,链接器无法识别符号
_tidySetPrettyPrinterCallback
。- ETA:我想通了;为此需要第二个链接库:
-ltidys
. 我现在可以获得相当不错的打印机进度。
- ETA:我想通了;为此需要第二个链接库:
- 上述代码段生成的唯一输出
0, 0, 0\n
来自第一条printf
语句和\n
第二条语句。 - 顺便说一句,我抄袭的那个 curl 示例代码?它有同样的问题。如果你运行它,一旦它碰到任何文本,你就会得到一个段错误,因为它在调用
printf
.
我没主意了。要么我做错了(可能),要么 libtidy 中有一个很大的错误(不太可能,但可能)。
ETA:这是一个很小的 HTML 文件,当您调用TidyExample minimal.html
结果时通常会出现空缓冲区:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<p>This is text.</p>
</body>
</html>
解决方案
好的,我找到了某种“解决方案”。它完成了工作,但我不知道为什么。
因此,在发现 之后-ltidys
,我正在尝试设置漂亮的打印回调,我发现如果我设置了一个,输出将是我所期望的......即使我实际上没有设置回调!
说真的,我所要做的就是插入 line tidySetPrettyPrinterCallback(tdoc, NULL);
,缓冲区填满并按应有的方式打印。注释掉它,它就会停止工作。
我研究了一些与 链接的其他功能,libtidys.a
它们似乎具有相同的效果。不过,我还没有做过任何严格的实验。
如果有人对可能导致这种情况的原因有任何见解,为了我自己的知识,我很想知道。但我不打算进一步探究。由于我已经找到了解决问题的实用方法,所以我暂时先解决这个问题,然后着手处理我尝试使用 Tidy 的实际项目。
推荐阅读
- python-3.x - Python:从一个元素的非结构化列表中提取内部值
- python - 有没有办法在 Python 3.x 中解密 OpenSSL AES 加密文件
- c++ - 从 VFTable c++ 重写类
- d3.js - d3v4 世界地图示例与来源解释
- laravel - 使用 laravel-6 重新加载页面时 Vue-Router 中断
- c# - 作为客户端通过蓝牙 SPP 接收响应 - Tizen .NET
- mysql - 按另一个表的字段中包含的大多数排序
- php - 如何显示登录/注销按钮();在 html 标题中?
- spring - 使用 Spring Boot 和 Micrometer 在 Dynatrace 中创建度量时出错
- excel - Excel VBA 结合了两个工作表更改