2011-02-08 11 views
3

J'ai besoin d'analyser des sections d'une chaîne de HTML. Par exemple:Analyse des sections de HTML dans 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> 

la section Parsing citation doit retourner:

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

Actuellement, je suis en utilisant une expression régulière pour saisir le contenu dans [section = quote] ... [/ section], mais étant donné que les sections sont saisies à l'aide d'un éditeur WYSIWYG, les balises de section se faire enveloppés dans une étiquette de paragraphe, de sorte que le résultat parser est:

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

l'expression régulière J'utilise est actuellement:

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

Et je fais aussi un nettoyage supplémentaire avant l'analyse syntaxique des sections:

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

Quelqu'un peut-il fournir une expression régulière qui réaliserait ce que je cherche ou que je perds mon temps à essayer faire cela avec Regex? J'ai vu des références au Html Agility Pack - serait-ce mieux pour quelque chose comme ça?

[Mise à jour]

Merci à Oscar J'ai utilisé une combinaison du pack Agility HTML et Regex pour analyser les sections. Il a encore besoin d'un peu d'affinage mais c'est presque là.

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

Oui, utiliser Html Agiligy pack –

+4

lien obligatoire pour http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – stuartd

+0

Parsing html avec regex est généralement une mauvaise idée, car html n'est pas régulier. Si vous pouvez jeter un oeil à un analyseur html, ils sont nombreux disponibles, et ils causeront beaucoup moins de douleur. – TheLukeMcCarthy

Répondre

2

Les travaux suivants, en utilisant la bibliothèque 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(); 

Si vous voulez juste imprimer Mauris at turpis nec dolor bibendum sollicitudin ac quis neque. sans <p>...</p>, vous pouvez remplacer par n.OuterHtmln.InnerHtml. Bien sûr, vous devriez vérifier si doc.DocumentNode.SelectNodes("//p") est null.
Si vous voulez charger le code HTML à partir d'une source en ligne au lieu d'un fichier, vous pouvez le faire:

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

Edit:

Si [section=quote] un [/section] pourrait être à l'intérieur toute balise (pas toujours <p>), vous pouvez remplacer doc.DocumentNode.SelectNodes("//p") par doc.DocumentNode.SelectNodes("//*").

+0

Wow merci. Je viens juste de remarquer ta réponse. Laissez-moi faire un tourbillon! –

+0

@Bien vous êtes les bienvenus;) –

1

Que diriez-vous de remplacer

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

avec

[section=quote] 

et

<p>[/section]</p> 

avec

[/section] 

dans le cadre de votre nettoyage. Ensuite, vous pouvez utiliser votre expression régulière existante.

+0

étant donné que le contenu html est entièrement entre les mains de l'utilisateur, je ne sais pas à quoi les balises [section] seront enveloppées (pourrait être div, p, n'importe quoi). –