¿Cómo arreglar HTML mal formado con HTML Agility Pack?

.net c# html html-agility-pack parsing

Pregunta

Tengo este HTML mal formado con etiquetas superpuestas:

<p>word1<b>word2</p>
<p>word3</b>word4</p>

La superposición puede ser anidada, también.

¿Cómo puedo convertirlo en HTML bien formado con HTML Agility Pack (HAP)?

Estoy buscando esta salida:

<p>word1<b>word2</b></p>
<p><b>word3</b>word4</p>

HtmlNode.ElementsFlags["b"] = HtmlElementFlag.Closed | HtmlElementFlag.CanOverlap , pero no funciona como se esperaba.

Respuesta aceptada

Es, de hecho, funciona como se esperaba, pero tal vez no funciona como se esperaba. De todos modos, aquí hay un fragmento de código de muestra (una aplicación de consola) que demuestra cómo se puede lograr una corrección de HTML utilizando la biblioteca.

La biblioteca tiene una colección ParseErrors que puede usar para determinar qué errores se detectaron durante el análisis de marcado.

Realmente hay dos tipos de problemas aquí:

1) elementos no cerrados . Este está arreglado de forma predeterminada por la biblioteca, pero hay una opción en el elemento P que evita eso en este caso.

2) Elementos sin abrir . Este es más complejo, ya que depende de cómo quieras arreglarlo, ¿dónde quieres que se abra la etiqueta? En el siguiente ejemplo, he usado el nodo hermano de texto anterior más cercano para abrir el elemento.

static void Main(string[] args)
{
    // clear the flags on P so unclosed elements in P will be auto closed.
    HtmlNode.ElementsFlags.Remove("p");

    // load the document
    HtmlDocument doc = new HtmlDocument();
    doc.Load("yourTestFile.htm");

    // build a list of nodes ordered by stream position
    NodePositions pos = new NodePositions(doc);

    // browse all tags detected as not opened
    foreach (HtmlParseError error in doc.ParseErrors.Where(e => e.Code == HtmlParseErrorCode.TagNotOpened))
    {
        // find the text node just before this error
        HtmlTextNode last = pos.Nodes.OfType<HtmlTextNode>().LastOrDefault(n => n.StreamPosition < error.StreamPosition);
        if (last != null)
        {
            // fix the text; reintroduce the broken tag
            last.Text = error.SourceText.Replace("/", "") + last.Text + error.SourceText;
        }
    }

    doc.Save(Console.Out);
}

public class NodePositions
{
    public NodePositions(HtmlDocument doc)
    {
        AddNode(doc.DocumentNode);
        Nodes.Sort(new NodePositionComparer());
    }

    private void AddNode(HtmlNode node)
    {
        Nodes.Add(node);
        foreach (HtmlNode child in node.ChildNodes)
        {
            AddNode(child);
        }
    }

    private class NodePositionComparer : IComparer<HtmlNode>
    {
        public int Compare(HtmlNode x, HtmlNode y)
        {
            return x.StreamPosition.CompareTo(y.StreamPosition);
        }
    }

    public List<HtmlNode> Nodes = new List<HtmlNode>();
}


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué