est-il possible de résoudre le problème dans HtmlAgilityPack quand il y a une balise html non fermée?

c# html-agility-pack xpath

Question

Eh bien, j'ai le problème suivant.
le html que j'ai est mal formé et j'ai des problèmes avec la sélection des nœuds à l'aide du pack d'agilité html lorsque c'est le cas.
le code est ci-dessous:

string strHtml = @"
<html>
  <div>
    <p><strong>Elem_A</strong>String_A1_2 String_A1_2</p>
    <p><strong>Elem_B</strong>String_B1_2 String_B1_2</p>
  </div>
  <div>
    <p><strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas</p>
    <p><strong>Elem_B</strong>String_B2_2 String_B2_2</p>
  </div>
</html>";
HtmlAgilityPack.HtmlDocument objHtmlDocument = new HtmlAgilityPack.HtmlDocument();
objHtmlDocument.LoadHtml(strHtml);
HtmlAgilityPack.HtmlNodeCollection colnodePs = objHtmlDocument.DocumentNode.SelectNodes("//p");
List<string> lststrText = new List<string>();
foreach (HtmlAgilityPack.HtmlNode nodeP in colnodePs)
{
  lststrText.Add(nodeP.InnerHtml);
}

le problème est que String_A2_2 est entre crochets.
donc htmlagility pack renvoie 5 chaînes au lieu de 4 dans le lststrText.
il est donc possible de laisser htmlagility pack renvoyer l'élément 3 sous la forme "<strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas" ?
ou peut-être que je peux faire du prétraitement pour fermer l'élément?
le contenu actuel de lststrText est

lststrText[0] = "<strong>Elem_A</strong>String_A1_2 String_A1_2"  
lststrText[1] = "<strong>Elem_B</strong>String_B1_2 String_B1_2"  
lststrText[2] = ""  
lststrText[3] = ""  
lststrText[4] = "<strong>Elem_B</strong>String_B2_2 String_B2_2"

Réponse acceptée

La plupart des analyseurs html tentent de créer un DOM fonctionnel, ce qui signifie que les balises suspendues ne sont pas acceptées. Ils seront convertis ou fermés d'une manière ou d'une autre.

Si vous ne souhaitez sélectionner que les nœuds et si la vitesse et les énormes quantités de données ne sont pas un problème, vous pouvez saisir toutes vos balises <p> avec une expression régulière:

Regex reMatchP = new Regex(@"<(p)>.*?</\1>");
foreach (Match m in reMatchP.Matches(strHtml))
{
   Console.WriteLine(m.Value);
}

Cette expression régulière suppose que les balises <p> sont bien formées et fermées.

Si vous utilisez beaucoup cette Regex dans votre programme, vous devez le déclarer comme:

static Regex reMatchP = new Regex(@"<(p)>.*?</\1>", RegexOptions.Compiled);

[Edit: changement de pack d'agilité]

Si vous souhaitez utiliser le pack HtmlAgility, vous pouvez modifier la fonction PushNodeEnd dans HtmlDocument.cs:

if (HtmlNode.IsCDataElement(CurrentNodeName()))
{
   _state = ParseState.PcData;
   return true;
}

// new code start
if ( !AllowedTags.Contains(_currentnode.Name) )
{
    close = true;
}
// new code end

où AllowedTags serait une liste de toutes les balises connues: b, p, br, span, div, etc.

la sortie n'est pas à 100% ce que vous voulez, mais peut-être assez proche?

<strong>Elem_A</strong>String_A1_2 String_A1_2
<strong>Elem_B</strong>String_B1_2 String_B1_2
<strong>Elem_A</strong>String_A2_2 <ignorestring_a2_2></ignorestring_a2_2> asdas
<strong>Elem_B</strong>String_B2_2 String_B2_2

Réponse populaire

Vous pouvez utiliser TidyNet pour effectuer le pré / post-traitement auquel vous faites allusion. Pouvez-vous modifier votre réponse pour expliquer pourquoi cela ne serait pas applicable dans votre cas?



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow