AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.8.0" />

 NodeExtensions

static class NodeExtensions
Useful methods for node objects.
using AngleSharp.Dom; using AngleSharp.Dom.Html; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace AngleSharp.Extensions { [DebuggerStepThrough] internal static class NodeExtensions { public static INode GetRoot(this INode node) { if (node.Parent == null) return node; return node.Parent.GetRoot(); } public static Url HyperReference(this INode node, string url) { if (url == null) return null; return new Url(node.BaseUrl, url); } public static bool IsDescendantOf(this INode node, INode parent) { if (node.Parent == null) return false; if (node.Parent == parent) return true; return node.Parent.IsDescendantOf(parent); } public static IEnumerable<INode> GetDescendants(this INode parent) { foreach (INode childNode in parent.ChildNodes) { yield return childNode; foreach (INode descendant in childNode.GetDescendants()) { yield return descendant; } } } public static bool IsInclusiveDescendantOf(this INode node, INode parent) { if (node != parent) return node.IsDescendantOf(parent); return true; } public static bool IsAncestorOf(this INode parent, INode node) { return node.IsDescendantOf(parent); } public static IEnumerable<INode> GetAncestors(this INode node) { while (true) { INode parent; node = (parent = node.Parent); if (parent == null) break; yield return node; } } public static IEnumerable<INode> GetInclusiveAncestors(this INode node) { INode parent; do { yield return node; node = (parent = node.Parent); } while (parent != null); } public static bool IsInclusiveAncestorOf(this INode parent, INode node) { if (node != parent) return node.IsDescendantOf(parent); return true; } public static bool HasDataListAncestor(this INode child) { return child.Ancestors<IHtmlDataListElement>().Any(); } public static bool IsSiblingOf(this INode node, INode element) { if (node.Parent != null) return node.Parent == element.Parent; return false; } public static int Index(this INode node) { return node.Parent.IndexOf(node); } public static int IndexOf(this INode parent, INode node) { int num = 0; if (parent != null) { foreach (INode childNode in parent.ChildNodes) { if (childNode == node) return num; num++; } } return -1; } public static bool IsPreceding(this INode before, INode after) { INode parent = before.Parent; if (parent == null) return false; if (parent == after) return true; if (parent == after.Parent) return parent.IndexOf(before) < parent.IndexOf(after); return parent.IsPreceding(after); } public static bool IsFollowing(this INode after, INode before) { return before.IsPreceding(after); } public static INode GetAssociatedHost(this INode node) { if (node is IDocumentFragment && node.Owner != null) return node.Owner.All.OfType<IHtmlTemplateElement>().FirstOrDefault((IHtmlTemplateElement m) => m.Content == node); return null; } public static bool IsHostIncludingInclusiveAncestor(this INode parent, INode node) { if (parent.IsInclusiveAncestorOf(node)) return true; INode associatedHost = node.GetRoot().GetAssociatedHost(); if (associatedHost != null) return parent.IsInclusiveAncestorOf(associatedHost); return false; } public static void EnsurePreInsertionValidity(this INode parent, INode node, INode child) { if ((!(parent is IDocument) && !(parent is IDocumentFragment) && !(parent is IElement)) || node.IsHostIncludingInclusiveAncestor(parent)) throw new DomException(ErrorCode.HierarchyRequest); if (child != null && child.Parent != parent) throw new DomException(ErrorCode.NotFound); if (!(node is IElement) && !(node is ICharacterData) && !(node is IDocumentType) && !(node is IDocumentFragment)) throw new DomException(ErrorCode.HierarchyRequest); IDocument document = parent as IDocument; if (document != null) { bool flag = false; switch (node.NodeType) { case NodeType.Element: flag = (document.DocumentElement != null || child is IDocumentType || child.IsFollowedByDoctype()); break; case NodeType.DocumentFragment: { int elementCount = node.GetElementCount(); flag = (elementCount > 1 || node.HasTextNodes() || (elementCount == 1 && document.DocumentElement != null) || child is IDocumentType || child.IsFollowedByDoctype()); break; } case NodeType.DocumentType: flag = (document.Doctype != null || (child != null && child.IsPrecededByElement()) || (child == null && document.DocumentElement != null)); break; case NodeType.Text: flag = true; break; } if (flag) throw new DomException(ErrorCode.HierarchyRequest); } else if (node is IDocumentType) { throw new DomException(ErrorCode.HierarchyRequest); } } public static INode PreInsert(this INode parent, INode node, INode child) { Node obj = parent as Node; Node node2 = node as Node; if (obj == null) throw new DomException(ErrorCode.NotSupported); parent.EnsurePreInsertionValidity(node, child); Node node3 = child as Node; if (node3 == node) node3 = node2.NextSibling; (parent.Owner ?? (parent as IDocument)).AdoptNode(node); obj.InsertBefore(node2, node3, false); return node; } public static INode PreRemove(this INode parent, INode child) { Node obj = parent as Node; if (obj == null) throw new DomException(ErrorCode.NotSupported); if (child == null || child.Parent != parent) throw new DomException(ErrorCode.NotFound); obj.RemoveChild(child as Node, false); return child; } public static bool HasTextNodes(this INode node) { return node.ChildNodes.OfType<IText>().Any(); } public static bool IsFollowedByDoctype(this INode child) { if (child == null) return false; bool flag = true; foreach (INode childNode in child.Parent.ChildNodes) { if (flag) flag = (childNode != child); else if (childNode.NodeType == NodeType.DocumentType) { return true; } } return false; } public static bool IsPrecededByElement(this INode child) { foreach (INode childNode in child.Parent.ChildNodes) { if (childNode == child) break; if (childNode.NodeType == NodeType.Element) return true; } return false; } public static int GetElementCount(this INode parent) { int num = 0; foreach (INode childNode in parent.ChildNodes) { if (childNode.NodeType == NodeType.Element) num++; } return num; } public static TNode FindChild<TNode>(this INode parent) where TNode : class, INode { if (parent == null) return null; for (int i = 0; i < parent.ChildNodes.Length; i++) { TNode val = parent.ChildNodes[i] as TNode; if (val != null) return val; } return null; } public static TNode FindDescendant<TNode>(this INode parent) where TNode : class, INode { if (parent == null) return null; for (int i = 0; i < parent.ChildNodes.Length; i++) { INode node = parent.ChildNodes[i]; TNode val = (node as TNode) ?? node.FindDescendant<TNode>(); if (val != null) return val; } return null; } } }