【问题标题】:trying to identify text nodes with htmlagility pack尝试使用 htmlagility 包识别文本节点
【发布时间】:2023-03-15 15:47:01
【问题描述】:

我正在尝试从具有如下格式的 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())]") ??新的 HtmlNodeCollection(null);

nonEmptyTextNodes 给计数为零,我不确定我在哪里做错了上面的代码。

谁能指出我正确的方向?非常感谢。

【问题讨论】:

    标签: c# .net xml html-agility-pack


    【解决方案1】:

    除了 Siebe 的回答,我还想指出修剪开始/结束 BR 标记的代码效率低下。如果您查看 HtmlNode 操作的 HtmlAgilityPack 代码,您会看到每当删除节点时,都会在父级(及其父级,一直向上)上调用 SetChanged() 方法。下次您检查树中任何内容的开始/结束索引时,需要重新计算它们。因此,如果您只是创建一个所有要删除的节点的临时列表,然后在它们全部被识别后删除它们,则可以使这段代码运行得更快。

    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

    【讨论】:

      【解决方案2】:

      不确定你想要达到什么目的

      //text()[not(self::text())]
      

      它尝试选择不是 text()-nodes 的 text()-nodes。所以什么都不会被发现。如果你只是使用

      //text()
      

      将选择所有 text()-nodes

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        • 2023-01-11
        • 2020-11-16
        • 1970-01-01
        • 2020-03-07
        • 2021-06-21
        • 1970-01-01
        相关资源
        最近更新 更多