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;
}
}
}