【问题标题】:Parse HTML by breaklines using HTML AgilityPack使用 HTML AgilityPack 通过断线解析 HTML
【发布时间】:2013-11-01 03:55:17
【问题描述】:

我正在尝试解析一个特定的 HTML 字符串,以便我可以提取一组由<br/> 换行符分隔的行。输入 HTML 如下所示:

<div class="PlainText">
  DATE: 2013-10-28 20:00:43 -0500 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  <br/> //Notice this has two break lines, i would like to stop after seeing two consecutive break lines.
</div>

在更大的 html 文档中使用这个 div,我可以得到HTML ChildNodes

List<HtmlNode> nodes = htmlDoc.DocumentNode
                                    .Descendants("div")
                                    .Where(x => x.Attributes.Contains("class") &&
                                            x.Attributes["class"].Value.Contains("PlainText")).ToList();

我不完全确定从这里去哪里,我想阅读所有文本,直到我看到两条断线并停止?

编辑

我在 Visual Studio 运行时检查器中查看了 childNodes nodes 并注意到实际上没有两个连续的 &lt;br/&gt; 行,而是一个断行和一个 #text 标记,其 innerHTMl 为 \n 一个新行特点。

【问题讨论】:

  • 真的吗?我看到两个 br 标签使用您发布的相同示例
  • 输入 HTML 有两个 br 标签,但正如您从屏幕截图中看到的,以及我在调试 nodes 返回的内容时检查得到的结果,它们之间有一个 #text 标签和一个 InnerHtml只读取一个换行符。
  • 你关心换行吗?您的问题仅涉及 br 标签。如果换行有问题,您可以在其上使用字符串修剪
  • 不,我不关心换行符,我想我会提到它,因为从技术上讲,它不是两个 br 紧挨着的标签,而是它们之间的换行符
  • HtmlAgility 包将换行符视为文本字段的一部分(因为换行符只是文本,它们不是标签),所以它们真的没有区别

标签: c# parsing html-agility-pack


【解决方案1】:

您可以使用 XPath //div[@class='PlainText'] 来获取所需的 div 节点。您还可以在从 div 获取子节点时检查下一个兄弟节点:

HtmlDocument doc = new HtmlDocument();
doc.Load("index.html");
Func<HtmlNode, bool> notTwoBrakes = 
    n => (n.Name != "br" || n.NextSibling != null && n.NextSibling.Name != "br");
var nodes = doc.DocumentNode.SelectNodes("//div[@class='PlainText']")
               .Select(div => div.ChildNodes.TakeWhile(notTwoBrakes));

我不使用内联 lambda 只是为了便于阅读。条件是这样的:

  • 检查下一个节点是否为null,如果为null,则取当前节点
  • 检查下一个节点是否为br节点,如果不是-取当前节点
  • 检查当前节点是否为br节点,如果不是-取当前节点
  • 否则停止获取子节点

结果:

【讨论】:

  • 在第二次br#text 之后,我仍然可以通过您的notTwoBrakes 支票找回一切?
  • @Warz 刚刚验证,一切正常。也许您还有其他一些条件可以停止读取数据。发现双中断后,我的查询停止读取每个 div 中的节点。您可以在调试器屏幕截图中看到它
【解决方案2】:

这样的东西应该可以工作

[Test]
public void Test()
{
    var x = ReadTillTwoBr(GetDivClass()).ToList();
}

public HtmlNode GetDivClass()
{
    var html = @"<html><div class=""PlainText"">
            DATE: 2013-10-28 20:00:43 -0500 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            <br   /> //Notice this has two break lines, i would like to stop after seeing two consecutive break lines.
            Item 3
        </div></html>";
    var doc = new HtmlDocument();
    doc.LoadHtml(html);

    return doc.DocumentNode
                .Descendants("div").First(x => x.Attributes.Contains("class") &&
                                                x.Attributes["class"].Value.Contains("PlainText"));

}

public IEnumerable<string> ReadTillTwoBr(HtmlNode node)
{
    var nonEmptyNodes =
        node.ChildNodes.Except(node.ChildNodes.Where(f => f.Name == "#text" && String.IsNullOrWhiteSpace(f.InnerHtml)))
            .ToList();

    foreach (var n in nonEmptyNodes)
    {
        if (IsBr(n) && IsBr(n.NextSibling))
        {
            yield break;
        }

        if (n.Name == "#text")
        {
            yield return n.InnerText.Trim();
        }
    }
}

public bool IsBr(HtmlNode n)
{
    return n != null && n.NodeType == HtmlNodeType.Element && n.Name == "br";
}

返回

注意在两个 br 之后它没有返回评论

编辑:

我删除了空的 #text 值,因为当你在最后两个 br 标记之间有一个换行符时,你实际上会得到一个带有换行符的 #text 标记。我认为这就是换行混乱所在。

【讨论】:

  • 不确定谁投了反对票,但我可以在这里使用一些相同的想法来检查只有 \n 换行符的元素 #text
  • 在那里,我对其进行了更新,以便它读取所有#text,直到找到两个连续的 br/ 标签。
  • @Warz 这有帮助吗?还是我误解了你的要求?
  • 是的,它有帮助,我现在正在运行我的测试,以查看您提到的文本标签是否可以忽略不计,并且在您的 isBr 运行时被忽略。顺便谢谢
  • 我一无所获,我已经修改了几次脚本。 yield break 永远不会发生并返回所有子节点
猜你喜欢
  • 2018-04-11
  • 2010-12-25
  • 2012-01-06
  • 2013-06-21
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
相关资源
最近更新 更多