使用AngleSharp处理一些HTML并提取元素的文本内容以供以后挖掘,我遇到了AngleSharp剥离HTML标记的问题。例如,我有一段像这样的HTML(减去换行符和制表符):
<div id="someID">
blah, blah, blah, blah
blah, blah,
<ul>
<li><i>action.</i></li>
<li><i>Typical, blah, blah, blah</li>
</ul>
blah, blah, blah
</div>
这里的问题是,当我得到TextContent
:
var content = someDiv.TextContext;
它会像这样出现:
"...blah, blah, action.Typical blah, blah..."
单词action
和Typical
在没有任何空格的情况下被粉碎(因为它们之间唯一的东西是html标签)。这会使我的努力绊倒,然后将文本内容标记化,因为action.Typical
被视为单个单词而不是两个单词。
当然,我可以运行搜索并替换(可能使用正则表达式),例如(\S)\.(\S)
,并将其替换为$1. $2
,但这样会使用www.somecompany.com
之类的内容并将其拆分为www
,somecompany
和com
,而可能希望保留该值(或www
和{{1}失败无论如何都不可能非常有用)。我可以排除包含多个点的字词,但网址可能显示为com
(不包含somecompany.com
),或者您可能会遇到www
这样的电子邮件地址。
这是否有一种强有力的方法?在标签被剥离后至少保留一个空格?
答案 0 :(得分:0)
因此,解决此问题的最佳方法似乎是向下递归根元素的ChildNodes
(不是Children
错过文本节点),然后再次将它们连接起来。所以,给定:
var rootElem = myDoc.GetElementById("someId");
我可以创建一个这样的函数:
IEnumerable<string> ExtractChildNodes(INode node)
{
if (node.HasChildNodes)
{
foreach (var c in node.ChildNodes)
{
foreach (var r in ExtractChildNodes(c))
{
yield return r;
}
}
}
else
{
yield return node.TextContent;
}
}
这将测试节点是否具有子节点,以及是否向下钻取到最低叶节点并从那里返回文本。我可以这样做:
var textContentWithSpacesBetweenNodes = string.Join(" ", ExtractChildNodes(rootElem));
那应该给我:
"...blah, blah, action. Typical blah, blah..."
action
和Typical
之间的空格。
这似乎不仅可以处理像<p>some.</p><p>words</p>
这样的情况,还可以解决像some</br>words
甚至some<br>words
这样的自我关闭标签,这对处理使用正则表达式或类似问题会非常痛苦类似。
答案 1 :(得分:0)
您描述的方式有效,除了您已遇到的某些方案(例如,自动关闭标记)。因此,我提出以下建议:
总的来说,以下实现应该完成这项工作:
String Stringify(INode node)
{
switch (node.NodeType)
{
case NodeType.Text:
return node.TextContent;
case NodeType.Element:
if (node.HasChildNodes)
{
var sb = new StringBuilder();
var isElement = false;
foreach (var child in node.ChildNodes)
{
var isPreviousElement = isElement;
var content = Stringify(child);
isElement = child.NodeType == NodeType.Element;
if (!String.IsNullOrEmpty(content) && isElement && isPreviousElement)
{
sb.Append(' ');
}
sb.Append(content);
}
return sb.ToString();
}
switch (node.NodeName.ToLowerInvariant())
{
case "br": return "\n";
}
goto default;
default:
return String.Empty;
}
}
这种实施的优势在于您可以根据自己的需要进行调整。例如,对于br
等标记,您可以轻松输出空格而不是换行符。