è possibile risolvere il problema in HtmlAgilityPack quando c'è un tag html non chiuso?

c# html-agility-pack xpath

Domanda

bene ho il seguente problema.
l'html che ho è malformato e ho problemi con la selezione dei nodi usando il pacchetto agility html quando questo è il caso.
il codice è qui sotto:

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

il problema è che String_A2_2 è racchiuso tra parentesi.
quindi htmlagility pack restituisce 5 stringhe anziché 4 in lststrText.
è quindi possibile lasciare che htmlagility pack restituisca l'elemento 3 come "<strong>Elem_A</strong>String_A2_2 <String_A2_2> asdas" ?
o forse posso fare un po 'di pre-elaborazione per chiudere l'elemento?
il contenuto corrente di lststrText è

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"

Risposta accettata

La maggior parte dei parser html tenta di creare un DOM funzionante, nel senso che i tag non sono accettati. Verranno convertiti o chiusi in qualche modo.

Se solo la selezione dei nodi è importante per te, e la velocità e le enormi quantità di dati non sono un problema, puoi invece prendere tutti i tag <p> con un'espressione regolare:

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

Questa espressione regolare presuppone che i tag <p> siano ben formati e chiusi.

Se devi eseguire molto questo Regex nel tuo programma dovresti dichiararlo come:

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

[Modifica: cambio pacchetto agilità]

Se si desidera utilizzare il pacchetto HtmlAgility, è possibile modificare la funzione PushNodeEnd in HtmlDocument.cs:

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

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

dove AllowedTags sarebbe un elenco di tutti i tag noti: b, p, br, span, div, ecc.

l'output non è al 100% quello che vuoi, ma forse abbastanza vicino?

<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

Risposta popolare

Potresti usare TidyNet per fare il pre / postelaborazione a cui alludi . Puoi modificare la tua risposta per spiegare perché non sarebbe applicabile nel tuo caso?



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché