2013-10-31 87 views
3

我想解析一个特定的HTML字符串,以便我可以提取一组由<br/>分隔线分解的行。输入HTML看起来像这样:使用HTML解析HTML使用HTML AgilityPack

<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> 

有了这个div较大的HTML文档中,我能得到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,发现里面居然是不是两个consectuive <br/>线,但单断线和#text标签与它的innerHTML是\n新行字符。

enter image description here

+0

真的吗?我看到两个br标签,使用您发布的同一个示例 – devshorts

+0

输入的HTML有两个br标签,但从屏幕截图中可以看出,以及在调试节点''返回时检查的内容时,有'#text'标签在它们之间有一个只读取换行符的InnerHtml。 – Warz

+0

你关心换行吗?你的问题只说br标签。如果换行符是一个问题,你可以使用一个字符串修剪它 – devshorts

回答

0

像这样的东西应该工作

[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"; 
} 

它返回

enter image description here

注意它是如何的两个宽的

EDIT后没有返回评论:

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

+0

downvote的任何理由? – devshorts

+0

不知道谁downvoted但是我能使用一些相同的理念在这里检查的元素'#text'只有一个'\ N'换行符 – Warz

+0

在那里,所以它读取所有#text,直到连续两个宽我更新了它/标签被找到。 – devshorts

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)); 

我不使用内联拉姆达只是可读性。条件是这样的:

  • 检查下一个节点为空,如果是空,然后取当前节点
  • 检查下一个节点是br节点,如果不是 - 以当前节点
  • 检查当前节点是br节点,如果不是 - 以当前节点
  • 否则停止服用子节点

结果:

enter image description here

+0

在第二个'br'和'#text'后面的'notTwoBrakes'检查中,我仍然可以得到一切吗? – Warz

+0

@Warz刚刚证实,一切正常。也许你有其他一些条件来停止阅读数据。我的查询停止阅读双节后发现每个div中的节点。你可以在调试器截图中看到它 –