diff --git a/src/AngleSharp.XPath.Tests/AngleSharp.XPath.Tests.csproj b/src/AngleSharp.XPath.Tests/AngleSharp.XPath.Tests.csproj
index 01e6733..5a2cd1b 100644
--- a/src/AngleSharp.XPath.Tests/AngleSharp.XPath.Tests.csproj
+++ b/src/AngleSharp.XPath.Tests/AngleSharp.XPath.Tests.csproj
@@ -1,15 +1,15 @@
-
-
-
-
+
+
+
+
- netcoreapp3.0
+ net6.0
false
-
\ No newline at end of file
+
diff --git a/src/AngleSharp.XPath.Tests/HtmlDocumentNavigatorTests.cs b/src/AngleSharp.XPath.Tests/HtmlDocumentNavigatorTests.cs
index 2c017ad..202e7fe 100644
--- a/src/AngleSharp.XPath.Tests/HtmlDocumentNavigatorTests.cs
+++ b/src/AngleSharp.XPath.Tests/HtmlDocumentNavigatorTests.cs
@@ -3,6 +3,8 @@
using AngleSharp.Html.Parser;
using NUnit.Framework;
using System.Threading.Tasks;
+using System.Xml.XPath;
+using AngleSharp.Dom;
namespace AngleSharp.XPath.Tests
{
@@ -99,5 +101,77 @@ public void SelectSingleNode_DontIgnoreNamespaces_ShouldReturnNode()
Assert.IsNotNull(node);
Assert.That(node.NodeName, Is.EqualTo("xhtml:link"));
}
+
+ [Test]
+ public void SelectNodes_CanReturnAttribute()
+ {
+ // Arrange
+ var html = "
hello world
";
+ var parser = new HtmlParser();
+ var doc = parser.ParseDocument(html);
+
+ // Act
+ var nodes = doc.DocumentElement.SelectNodes("//@*");
+
+ // Assert
+ Assert.IsNotNull(nodes);
+ Assert.That(nodes, Has.Count.EqualTo(2));
+ Assert.That(nodes, Is.All.InstanceOf());
+ }
+
+ [Test]
+ public void TestNameXPathFunctionOnXMLDoc()
+ {
+ // Arrange
+ var xml = @"TestTest
";
+ var angleSharpXmlDoc = new XmlParser().ParseDocument(xml);
+
+ // Act
+ var xmlNav = angleSharpXmlDoc.CreateNavigator();
+
+ // Assert
+ Assert.AreEqual(TagNames.Html, xmlNav.Evaluate("name()"));
+ }
+
+ [Test]
+ public void TestNameXPathFunctionOnHTMLDoc()
+ {
+ // Arrange
+ var html = @"TestTest
";
+
+ var angleSharpHtmlDoc = new HtmlParser().ParseDocument(html);
+
+ // Act
+ var htmlNav = angleSharpHtmlDoc.CreateNavigator();
+
+ // Assert
+ Assert.AreEqual(TagNames.Html, htmlNav.Evaluate("name()"));
+ }
+
+ [Test]
+ public void MoveToParent_CallWhenCurrentNodeIsAttr_ShouldBeMovedToAttrOwnerElement()
+ {
+ // Arrange
+ var xml = @"foo";
+ var parser = new XmlParser();
+ var doc = parser.ParseDocument(xml);
+ var nav = doc.CreateNavigator(false);
+ nav.MoveToChild("root", "");
+
+ // Act
+
+ if (nav.MoveToFirstAttribute())
+ {
+ do
+ {
+ Assert.AreEqual(nav.NodeType, XPathNodeType.Attribute);
+ }
+ while (nav.MoveToNextAttribute());
+ nav.MoveToParent();
+ }
+
+ // Assert
+ Assert.AreEqual(nav.Name, "root");
+ }
}
}
diff --git a/src/AngleSharp.XPath/AngleSharp.XPath.csproj b/src/AngleSharp.XPath/AngleSharp.XPath.csproj
index e802bd8..f116ac4 100644
--- a/src/AngleSharp.XPath/AngleSharp.XPath.csproj
+++ b/src/AngleSharp.XPath/AngleSharp.XPath.csproj
@@ -1,13 +1,13 @@
- 1.1.7
+ 2.0.0
+ 2.0.0
+ 2.0.0
Denis Ivanov
AngleSharp.XPath
- 1.1.7
AngleSharp.XPath
AngleSharp.XPath
- netstandard2.0
- 1.1.7
+ netstandard2.0;net461;net472;net6.0
XPath support for AngleSharp
https://github.com/AngleSharp/AngleSharp.XPath/
MIT
@@ -16,10 +16,15 @@
Key.snk
true
True
+ https://raw.githubusercontent.com/AngleSharp/AngleSharp.XPath/master/logo.png
-
+
+
+
+
+
diff --git a/src/AngleSharp.XPath/HtmlDocumentNavigator.cs b/src/AngleSharp.XPath/HtmlDocumentNavigator.cs
index 3638473..34d1051 100644
--- a/src/AngleSharp.XPath/HtmlDocumentNavigator.cs
+++ b/src/AngleSharp.XPath/HtmlDocumentNavigator.cs
@@ -10,7 +10,6 @@ public class HtmlDocumentNavigator : XPathNavigator
{
private readonly IDocument _document;
private INode _currentNode;
- private int _attrIndex;
private readonly bool _ignoreNamespaces;
///
@@ -24,7 +23,6 @@ public HtmlDocumentNavigator(IDocument document, INode currentNode, bool ignoreN
_document = document ?? throw new ArgumentNullException(nameof(document));
NameTable = new NameTable();
_currentNode = currentNode ?? throw new ArgumentNullException(nameof(currentNode));
- _attrIndex = -1;
_ignoreNamespaces = ignoreNamespaces;
}
@@ -49,15 +47,28 @@ public HtmlDocumentNavigator(IDocument document, INode currentNode, bool ignoreN
///
public override string LocalName =>
- _attrIndex != -1
- ? NameTable.GetOrAdd(CurrentElement.Attributes[_attrIndex].LocalName)
+ CurrentNode is IAttr attr
+ ? attr.LocalName
: NameTable.GetOrAdd(CurrentNode is IElement e ? e.LocalName : string.Empty);
///
- public override string Name =>
- _attrIndex != -1
- ? NameTable.GetOrAdd(CurrentElement.Attributes[_attrIndex].Name)
- : NameTable.GetOrAdd(_currentNode.NodeName);
+ public override string Name
+ {
+ get
+ {
+ if (CurrentNode is IAttr attr)
+ {
+ return NameTable.GetOrAdd(attr.Name);
+ }
+
+ if (CurrentElement != null)
+ {
+ return NameTable.GetOrAdd(CurrentElement.LocalName);
+ }
+
+ return NameTable.GetOrAdd(_currentNode.NodeName);
+ }
+ }
///
public override string NamespaceURI
@@ -69,16 +80,16 @@ public override string NamespaceURI
return string.Empty;
}
- return _attrIndex != -1
- ? NameTable.GetOrAdd(CurrentElement.Attributes[_attrIndex].NamespaceUri ?? string.Empty)
+ return CurrentNode is IAttr attr
+ ? NameTable.GetOrAdd(attr.NamespaceUri ?? string.Empty)
: NameTable.GetOrAdd(CurrentElement?.NamespaceUri ?? string.Empty);
}
}
///
public override string Prefix =>
- _attrIndex != 1
- ? NameTable.GetOrAdd(CurrentElement.Attributes[_attrIndex].Prefix ?? string.Empty)
+ CurrentNode is IAttr attr
+ ? NameTable.GetOrAdd(attr.Prefix ?? string.Empty)
: NameTable.GetOrAdd(CurrentElement?.Prefix ?? string.Empty);
///
@@ -107,7 +118,7 @@ public override XPathNodeType NodeType
return XPathNodeType.Element;
case Dom.NodeType.Element:
- return _attrIndex != -1 ? XPathNodeType.Attribute : XPathNodeType.Element;
+ return XPathNodeType.Element;
case Dom.NodeType.ProcessingInstruction:
return XPathNodeType.ProcessingInstruction;
@@ -155,7 +166,7 @@ public override string Value
return documentType.Name;
case Dom.NodeType.Element:
- return _attrIndex != -1 ? CurrentElement.Attributes[_attrIndex].Value : _currentNode.TextContent;
+ return _currentNode.TextContent;
case Dom.NodeType.Entity:
return _currentNode.TextContent;
@@ -207,7 +218,6 @@ public override bool MoveTo(XPathNavigator other)
if (navigator._document == _document)
{
_currentNode = navigator._currentNode;
- _attrIndex = navigator._attrIndex;
return true;
}
@@ -218,8 +228,8 @@ public override bool MoveTo(XPathNavigator other)
public override bool MoveToFirstAttribute()
{
if (HasAttributes)
- {
- _attrIndex = 0;
+ {
+ _currentNode = CurrentElement.Attributes[0];
return true;
}
@@ -278,12 +288,24 @@ public override bool MoveToNextAttribute()
return false;
}
- if (_attrIndex >= CurrentElement.Attributes.Length - 1)
+ if (!(CurrentNode is IAttr attr))
+ {
+ return false;
+ }
+
+ if (attr.OwnerElement == null)
+ {
+ return false;
+ }
+
+ var attrIndex = attr.OwnerElement.Attributes.Index(attr);
+
+ if (attrIndex >= CurrentElement.Attributes.Length - 1)
{
- return false;
+ return false;
}
- _attrIndex++;
+ _currentNode = attr.OwnerElement.Attributes[attrIndex + 1];
return true;
}
@@ -296,6 +318,12 @@ public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope)
///
public override bool MoveToParent()
{
+ if (CurrentNode is IAttr attr)
+ {
+ _currentNode = attr.OwnerElement;
+ return true;
+ }
+
if (_currentNode.Parent == null)
{
return false;