Skip to content

Relative / Descendent Selectors #252

Description

@davebyrne

The documentation suggests that a selector when applied to an ElementRef will match against children/descendents of the element. This does not seem to be the case unless the css rule is prefixed by :scope. All selectors not prefixed by :scope seem to match against the root element, regardless of which ElementRef is used for matching.

The specific documentation for ElementRef::select says:

Returns an iterator over descendent elements matching a selector.

The following test case reproduces the behavior.


    #[test]
    fn test_relative_selector() { 
        let raw_html = r#"
            <html>                
                <body>
                    <article>
                        <div>
                            <h1>select me</h1>
                        </div>
                    </article>
                </body>
            </html>
            "#;
        let doc = Html::parse_document(raw_html);

        // this works
        let selector = Selector::parse("body > article > div > h1").unwrap();
        let el = doc.root_element().select(&selector).next();
        assert!(el.is_some());

        let article = doc.root_element()
            .select(&Selector::parse("body > article").unwrap())
            .next()
            .unwrap();

        // this works too. using :scope to indicate selector relative to the article element
        let scoped_selector = Selector::parse(":scope > div > h1").unwrap();
        let el = article.select(&scoped_selector).next();
        assert!(el.is_some());

        // this should not match relative to the article element, but it does match.
        let scoped_selector = Selector::parse("body > article > div > h1").unwrap();
        let el = article.select(&scoped_selector).next();
        assert!(el.is_none());

    }

Activity

  1. adamreichold commented on May 14, 2025

    @adamreichold
    Member

    I suspect that in addition to setting context_element (which is what :scope resolves to), we need to call nest_for_relative_selector in Selector::matches_with_scope_and_cache to set the context's relative_selector_anchor property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions