2011-02-11 10 views
7

Esto parece ser una pregunta recurrente, pero aquí va.Cómo analizar HTML para modificar todas las palabras

Tengo HTML que está bien formateado (proviene de una fuente controlada, por lo que se puede tomar como un hecho). Necesito iterar a través del contenido del cuerpo del HTML, buscar todas las palabras en el documento, realizar algunas modificaciones en esas palabras y guardar los resultados.

Por ejemplo, tengo el archivo sample.html y quiero ejecutarlo a través de mi aplicación y producto output.html, que es exactamente igual al original, más mis ediciones.

He encontrado lo siguiente utilizando HTMLAgilityPack, pero todos los ejemplos que he encontrado miran los atributos de las etiquetas especificadas, ¿hay alguna modificación fácil que examine los contenidos y realice mis ediciones?

HtmlDocument HD = new HtmlDocument(); 
HD.Load (@"e:\test.htm"); 
var NoAltElements = HD.DocumentNode.SelectNodes("//img[not(@alt)]"); 
if (NoAltElements != null) 
{ 
    foreach (HtmlNode HN in NoAltElements) 
    { 
     HN.Attributes.Append("alt", "no alt image"); 
    } 
} 

HD.Save(@"e:\test.htm"); 

Lo anterior busca etiquetas de imagen sin etiquetas ALT. Quiero buscar todas las etiquetas en el archivo <body> y hacer algo con los contenidos (lo que puede implicar la creación de nuevas etiquetas en el proceso).

Una muestra muy simple de lo que podría hacer es tomar la siguiente entrada:

<html> 
    <head><title>Some Title</title></head> 
    <body> 
     <h1>This is my page</h1> 
     <p>This is a paragraph of text.</p> 
    </body> 
</html> 

y producir la salida, que tiene cada palabra y alterna entre lo que es mayúscula y lo que es cursiva:

<html> 
    <head><title>Some Title</title></head> 
    <body> 
     <h1>THIS <em>is</em> MY <em>page</em></h1> 
     <p>THIS <em>is</em> A <em>paragraph</em> OF <em>text</em>.</p> 
    </body> 
</html> 

Ideas, sugerencias?

Respuesta

5

Personalmente, dada esta configuración, trabajaría con la propiedad InnerText de HtmlNode para buscar las palabras (probablemente con Regex para poder excluir la puntuación y no simplemente confiar en los espacios) y luego usar la propiedad InnerHtml para hacer el cambia usando llamadas iterativas a Regex.Replace (porque Regex.Replace tiene un método que le permite especificar tanto la posición de inicio como la cantidad de veces que se debe reemplazar).

código de procesamiento:

IEnumerable<HtmlNode> nodes = doc.DocumentNode.DescendantNodes().Where(n => n.InnerText == "something"); 
foreach (HtmlNode node in nodes) 
{ 
    string[] words = getWords(node.InnerText); 

    node.InnerHtml = processHtml(node.InnerHtml, words); 
} 

identificar palabras (es probable que haya alguna manera impermeable a hacer esto, pero aquí está una puñalada inicial):

private string[] getWords(string text) 
{ 
    Regex reg = new Regex("/w+"); 
    MatchCollection matches = reg.Matches(text); 
    List<string> words = new List<string>(); 
    foreach (Match match in matches) 
    { 
     words.Add(match.Value); 
    } 
    return words.ToArray(); 
} 

proceso el html:

private string processHtml(string html, string[] words) 
{ 
    int startPosition = 0; 
    foreach (string word in words) 
    { 
     startPosition = html.IndexOf(word, startPosition); 
     Regex reg = new Regex(word); 
     html = reg.Replace(html, alterWord(word), 1, startPosition); 
    } 

    return html; 
} 

Dejaré los detalles de alterWord() para ti. :)

+0

¡Gracias, creo que esto es exactamente lo que estaba buscando! – Elie

3

Probar .SelectNodes("//body//*"). Eso te dará todos los elementos dentro de cualquier elemento body, a cualquier profundidad.

+0

Pero, ¿cómo puedo iterar sobre el contenido de esa etiqueta, para poder analizar cada palabra que no es una etiqueta? – Elie

+0

En ese punto, casi tiene que confiar en procesar el contenido del elemento como una cadena, probablemente utilizando expresiones regulares. – Flynn1179

Cuestiones relacionadas