HtmlAgilityPack SelectNodes expresión para ignorar un elemento con un atributo determinado

c# html-agility-pack selectnodes xpath

Pregunta

Estoy tratando de seleccionar nodos excepto de nodos de script y una ul que tiene una clase llamada 'relativeNav'. ¿Puede alguien dirigirme por favor al camino correcto? He estado buscando esto durante una semana y no lo encuentro por ningún lado. Actualmente tengo esto pero obviamente seleccionando el // ul [@ class = 'relativeNav'] también. ¿Hay alguna forma de poner una expresión NOT de ella para que SelectNode la ignore?

        foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//body//*[not(self::script)]/text()"))
        {
            Console.WriteLine("Node: " + node);
            singleString += node.InnerText.Trim() + "\n";
        }

Respuesta aceptada

Dado un documento HTML con una estructura similar a:

<html>
<head><title>HtmlDocument</title>
</head>
<body>
<div>
<span>Hello Span World</span>
<script>
Script Text
</script>
</div>
<ul class='relativeNav'>
<li>Hello </li>
<li>Li</li>
<li>World</li>
</ul>
</body>
</html>

La siguiente expresión XPath seleccionará todos los nodos que no sean elementos de script excluyendo todos los elementos secundarios de UL con la clase 'relativeNav':

var nodes = htmlDoc.DocumentNode.SelectNodes("//body//*[not(parent::ul[@class='relativeNav']) and not(self::script)]/text()");

Actualización: olvidé mencionar que si necesita excluir a cualquier hijo de ul [class = 'relativeNav'] independientemente de su profundidad, debe usar:

"//body//*[not(ancestor::ul[@class='relativeNav']) and not(self::script)]/text()"

Si también desea excluir el elemento ul (algo irrelevante en el ejemplo anterior, ya que el elemento no contiene texto) debe especificar:

"//body//*[not(ancestor-or-self::ul[@class='relativeNav']) and not(self::script)]"

Respuesta popular

Espero que esto sea lo que necesiten:

HtmlDocument doc = new HtmlDocument();
var nodesToExclude1 = doc.DocumentNode.SelectNodes("//ul[@class='relativeNav']");
var nodesToExclude2 = doc.DocumentNode.SelectNodes("//body//script");
var requiredNodes = doc.DocumentNode.SelectNodes("//")
                       .Where(node => !nodesToExclude1.Contains(node) &&
                                      !nodesToExclude2.Contains(node));

foreach (HtmlNode node in requiredNodes)
{
    Console.WriteLine("Node: " + node);
    singleString += node.InnerText.Trim() + "\n";
}


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow