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

StackOverflow https://stackoverflow.com/questions/1928293

  •  20-09-2019
  •  | 
  •  

Question

Eh bien, j'ai le problème suivant.
le code html que j'ai est malformé et j'avoir des problèmes avec la sélection des noeuds en utilisant pack agilité html lorsque cela 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 placé entre crochets.
si pack htmlagility retourne 5 chaînes au lieu de 4 dans le lststrText.
donc est-il possible de laisser l'élément de retour pack htmlagility 3 comme "<strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas"
ou peut-être que je peux faire un peu de 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"
Était-ce utile?

La solution

La plupart des parseurs html essayer de construire un DOM de travail, ce qui signifie balises ballants ne sont pas acceptés. Ils seront convertis ou fermés en quelque sorte.

Si seulement le choix des nœuds est d'importance pour vous, et la vitesse et d'énormes quantités de données ne sont pas un problème, vous pouvez saisir vos

avec une expression régulière à la place:

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 sont bien formées et fermées.

Si vous êtes à exécuter ce Regex beaucoup dans votre programme, vous annonciez comme:

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

[Edit: Agilité changement pack]

Si vous voulez utiliser emballer 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, durée, 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

Autres conseils

Vous pouvez utiliser TidyNet pour faire la vous faites allusion à pré / post-traitement. Pouvez-vous modifier votre réponse pour expliquer pourquoi ce ne serais pas applicable dans votre cas?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top