尝试使用 htmlagility pack 识别文本节点
trying to identify text nodes with htmlagility pack
我正在尝试从具有如下格式的 HTML 文本中识别文本节点
示例文本 1:<strong>[Hot Water][Steam][Electric]</strong> Preheating Coil
示例文本 2:<b><span>[Steam] [Natural Gas Fired] [Electric] [Steam to steam]</span></b><span> Humidifier</span><br>
使用下面的代码
public static string IdentifyHTMLTagsAndRemove(string htmlText)
{
_ = htmlText ?? throw new ArgumentNullException(nameof(htmlText));
var document = new HtmlDocument();
document.LoadHtml(htmlText);
var rootNode = document.DocumentNode;
// get first and last text nodes
var nonEmptyTextNodes = rootNode.SelectNodes("//text()[not(self::text())]") ?? new HtmlNodeCollection(null);
//if (nonEmptyTextNodes.Count == 0)
//{
// return rootNode.OuterHtml;
//}
if (nonEmptyTextNodes.Count > 0)
{
var firstTextNode = nonEmptyTextNodes[0];
var lastTextNode = nonEmptyTextNodes[^1];
// get all br nodes in html string,
var breakNodes = rootNode.SelectNodes("//br") ?? new HtmlNodeCollection(null);
var lastTextNodeLengthIndex = lastTextNode.OuterStartIndex + lastTextNode.OuterLength;
foreach (var breakNode in breakNodes)
{
if (breakNode == null)
continue;
// check index of br nodes against first and last text nodes
// and remove br nodes that sit outside text nodes
if (breakNode.OuterStartIndex <= firstTextNode.OuterStartIndex
|| breakNode.OuterStartIndex >= lastTextNodeLengthIndex)
{
breakNode.Remove();
}
}
}
return rootNode.OuterHtml;
}
但是这里总是失败
var nonEmptyTextNodes =
rootNode.SelectNodes("//text()[not(self::text())]") ?? new
HtmlNodeCollection(null);
和nonEmptyTextNodes
计数为零,我不确定上面的代码哪里做错了。
谁能给我指出正确的方向?非常感谢。
不确定你想用
实现什么
//text()[not(self::text())]
它尝试 select 不是 text() 节点的 text() 节点。所以什么也找不到。如果你只是使用
//text()
将select所有文本()-节点
除了 Siebe 的回答之外,我还想指出修剪 start/end BR 标签的代码效率低下。如果您查看 HtmlNode 操作的 HtmlAgilityPack 代码,您会发现无论何时删除节点,都会在父级(及其父级,一直向上)上调用 SetChanged() 方法。下次您检查树中任何内容的 start/end 索引时,需要重新计算它们。因此,如果您只是创建一个包含所有要删除的节点的临时列表,然后在它们全部被识别后删除它们,那么这段代码可以 运行 更快。
var lastTextNodeLengthIndex = lastTextNode.OuterStartIndex + lastTextNode.OuterLength;
var breakNodesToRemove = rootNode.SelectNodes("//br")?.Where(node => node.OuterStartIndex <= firstTextNode.OuterStartIndex || node.OuterStartIndex >= lastTextNodeLengthIndex).ToList();
breakNodesToRemove?.ForEach(a => a.Remove());
参考:https://github.com/zzzprojects/html-agility-pack/blob/master/src/HtmlAgilityPack.Shared/HtmlNode.cs
我正在尝试从具有如下格式的 HTML 文本中识别文本节点
示例文本 1:<strong>[Hot Water][Steam][Electric]</strong> Preheating Coil
示例文本 2:<b><span>[Steam] [Natural Gas Fired] [Electric] [Steam to steam]</span></b><span> Humidifier</span><br>
使用下面的代码
public static string IdentifyHTMLTagsAndRemove(string htmlText)
{
_ = htmlText ?? throw new ArgumentNullException(nameof(htmlText));
var document = new HtmlDocument();
document.LoadHtml(htmlText);
var rootNode = document.DocumentNode;
// get first and last text nodes
var nonEmptyTextNodes = rootNode.SelectNodes("//text()[not(self::text())]") ?? new HtmlNodeCollection(null);
//if (nonEmptyTextNodes.Count == 0)
//{
// return rootNode.OuterHtml;
//}
if (nonEmptyTextNodes.Count > 0)
{
var firstTextNode = nonEmptyTextNodes[0];
var lastTextNode = nonEmptyTextNodes[^1];
// get all br nodes in html string,
var breakNodes = rootNode.SelectNodes("//br") ?? new HtmlNodeCollection(null);
var lastTextNodeLengthIndex = lastTextNode.OuterStartIndex + lastTextNode.OuterLength;
foreach (var breakNode in breakNodes)
{
if (breakNode == null)
continue;
// check index of br nodes against first and last text nodes
// and remove br nodes that sit outside text nodes
if (breakNode.OuterStartIndex <= firstTextNode.OuterStartIndex
|| breakNode.OuterStartIndex >= lastTextNodeLengthIndex)
{
breakNode.Remove();
}
}
}
return rootNode.OuterHtml;
}
但是这里总是失败
var nonEmptyTextNodes = rootNode.SelectNodes("//text()[not(self::text())]") ?? new HtmlNodeCollection(null);
和nonEmptyTextNodes
计数为零,我不确定上面的代码哪里做错了。
谁能给我指出正确的方向?非常感谢。
不确定你想用
实现什么//text()[not(self::text())]
它尝试 select 不是 text() 节点的 text() 节点。所以什么也找不到。如果你只是使用
//text()
将select所有文本()-节点
除了 Siebe 的回答之外,我还想指出修剪 start/end BR 标签的代码效率低下。如果您查看 HtmlNode 操作的 HtmlAgilityPack 代码,您会发现无论何时删除节点,都会在父级(及其父级,一直向上)上调用 SetChanged() 方法。下次您检查树中任何内容的 start/end 索引时,需要重新计算它们。因此,如果您只是创建一个包含所有要删除的节点的临时列表,然后在它们全部被识别后删除它们,那么这段代码可以 运行 更快。
var lastTextNodeLengthIndex = lastTextNode.OuterStartIndex + lastTextNode.OuterLength;
var breakNodesToRemove = rootNode.SelectNodes("//br")?.Where(node => node.OuterStartIndex <= firstTextNode.OuterStartIndex || node.OuterStartIndex >= lastTextNodeLengthIndex).ToList();
breakNodesToRemove?.ForEach(a => a.Remove());
参考:https://github.com/zzzprojects/html-agility-pack/blob/master/src/HtmlAgilityPack.Shared/HtmlNode.cs