TreeWalker
The treewalker for walking through the DOM tree.
using AngleSharp.Extensions;
namespace AngleSharp.Dom.Collections
{
internal sealed class TreeWalker : ITreeWalker
{
private readonly INode _root;
private readonly FilterSettings _settings;
private readonly NodeFilter _filter;
private INode _current;
public INode Root => _root;
public FilterSettings Settings => _settings;
public NodeFilter Filter => _filter;
public INode Current {
get {
return _current;
}
set {
_current = value;
}
}
public TreeWalker(INode root, FilterSettings settings, NodeFilter filter)
{
_root = root;
_settings = settings;
_filter = (filter ?? ((NodeFilter)((INode m) => FilterResult.Accept)));
_current = _root;
}
public INode ToNext()
{
INode node = _current;
FilterResult filterResult = FilterResult.Accept;
while (node != null) {
while (filterResult != FilterResult.Reject && node.HasChildNodes) {
node = node.FirstChild;
filterResult = Check(node);
if (filterResult == FilterResult.Accept) {
_current = node;
return node;
}
}
while (node != _root) {
INode nextSibling = node.NextSibling;
if (nextSibling != null) {
node = nextSibling;
break;
}
node = node.Parent;
}
if (node == _root)
break;
filterResult = Check(node);
if (filterResult == FilterResult.Accept) {
_current = node;
return node;
}
}
return null;
}
public INode ToPrevious()
{
INode node = _current;
while (node != null && node != _root) {
INode previousSibling = node.PreviousSibling;
while (previousSibling != null) {
node = previousSibling;
FilterResult filterResult = Check(node);
while (filterResult != FilterResult.Reject && node.HasChildNodes) {
node = node.LastChild;
filterResult = Check(node);
if (filterResult == FilterResult.Accept) {
_current = node;
return node;
}
}
}
if (node == _root || node.Parent == null)
break;
if (Check(node) == FilterResult.Accept) {
_current = node;
return node;
}
}
return null;
}
public INode ToParent()
{
INode node = _current;
while (node != null && node != _root) {
node = node.Parent;
if (node != null && Check(node) == FilterResult.Accept) {
_current = node;
return node;
}
}
return null;
}
public INode ToFirst()
{
INode node = (_current != null) ? _current.FirstChild : null;
while (node != null) {
switch (Check(node)) {
case FilterResult.Accept:
_current = node;
return node;
case FilterResult.Skip: {
INode firstChild = node.FirstChild;
if (firstChild != null) {
node = firstChild;
break;
}
goto default;
}
default:
while (node != null) {
INode nextSibling = node.NextSibling;
if (nextSibling != null) {
node = nextSibling;
break;
}
INode parent = node.Parent;
if (parent == null || parent == _root || parent == _current) {
node = null;
break;
}
node = parent;
}
break;
}
}
return null;
}
public INode ToLast()
{
INode node = (_current != null) ? _current.LastChild : null;
while (node != null) {
switch (Check(node)) {
case FilterResult.Accept:
_current = node;
return node;
case FilterResult.Skip: {
INode lastChild = node.LastChild;
if (lastChild != null) {
node = lastChild;
break;
}
goto default;
}
default:
while (node != null) {
INode previousSibling = node.PreviousSibling;
if (previousSibling != null) {
node = previousSibling;
break;
}
INode parent = node.Parent;
if (parent == null || parent == _root || parent == _current) {
node = null;
break;
}
node = parent;
}
break;
}
}
return null;
}
public INode ToPreviousSibling()
{
INode node = _current;
if (node != _root) {
while (node != null) {
INode node2 = node.PreviousSibling;
while (node2 != null) {
node = node2;
FilterResult filterResult = Check(node);
if (filterResult == FilterResult.Accept) {
_current = node;
return node;
}
node2 = node.LastChild;
if (filterResult == FilterResult.Reject || node2 == null)
node2 = node.PreviousSibling;
}
node = node.Parent;
if (node == null || node == _root || Check(node) == FilterResult.Accept)
break;
}
}
return null;
}
public INode ToNextSibling()
{
INode node = _current;
if (node != _root) {
while (node != null) {
INode node2 = node.NextSibling;
while (node2 != null) {
node = node2;
FilterResult filterResult = Check(node);
if (filterResult == FilterResult.Accept) {
_current = node;
return node;
}
node2 = node.FirstChild;
if (filterResult == FilterResult.Reject || node2 == null)
node2 = node.NextSibling;
}
node = node.Parent;
if (node == null || node == _root || Check(node) == FilterResult.Accept)
break;
}
}
return null;
}
private FilterResult Check(INode node)
{
if (!_settings.Accepts(node))
return FilterResult.Skip;
return _filter(node);
}
}
}