How to map CSS selectors to XPath queries

Sunday, 24 Sep 2006

Over in the use Perl journals, Tatsuhiko Miyagawa wondered whether CSS selectors can be translated to XPath – which, of course, they can. Like him, however, I discovered that there isn’t any easily found table of equivalents that shows how selectors map to queries (though quite a lot of working Javascript to do such a conversion). Maybe that’s because to people versed in XPath, it’s really quite straightforward and obvious, but I decided to take 5 minutes to knock out some Google fodder.

So here you go:

Overview from the CSS Level 2 selectors spec with added XPath equivalents
CSS Pattern XPath equivalent Meaning
* * Matches any element.
E E Matches any E element (i.e., an element of type E).
E F E//F Matches any F element that is a descendant of an E element.
E > F E/F Matches any F element that is a child of an element E.
E:first-child *[1]/self::E Matches element E when E is the first child of its parent.
E:lang(c) E[ @xml:lang = "c"
or starts-with( @xml:lang, concat( "c", "-" ) ) ]
Matches element of type E if it is in (human) language c (the document language specifies how language is determined).
E + F E/following-sibling::*[1]/self::F Matches any F element immediately preceded by an element E.
E[foo] E[ @foo ] Matches any E element with the "foo" attribute set (whatever the value).
E[foo="warning"] E[ @foo = "warning" ] Matches any E element whose "foo" attribute value is exactly equal to "warning".
E[foo~="warning"] E[ contains(
concat( " ", @foo, " " ),
concat( " ", "warning", " " )
) ]
Matches any E element whose "foo" attribute value is a list of space-separated values, one of which is exactly equal to "warning".
E[lang|="en"] E[ @lang = "en"
or starts-with( @lang, concat( "en", "-" ) ) ]
Matches any E element whose "lang" attribute has a hyphen-separated list of values beginning (from the left) with "en".
DIV.warning DIV[ contains(
concat( " ", @class, " " ),
concat( " ", "warning", " " )
) ]
HTML only. The same as DIV[class~="warning"].
E#myid E[ @id = "myid" ] Matches any E element ID equal to "myid".

Obviously, the E:link, E:visited, E:active, E:hover and E:focus selectors have no equivalent XPath query so I left them out.

The table in the spec doesn’t include examples of the shorthand notation for class or ID selectors that apply to any element (.warning and #myid, respectively), but they’re simply the same as *.warning and *#myid, from which follows how to translate them.

Lastly, any XPath query translated from a CSS selector needs to begin with //.

That’s all there is to it.