Module: Taurus::XML::CssToXPath
- Defined in:
- lib/taurus/xml/css_to_xpath.rb
Overview
Minimal CSS-to-XPath translator covering the common Nokogiri subset:
tag → //tag
* → //*
.class → //*[contains(concat(' ',@class,' '),' class ')]
#id → //*[@id='id']
[attr] → //*[@attr]
[attr=val] → //*[@attr='val']
tag[attr] → //tag[@attr]
tag[attr=val] → //tag[@attr='val']
parent > child → //parent/child
ancestor descendant → //ancestor//descendant
a, b → //a | //b
tag:first-child → //tag[position()=1]
tag:last-child → //tag[position()=last()]
tag:not(simple) → //tag[not(self::simple)]
For anything beyond this subset, raise ArgumentError. Callers can fall back to writing XPath directly via #xpath/#at_xpath.
Constant Summary collapse
- TAG_RE =
Token types in a single simple selector. tag (optional), then zero or more of: .class, #id, [attr...], :pseudo
/\A(\*|[\w-]+)/.freeze
- DOT_CLASS_RE =
/\A\.([\w-]+)/.freeze
- HASH_ID_RE =
/\A#([\w-]+)/.freeze
- BRACKET_RE =
/\A\[([^\]]+)\]/.freeze
- PSEUDO_RE =
/\A:([\w-]+(?:\([^)]*\))?)/.freeze
Class Method Summary collapse
- .convert(rule) ⇒ Object
- .convert_one(rule) ⇒ Object
-
.parse_simple(part) ⇒ Object
Parse a single simple selector into (tag, predicates) where predicates is an array of XPath fragments to be joined via [p1][p2]...
Class Method Details
.convert(rule) ⇒ Object
38 39 40 |
# File 'lib/taurus/xml/css_to_xpath.rb', line 38 def convert(rule) rule.to_s.split(COMMA_SPLIT).map { |r| convert_one(r.strip) }.join(" | ") end |
.convert_one(rule) ⇒ Object
42 43 44 45 46 47 48 49 50 51 |
# File 'lib/taurus/xml/css_to_xpath.rb', line 42 def convert_one(rule) return "//*" if rule == "*" # Tokenize chain first (handles > and whitespace) if rule =~ /\s/ || rule.include?(">") return convert_chain(rule) end convert_simple(rule, prefix: "//") end |
.parse_simple(part) ⇒ Object
Parse a single simple selector into (tag, predicates) where predicates is an array of XPath fragments to be joined via [p1][p2]...
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/taurus/xml/css_to_xpath.rb', line 55 def parse_simple(part) tag = "*" preds = [] s = part.strip if s =~ TAG_RE tag = $1 s = $' end until s.empty? case s when DOT_CLASS_RE preds << "contains(concat(' ',normalize-space(@class),' '),' #{$1} ')" s = $' when HASH_ID_RE preds << "@id='#{$1}'" s = $' when BRACKET_RE preds << convert_attrs($1) s = $' when PSEUDO_RE preds << convert_pseudo($1) s = $' else raise ArgumentError, "unsupported CSS selector at #{s.inspect} (in #{part.inspect})" end end [tag, preds] end |