AngleSharp by AngleSharp

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

.NET API 1,214,976 bytes

 Node

Represents a node in the generated tree.
using AngleSharp.Dom.Collections; using AngleSharp.Extensions; using AngleSharp.Html; using System; using System.IO; using System.Runtime.CompilerServices; using System.Text; namespace AngleSharp.Dom { internal abstract class Node : EventTarget, INode, IEventTarget, IMarkupFormattable, IEquatable<INode> { private static readonly ConditionalWeakTable<Node, Document> Owners = new ConditionalWeakTable<Node, Document>(); private readonly NodeType _type; private readonly string _name; private readonly NodeFlags _flags; private Url _baseUri; private Node _parent; private NodeList _children; public bool HasChildNodes => _children.Length != 0; public string BaseUri => BaseUrl?.Href ?? string.Empty; public Url BaseUrl { get { if (_baseUri != null) return _baseUri; if (_parent != null) return _parent.BaseUrl; Document owner = Owner; if (owner != null) return owner._baseUri ?? owner.DocumentUrl; if (_type == NodeType.Document) { owner = (Document)this; return owner.DocumentUrl; } return null; } set { _baseUri = value; } } public NodeType NodeType => _type; public virtual string NodeValue { get { return null; } set { } } public virtual string TextContent { get { return null; } set { } } INode INode.PreviousSibling { get { return PreviousSibling; } } INode INode.NextSibling { get { return NextSibling; } } INode INode.FirstChild { get { return FirstChild; } } INode INode.LastChild { get { return LastChild; } } IDocument INode.Owner { get { return Owner; } } INode INode.Parent { get { return _parent; } } public IElement ParentElement => _parent as IElement; INodeList INode.ChildNodes { get { return _children; } } public string NodeName => _name; internal Node PreviousSibling { get { if (_parent != null) { int length = _parent._children.Length; for (int i = 1; i < length; i++) { if (_parent._children[i] == this) return _parent._children[i - 1]; } } return null; } } internal Node NextSibling { get { if (_parent != null) { int num = _parent._children.Length - 1; for (int i = 0; i < num; i++) { if (_parent._children[i] == this) return _parent._children[i + 1]; } } return null; } } internal Node FirstChild { get { if (_children.Length <= 0) return null; return _children[0]; } } internal Node LastChild { get { if (_children.Length <= 0) return null; return _children[_children.Length - 1]; } } internal NodeFlags Flags => _flags; internal NodeList ChildNodes { get { return _children; } set { _children = value; } } internal Node Parent { get { return _parent; } set { _parent = value; } } internal Document Owner { get { Document value = null; if (_type != NodeType.Document) Owners.TryGetValue(this, out value); return value; } set { Document owner = Owner; if (owner != value) { Owners.Remove(this); Owners.Add(this, value); for (int i = 0; i < _children.Length; i++) { _children[i].Owner = value; } if (owner != null) NodeIsAdopted(owner); } } } internal Node(Document owner, string name, NodeType type = NodeType.Element, NodeFlags flags = NodeFlags.None) { Owners.Add(this, owner); _name = (name ?? string.Empty); _type = type; _children = this.CreateChildren(); _flags = flags; } internal void AppendText(string s) { TextNode textNode = LastChild as TextNode; if (textNode == null) AddNode(new TextNode(Owner, s)); else textNode.Append(s); } internal void InsertText(int index, string s) { if (index > 0 && index <= _children.Length && _children[index - 1].NodeType == NodeType.Text) ((IText)_children[index - 1]).Append(s); else if (index >= 0 && index < _children.Length && _children[index].NodeType == NodeType.Text) { ((IText)_children[index]).Insert(0, s); } else { TextNode node = new TextNode(Owner, s); InsertNode(index, node); } } public virtual void ToHtml(TextWriter writer, IMarkupFormatter formatter) { writer.Write(TextContent); } public INode AppendChild(INode child) { return this.PreInsert(child, null); } public INode InsertChild(int index, INode child) { Node child2 = (index < _children.Length) ? _children[index] : null; return this.PreInsert(child, child2); } public INode InsertBefore(INode newElement, INode referenceElement) { return this.PreInsert(newElement, referenceElement); } public INode ReplaceChild(INode newChild, INode oldChild) { return ReplaceChild(newChild as Node, oldChild as Node, false); } public INode RemoveChild(INode child) { return this.PreRemove(child); } public abstract INode Clone(bool deep = true); public DocumentPositions CompareDocumentPosition(INode otherNode) { if (this == otherNode) return DocumentPositions.Same; if (Owner != otherNode.Owner) { DocumentPositions documentPositions = (otherNode.GetHashCode() > GetHashCode()) ? DocumentPositions.Following : DocumentPositions.Preceding; return DocumentPositions.Disconnected | DocumentPositions.ImplementationSpecific | documentPositions; } if (otherNode.IsAncestorOf(this)) return DocumentPositions.Preceding | DocumentPositions.Contains; if (otherNode.IsDescendantOf(this)) return DocumentPositions.Following | DocumentPositions.ContainedBy; if (otherNode.IsPreceding(this)) return DocumentPositions.Preceding; return DocumentPositions.Following; } public bool Contains(INode otherNode) { return this.IsInclusiveAncestorOf(otherNode); } public void Normalize() { for (int i = 0; i < _children.Length; i++) { TextNode text = _children[i] as TextNode; if (text != null) { int length = text.Length; if (length == 0) { RemoveChild(text, false); i--; } else { StringBuilder stringBuilder = Pool.NewStringBuilder(); TextNode sibling = text; int end = i; Document owner = Owner; while ((sibling = (sibling.NextSibling as TextNode)) != null) { stringBuilder.Append(sibling.Data); end++; owner.ForEachRange((AngleSharp.Dom.Collections.Range m) => m.Head == sibling, delegate(AngleSharp.Dom.Collections.Range m) { m.StartWith(text, length); }); owner.ForEachRange((AngleSharp.Dom.Collections.Range m) => m.Tail == sibling, delegate(AngleSharp.Dom.Collections.Range m) { m.EndWith(text, length); }); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Head == sibling.Parent) return m.Start == end; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.StartWith(text, length); }); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Tail == sibling.Parent) return m.End == end; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.EndWith(text, length); }); length += sibling.Length; } text.Replace(text.Length, 0, stringBuilder.ToPool()); for (int num = end; num > i; num--) { RemoveChild(_children[num], false); } } } else if (_children[i].HasChildNodes) { _children[i].Normalize(); } } } public string LookupNamespaceUri(string prefix) { if (string.IsNullOrEmpty(prefix)) prefix = null; return LocateNamespace(prefix); } public string LookupPrefix(string namespaceUri) { if (string.IsNullOrEmpty(namespaceUri)) return null; return LocatePrefix(namespaceUri); } public bool IsDefaultNamespace(string namespaceUri) { if (string.IsNullOrEmpty(namespaceUri)) namespaceUri = null; string other = LocateNamespace(null); return namespaceUri.Is(other); } public virtual bool Equals(INode otherNode) { if (BaseUri.Is(otherNode.BaseUri) && NodeName.Is(otherNode.NodeName) && ChildNodes.Length == otherNode.ChildNodes.Length) { for (int i = 0; i < _children.Length; i++) { if (!_children[i].Equals(otherNode.ChildNodes[i])) return false; } return true; } return false; } protected static void GetPrefixAndLocalName(string qualifiedName, ref string namespaceUri, out string prefix, out string localName) { if (!qualifiedName.IsXmlName()) throw new DomException(DomError.InvalidCharacter); if (!qualifiedName.IsQualifiedName()) throw new DomException(DomError.Namespace); if (string.IsNullOrEmpty(namespaceUri)) namespaceUri = null; int num = qualifiedName.IndexOf(':'); if (num > 0) { prefix = qualifiedName.Substring(0, num); localName = qualifiedName.Substring(num + 1); } else { prefix = null; localName = qualifiedName; } if (IsNamespaceError(prefix, namespaceUri, qualifiedName)) throw new DomException(DomError.Namespace); } protected static bool IsNamespaceError(string prefix, string namespaceUri, string qualifiedName) { if ((prefix == null || namespaceUri != null) && (!prefix.Is(NamespaceNames.XmlPrefix) || namespaceUri.Is(NamespaceNames.XmlUri)) && ((!qualifiedName.Is(NamespaceNames.XmlNsPrefix) && !prefix.Is(NamespaceNames.XmlNsPrefix)) || namespaceUri.Is(NamespaceNames.XmlNsUri))) { if (namespaceUri.Is(NamespaceNames.XmlNsUri)) { if (!qualifiedName.Is(NamespaceNames.XmlNsPrefix)) return !prefix.Is(NamespaceNames.XmlNsPrefix); return false; } return false; } return true; } protected virtual string LocateNamespace(string prefix) { return _parent?.LocateNamespace(prefix); } protected virtual string LocatePrefix(string namespaceUri) { return _parent?.LocatePrefix(namespaceUri); } internal void ChangeOwner(Document document) { Document owner = Owner; _parent?.RemoveChild(this, false); Owner = document; NodeIsAdopted(owner); } internal void InsertNode(int index, Node node) { node.Parent = this; _children.Insert(index, node); } internal void AddNode(Node node) { node.Parent = this; _children.Add(node); } internal void RemoveNode(int index, Node node) { node.Parent = null; _children.RemoveAt(index); } internal void ReplaceAll(Node node, bool suppressObservers) { Document owner = Owner; if (node != null) owner.AdoptNode(node); NodeList nodeList = new NodeList(); NodeList nodeList2 = new NodeList(); nodeList.AddRange(_children); if (node != null) { if (node.NodeType == NodeType.DocumentFragment) nodeList2.AddRange(node._children); else nodeList2.Add(node); } for (int i = 0; i < nodeList.Length; i++) { RemoveChild(nodeList[i], true); } for (int j = 0; j < nodeList2.Length; j++) { InsertBefore(nodeList2[j], null, true); } if (!suppressObservers) owner.QueueMutation(MutationRecord.ChildList(this, nodeList2, nodeList, null, null)); } internal INode InsertBefore(Node newElement, Node referenceElement, bool suppressObservers) { Document owner = Owner; int count = (newElement.NodeType != NodeType.DocumentFragment) ? 1 : newElement.ChildNodes.Length; if (referenceElement != null && owner != null) { int childIndex = referenceElement.Index(); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Head == this) return m.Start > childIndex; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.StartWith(this, m.Start + count); }); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Tail == this) return m.End > childIndex; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.EndWith(this, m.End + count); }); } if (newElement.NodeType == NodeType.Document || newElement.Contains(this)) throw new DomException(DomError.HierarchyRequest); NodeList nodeList = new NodeList(); int num = _children.Index(referenceElement); if (num == -1) num = _children.Length; if (newElement._type == NodeType.DocumentFragment) { int num2 = num; int i = num; while (newElement.HasChildNodes) { Node node = newElement.ChildNodes[0]; newElement.RemoveChild(node, true); InsertNode(num2, node); num2++; } for (; i < num2; i++) { Node node2 = _children[i]; nodeList.Add(node2); NodeIsInserted(node2); } } else { nodeList.Add(newElement); InsertNode(num, newElement); NodeIsInserted(newElement); } if (!suppressObservers && owner != null) owner.QueueMutation(MutationRecord.ChildList(this, nodeList, null, (num > 0) ? _children[num - 1] : null, referenceElement)); return newElement; } internal void RemoveChild(Node node, bool suppressObservers) { Document owner = Owner; int index = _children.Index(node); if (owner != null) { owner.ForEachRange((AngleSharp.Dom.Collections.Range m) => m.Head.IsInclusiveDescendantOf(node), delegate(AngleSharp.Dom.Collections.Range m) { m.StartWith(this, index); }); owner.ForEachRange((AngleSharp.Dom.Collections.Range m) => m.Tail.IsInclusiveDescendantOf(node), delegate(AngleSharp.Dom.Collections.Range m) { m.EndWith(this, index); }); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Head == this) return m.Start > index; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.StartWith(this, m.Start - 1); }); owner.ForEachRange(delegate(AngleSharp.Dom.Collections.Range m) { if (m.Tail == this) return m.End > index; return false; }, delegate(AngleSharp.Dom.Collections.Range m) { m.EndWith(this, m.End - 1); }); } Node node2 = (index > 0) ? _children[index - 1] : null; if (!suppressObservers && owner != null) { NodeList removedNodes = new NodeList { node }; owner.QueueMutation(MutationRecord.ChildList(this, null, removedNodes, node2, node.NextSibling)); owner.AddTransientObserver(node); } RemoveNode(index, node); NodeIsRemoved(node, node2); } internal INode ReplaceChild(Node node, Node child, bool suppressObservers) { if (this.IsEndPoint() || node.IsHostIncludingInclusiveAncestor(this)) throw new DomException(DomError.HierarchyRequest); if (child.Parent != this) throw new DomException(DomError.NotFound); if (node.IsInsertable()) { IDocument document = _parent as IDocument; Node nextSibling = child.NextSibling; Document owner = Owner; NodeList nodeList = new NodeList(); NodeList nodeList2 = new NodeList(); if (document != null) { bool flag = false; switch (node._type) { case NodeType.DocumentType: flag = (document.Doctype != child || child.IsPrecededByElement()); break; case NodeType.Element: flag = (document.DocumentElement != child || child.IsFollowedByDoctype()); break; case NodeType.DocumentFragment: { int elementCount = node.GetElementCount(); flag = (elementCount > 1 || node.HasTextNodes() || (elementCount == 1 && (document.DocumentElement != child || child.IsFollowedByDoctype()))); break; } } if (flag) throw new DomException(DomError.HierarchyRequest); } if (nextSibling == node) nextSibling = node.NextSibling; if (owner != null) owner.AdoptNode(node); RemoveChild(child, true); InsertBefore(node, nextSibling, true); nodeList2.Add(child); if (node._type == NodeType.DocumentFragment) nodeList.AddRange(node._children); else nodeList.Add(node); if (!suppressObservers && owner != null) owner.QueueMutation(MutationRecord.ChildList(this, nodeList, nodeList2, child.PreviousSibling, nextSibling)); return child; } throw new DomException(DomError.HierarchyRequest); } internal virtual void NodeIsAdopted(Document oldDocument) { } internal virtual void NodeIsInserted(Node newNode) { newNode.OnParentChanged(); } internal virtual void NodeIsRemoved(Node removedNode, Node oldPreviousSibling) { removedNode.OnParentChanged(); } protected virtual void OnParentChanged() { } protected void CloneNode(Node target, bool deep) { target._baseUri = _baseUri; if (deep) { foreach (INode child in _children) { target.AddNode((Node)child.Clone(true)); } } } } }