Module: Jam

Defined in:
lib/jam/engine.rb,
lib/jam/rexml.rb,
lib/jam/hpricot.rb,
lib/jam/template.rb,
lib/jam/css2xpath.rb,
lib/jam/css_to_xpath.rb,
lib/jam/nokogiri.rb,
lib/jam/libxml.rb

Overview

css_to_xpath - generic CSS to XPath selector transformer

Defined Under Namespace

Modules: CSStoXPath Classes: Engine, Hpricot, LibXML, Nokogiri, REXML, Template

Class Method Summary collapse

Class Method Details

.css_to_xpath(css) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
87
88
89
# File 'lib/jam/css2xpath.rb', line 3

def self.css_to_xpath(rule)
  regElement    = /^([#.]?)([a-z0-9\\*_-]*)((\|)([a-z0-9\\*_-]*))?/i
  regAttr1      = /^\[([^\]]*)\]/i
  regAttr2      = /^\[\s*([^~=\s]+)\s*(~?=)\s*"([^"]+)"\s*\]/i
  regPseudo     = /^:([a-z_-])+/i
  regCombinator = /^(\s*[>+\s])?/i
  regComma      = /^\s*,/i

  index = 1;
  parts = ["//", "*"]
  lastRule = nil

  while rule.length && rule != lastRule
    lastRule = rule

    # Trim leading whitespace
    rule = rule.gsub(/^\s*|\s*$/, "")  #.replace
    break if rule.length == 0

    # Match the element identifier
    m = regElement.match(rule)
    if m
      if !m[1]
        # XXXjoe Namespace ignored for now
        if m[5]
          parts[index] = m[5]
        else
          parts[index] = m[2]
        end
      elsif (m[1] == '#')
          parts.push("[@id='" + m[2] + "']") 
      elsif (m[1] == '.')
          parts.push("[contains(@class, '" + m[2] + "')]") 
      end        
      rule = rule.substr(m[0].length)
    end

    # Match attribute selectors
    m = regAttr2.match(rule)
    if m
      if m[2] == "~="
        parts.push("[contains(@" + m[1] + ", '" + m[3] + "')]")
      else
        parts.push("[@" + m[1] + "='" + m[3] + "']")
      end
      rule = rule.substr(m[0].length)
    else
      m = regAttr1.match(rule)
      if m
        parts.push("[@" + m[1] + "]")
        rule = rule.substr(m[0].length)
      end
    end

    # Skip over pseudo-classes and pseudo-elements, which are of no use to us
    m = regPseudo.match(rule)
    while m
      rule = rule.substr(m[0].length)
      m = regPseudo.match(rule)
    end

    # Match combinators
    m = regCombinator.match(rule)
    if m && m[0].length
      if m[0].index(">")
        parts.push("/")
      elsif m[0].index("+")
        parts.push("/following-sibling::")
      else
        parts.push("//")
      end
      index = parts.length
      parts.push("*")
      rule = rule.substr(m[0].length)
    end

    m = regComma.match(rule)
    if m
      parts.push(" | ", "//", "*")
      index = parts.length - 1
      rule = rule.substr(m[0].length)
    end
  end
  
  xpath = parts.join("")
  return xpath
end