2011-02-08 3 views
3

Мне нужно проанализировать разделы из строки HTML. Например:Разбор разделов HTML в C#

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> 
<p>[section=quote]</p> 
<p>Mauris at turpis nec dolor bibendum sollicitudin ac quis neque.</p> 
<p>[/section]</p> 

разборе раздел цитата должна возвращать:

<p>Mauris at turpis nec dolor bibendum sollicitudin ac quis neque.</p> 

В настоящее время я использую регулярное выражение, чтобы захватить содержимое внутри [раздел = quote] ... [/ раздел] но так как секции вводятся с помощью редактора WYSIWYG, раздел теги сами получить завернутые в пункте тега, так разобранный результат:

</p> 
<p>Mauris at turpis nec dolor bibendum sollicitudin ac quis neque.</p> 
<p> 

Регулярное выражение, я использую в настоящее время является:

\[section=(.+?)\](.+?)\[/section\] 

И я также делаю некоторую дополнительную очистку до разбора разделов:

protected string CleanHtml(string input) { 
    // remove whitespace 
    input = Regex.Replace(input, @"\s*(<[^>]+>)\s*", "$1", RegexOptions.Singleline); 
    // remove empty p elements 
    input = Regex.Replace(input, @"<p\s*/>|<p>\s*</p>", string.Empty); 
    return input; 
} 

Может кто-нибудь обеспечить регулярное выражение, которое бы добиться того, что я ищу, или я тратить свое время, пытаясь сделать это с помощью Regex? Я видел ссылки на Html Agility Pack - будет ли это лучше для чего-то подобного?

[Update]

Благодаря Оскару я использовал сочетание пакета HTML Agility и Regex для разбора разделов. Он по-прежнему нуждается в переработке, но он почти там.

public void ParseSections(string content) 
{ 
    this.SourceContent = content; 
    this.NonSectionedContent = content; 

    content = CleanHtml(content); 

    if (!sectionRegex.IsMatch(content)) 
     return; 

    var doc = new HtmlDocument(); 
    doc.LoadHtml(content); 

    bool flag = false; 
    string sectionName = string.Empty; 
    var sectionContent = new StringBuilder(); 
    var unsectioned = new StringBuilder(); 

    foreach (var n in doc.DocumentNode.SelectNodes("//p")) {    
     if (startSectionRegex.IsMatch(n.InnerText)) { 
      flag = true; 
      sectionName = startSectionRegex.Match(n.InnerText).Groups[1].Value.ToLowerInvariant(); 
      continue; 
     } 
     if (endSectionRegex.IsMatch(n.InnerText)) { 
      flag = false; 
      this.Sections.Add(sectionName, sectionContent.ToString()); 
      sectionContent.Clear(); 
      continue; 
     } 

     if (flag) 
      sectionContent.Append(n.OuterHtml); 
     else 
      unsectioned.Append(n.OuterHtml); 
    } 

    this.NonSectionedContent = unsectioned.ToString(); 
} 
+1

Да, использовать Html Agiligy пакет –

+4

Обязательной ссылку http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – stuartd

+0

Синтаксического HTML с Регулярное выражение обычно плохое, поскольку html не является регулярным. Если вы можете взглянуть на синтаксический анализатор html, их будет много, и они вызовут гораздо меньшую боль. – TheLukeMcCarthy

ответ

2

следующие работы, используя библиотеку HtmlAgilityPack:

using HtmlAgilityPack; 

...

HtmlDocument doc = new HtmlDocument(); 
doc.Load(@"C:\file.html"); 


bool flag = false; 
var sb = new StringBuilder(); 
foreach (var n in doc.DocumentNode.SelectNodes("//p")) 
{ 
    switch (n.InnerText) 
    { 
     case "[section=quote]": 
      flag = true; 
      continue; 
     case "[/section]": 
      flag = false; 
      break; 
    } 
    if (flag) 
    { 
     sb.AppendLine(n.OuterHtml); 
    } 
} 

Console.Write(sb); 
Console.ReadLine(); 

Если вы просто хотите напечатать Mauris at turpis nec dolor bibendum sollicitudin ac quis neque. без <p>...</p>, вы можете заменить n.OuterHtml на n.InnerHtml.

Конечно, вы должны проверить, doc.DocumentNode.SelectNodes("//p") is null.
Если вы хотите загрузить HTML из интернет-источника, вместо файла, вы можете сделать:

var htmlWeb = new HtmlWeb(); 
var doc = htmlWeb.Load("http://..../page.html"); 

Edit:

Если [section=quote][/section] может быть внутри любого тега (не всегда <p>), вы можете заменить doc.DocumentNode.SelectNodes("//p") на doc.DocumentNode.SelectNodes("//*").

+0

Wow thanks. Я только что заметил ваш ответ. Позволь мне дать ему вихрь! –

+0

@ Благодарим вас;) –

1

Как о замене

<p>[section=quote]</p> 

с

[section=quote] 

и

<p>[/section]</p> 

с

[/section] 

как часть вашей очистки. Затем вы можете использовать существующее регулярное выражение.

+0

, так как содержимое html полностью находится в руках пользователя, я действительно не знаю, как будут упаковываться теги [section] (может быть div, p, anything). –

Смежные вопросы