尝试使用 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