Ich verwende HtmlAgilityPack, um einen Dokumentbaum um eine Ebene nach dem anderen zu durchlaufen. Es scheint jedoch, dass der Aufruf von node.Descendants(0)
den gesamten Knotenbaum zurückgibt.
Hinweis: Ich habe versucht, in meine verbatim-HTML-Zeichenfolge einzufügen, aber der SE-Parser hat es nicht gefallen, also habe ich es als Snippet hinzugefügt.
<html>
<head>
<meta name="generator"
content="HTML Tidy for HTML5 (experimental) for Windows https://github.com/w3c/tidy-html5/tree/c63cc39" />
<title></title>
</head>
<body>
<p id="p1" class="newline">
<span id="span1" class="bold">
<span id="span2" class="literal">BOLD TEXT</span>
</span>
</p>
</body>
</html>
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var lines = doc.DocumentNode.Descendants().Where(x => x.HasClass("newline")).ToArray();
Console.WriteLine(string.Join("\r\n", lines[0].Descendants(0)
.Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));
Was der obige Code macht, sind die Nachkommen des ersten p
Tags. Wenn ich als Argument 0
oder 1
, wird der gesamte Knotenbaum zurückgegeben und darunter ausgegeben. Die Sache ist, dass der Textknoten, der BOLD TEXT
enthält, 3 Ebenen unterhalb des p
Tags verschachtelt ist. Mit dem obigen Code würde ich nur erwarten, dass es einen span1
, span1
, und dann einen anderen span1
.
Was mache ich falsch in meinem Aufruf an .Descendants
?
#text
span span1
#text
span span2
#text BOLD TEXT
#text
#text
Bearbeiten: Eine temporäre Problemumgehung besteht darin, sicherzustellen, dass Sie nur Nachkommen erhalten, deren Eltern dem aktuellen Knoten entsprechen. Immer noch auf der Suche nach einer praktischeren Lösung.
Console.WriteLine(string.Join("\r\n", lines[0].Descendants(0)
.Where(x => x.ParentNode == lines[0])
.Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));
Ich habe das gleiche Problem, fing an zu googeln und fand deine Frage :). Und dann habe ich beschlossen, Entwickler direkt zu fragen . Und hier ist eine kurze Version der Antwort:
Laut Code verhält es sich anders:
/// <summary>
/// Gets all Descendant nodes in enumerated list
/// </summary>
/// <returns></returns>
public IEnumerable<HtmlNode> Descendants(int level)
{
if (level > HtmlDocument.MaxDepthLevel)
{
throw new ArgumentException(HtmlNode.DepthLevelExceptionMessage);
}
foreach (HtmlNode node in ChildNodes)
{
yield return node;
foreach (HtmlNode descendant in node.Descendants(level + 1))
{
yield return descendant;
}
}
}
Es nimmt alle Nachkommen und nimmt childs, indem es den Level um eins erhöht, bis kein Nachfolger oder der maximale Level erreicht ist (int.MaxValue). Allerdings stimme ich Ihnen zu, sollte es wahrscheinlich Nachkommen zurückgeben, bis das angegebene Niveau erreicht ist. Leider werden wir aus Gründen der Abwärtskompatibilität wahrscheinlich nichts für diese Methode tun, um die aktuellen Anwendungen nicht zu beeinflussen.
In Ihrem Fall kann ChildNodes
anstelle von Descendants(0)
. Der Code sieht folgendermaßen aus:
Console.WriteLine(string.Join("\r\n", lines[0].ChildNodes
.Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));