diff --git a/readme.md b/readme.md index 7ab9a27..92ede23 100644 --- a/readme.md +++ b/readme.md @@ -26,6 +26,11 @@ At the moment, supports the following CSS selector features: - [Attribute selector](https://www.w3.org/TR/selectors-3/#attribute-selectors) - [Class selector](https://www.w3.org/TR/selectors-3/#class-html) - [ID selector](https://www.w3.org/TR/selectors-3/#id-selectors) +- [Pseudo-classes](https://www.w3.org/TR/selectors-3/#pseudo-classes): + * [:checked](https://www.w3.org/TR/selectors-3/#checked) + * [:first-child](https://www.w3.org/TR/selectors-3/#first-child-pseudo) + * [:last-child](https://www.w3.org/TR/selectors-3/#last-child-pseudo) + * [:only-child](https://www.w3.org/TR/selectors-3/#only-child-pseudo) And all [combinators](https://www.w3.org/TR/selectors-3/#combinators) diff --git a/src/Css/Css.cs b/src/Css/Css.cs index 82cd1ab..008e573 100644 --- a/src/Css/Css.cs +++ b/src/Css/Css.cs @@ -170,6 +170,13 @@ record LastChildSelector : SimpleSelector public override void Append(StringBuilder builder) => builder.Append("[not(following-sibling::*)]"); } +record OnlyChildSelector : SimpleSelector +{ + public static SimpleSelector Default { get; } = new OnlyChildSelector(); + OnlyChildSelector() { } + public override void Append(StringBuilder builder) => builder.Append("[not(preceding-sibling::*) and not(following-sibling::*)]"); +} + enum Combinator { None, diff --git a/src/Css/Parser.cs b/src/Css/Parser.cs index 511d558..fa64a81 100644 --- a/src/Css/Parser.cs +++ b/src/Css/Parser.cs @@ -81,11 +81,13 @@ class Parser from identifier in Span.EqualTo("checked") .Or(Span.EqualTo("first-child")) .Or(Span.EqualTo("last-child")) + .Or(Span.EqualTo("only-child")) select identifier.ToStringValue() switch { "checked" => CheckedSelector.Default, "first-child" => FirstChildSelector.Default, "last-child" => LastChildSelector.Default, + "only-child" => OnlyChildSelector.Default, _ => throw new NotSupportedException() }) .Named("checked pseudo selector"); diff --git a/src/Tests/XPathTests.cs b/src/Tests/XPathTests.cs index d73223f..d6c0a2a 100644 --- a/src/Tests/XPathTests.cs +++ b/src/Tests/XPathTests.cs @@ -44,6 +44,7 @@ public void ToXPath(string css, string xpath) [InlineData("option:checked", "second")] [InlineData("div:first-child", "Warning Hello")] [InlineData("div:last-child", "Footer")] + [InlineData("h1:only-child", "Sub-header")] [Theory] public void EvaluatePageHtml(string expression, string value) => Assert.Equal(value, string.Join(' ', XDocument.Load("page.html") diff --git a/src/Tests/page.html b/src/Tests/page.html index a541581..356fbe1 100644 --- a/src/Tests/page.html +++ b/src/Tests/page.html @@ -4,7 +4,10 @@
Warning
-

para

+

Header

+

+

Sub-header

+

Hello
1