Je suis en train d'analyser une chaîne HTML spécifique afin que je puisse extraire un ensemble de lignes brisées par <br/>
lignes de rupture. Le HTML d'entrée ressemble à ceci:
<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>
Avec cette div dans un document html plus grand, j'ai pu obtenir le HTML ChildNodes
List<HtmlNode> nodes = htmlDoc.DocumentNode
.Descendants("div")
.Where(x => x.Attributes.Contains("class") &&
x.Attributes["class"].Value.Contains("PlainText")).ToList();
Je ne sais pas trop où aller à partir de là, j'aimerais lire tout le texte jusqu'à ce que je voie deux lignes de fracture et que je m'arrête?
MODIFIER
J'ai examiné les nodes
childNodes dans l'inspecteur d'exécution Visual Studio et j'ai remarqué qu'il n'y avait pas réellement deux lignes <br/>
consectuives, mais une seule ligne de rupture et une balise #text
dont le caractère innerHTMl était \n
.
Quelque chose comme ça devrait marcher
[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";
}
Qui retourne
Remarquez comment il n'a pas renvoyé le commentaire après les deux frères
MODIFIER:
J'ai supprimé les valeurs #text
vides depuis que lorsque vous avez une nouvelle ligne entre les deux dernières balises br
vous obtenez une balise #text
avec des nouvelles lignes. Je pense que c’est là que réside la confusion.
Vous pouvez utiliser XPath //div[@class='PlainText']
pour obtenir les nœuds div requis. Vous pouvez également vérifier le prochain noeud frère lors de la prise de noeuds enfants de 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));
Je n'utilise pas inline lambda uniquement pour la lisibilité. La condition fonctionne comme ceci:
br
noeud, sinon - prenez le noeud actuel br
noeud, sinon - prenez le noeud actuel Résultat: