Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 296457bd464dd9dc0aa58ca58b01f0293ef0a626 0 parents
@wycats authored
7 css.rb
@@ -0,0 +1,7 @@
+$:.unshift File.dirname(__FILE__)
+require 'css/node'
+require 'css/xpath_visitor'
+require 'css/generated_tokenizer'
+require 'css/generated_parser'
+require 'css/tokenizer'
+require 'css/parser'
653 css/generated_parser.rb
@@ -0,0 +1,653 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by racc 1.4.5
+# from racc grammer file "lib/nokogiri/css/parser.y".
+#
+
+require 'racc/parser'
+
+
+module Nokogiri
+
+ module CSS
+
+ class GeneratedParser < Racc::Parser
+
+##### racc 1.4.5 generates ###
+
+racc_reduce_table = [
+ 0, 0, :racc_error,
+ 4, 46, :_reduce_1,
+ 1, 46, :_reduce_2,
+ 2, 49, :_reduce_3,
+ 2, 49, :_reduce_4,
+ 2, 49, :_reduce_5,
+ 1, 49, :_reduce_6,
+ 2, 49, :_reduce_7,
+ 2, 49, :_reduce_8,
+ 2, 50, :_reduce_9,
+ 2, 50, :_reduce_10,
+ 1, 50, :_reduce_none,
+ 2, 50, :_reduce_12,
+ 1, 50, :_reduce_13,
+ 3, 48, :_reduce_14,
+ 1, 48, :_reduce_none,
+ 2, 57, :_reduce_16,
+ 1, 51, :_reduce_17,
+ 1, 51, :_reduce_18,
+ 6, 55, :_reduce_19,
+ 6, 55, :_reduce_20,
+ 5, 55, :_reduce_21,
+ 2, 54, :_reduce_22,
+ 3, 54, :_reduce_23,
+ 3, 54, :_reduce_24,
+ 3, 54, :_reduce_25,
+ 1, 59, :_reduce_none,
+ 1, 59, :_reduce_none,
+ 4, 60, :_reduce_28,
+ 3, 60, :_reduce_29,
+ 2, 60, :_reduce_30,
+ 1, 60, :_reduce_31,
+ 2, 61, :_reduce_32,
+ 2, 61, :_reduce_33,
+ 1, 52, :_reduce_none,
+ 0, 52, :_reduce_none,
+ 2, 56, :_reduce_36,
+ 2, 56, :_reduce_37,
+ 2, 56, :_reduce_38,
+ 2, 56, :_reduce_39,
+ 1, 56, :_reduce_none,
+ 1, 56, :_reduce_none,
+ 1, 56, :_reduce_none,
+ 1, 56, :_reduce_none,
+ 1, 62, :_reduce_44,
+ 4, 58, :_reduce_45,
+ 4, 58, :_reduce_46,
+ 0, 58, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 5, 53, :_reduce_55,
+ 1, 64, :_reduce_none,
+ 2, 47, :_reduce_none,
+ 0, 47, :_reduce_none ]
+
+racc_reduce_n = 59
+
+racc_shift_n = 97
+
+racc_action_table = [
+ 5, 79, 81, 27, 10, 26, 94, 93, 42, 2,
+ 42, 30, 56, 5, 5, 28, 79, 81, 10, 42,
+ 42, 42, 47, 2, 51, 42, 42, 10, 82, 84,
+ 85, 52, 78, 10, 10, 7, 9, 12, 15, 42,
+ 10, 17, 77, 82, 84, 85, 10, 78, 7, 7,
+ 9, 12, 15, 42, 5, 17, 68, 77, 10, 9,
+ 69, 15, 10, 2, 17, 9, 9, 15, 15, 50,
+ 17, 17, 9, 5, 15, 26, 21, 17, 9, 54,
+ 15, 23, 63, 17, 37, 38, 39, 64, 42, 7,
+ 9, 12, 15, 44, 9, 17, 15, 42, 15, 17,
+ 76, 42, 86, 31, 42, 89, 42, 25, 7, 91,
+ 33, 92, 34, 35, 53, 42, 42 ]
+
+racc_action_check = [
+ 0, 73, 73, 6, 0, 7, 90, 90, 63, 0,
+ 28, 7, 29, 17, 55, 6, 71, 71, 55, 33,
+ 34, 35, 17, 55, 22, 37, 38, 4, 73, 73,
+ 73, 23, 73, 1, 11, 0, 0, 0, 0, 42,
+ 67, 0, 73, 71, 71, 71, 14, 71, 17, 55,
+ 55, 55, 55, 44, 36, 55, 50, 71, 36, 4,
+ 52, 4, 16, 36, 4, 1, 11, 1, 11, 21,
+ 1, 11, 67, 41, 67, 5, 5, 67, 14, 27,
+ 14, 5, 41, 14, 13, 13, 13, 41, 64, 36,
+ 36, 36, 36, 16, 16, 36, 16, 65, 18, 16,
+ 69, 15, 72, 9, 75, 80, 83, 5, 41, 87,
+ 13, 88, 13, 13, 24, 93, 94 ]
+
+racc_action_pointer = [
+ -2, 27, nil, nil, 21, 65, 3, -5, nil, 92,
+ nil, 28, nil, 77, 40, 92, 56, 11, 58, nil,
+ nil, 62, -18, 20, 72, nil, nil, 79, 1, -30,
+ nil, nil, nil, 10, 11, 12, 52, 16, 17, nil,
+ nil, 71, 30, nil, 44, nil, nil, nil, nil, nil,
+ 40, nil, 53, nil, nil, 12, nil, nil, nil, nil,
+ nil, nil, nil, -1, 79, 88, nil, 34, nil, 84,
+ nil, 13, 61, -2, nil, 95, nil, nil, nil, nil,
+ 64, nil, nil, 97, nil, nil, nil, 68, 69, nil,
+ -4, nil, nil, 106, 107, nil, nil ]
+
+racc_action_default = [
+ -59, -42, -17, -13, -41, -59, -59, -59, -2, -59,
+ -44, -43, -18, -15, -40, -58, -35, -59, -11, -38,
+ -37, -31, -59, -26, -59, -22, -27, -59, -58, -59,
+ -26, -16, -39, -58, -58, -58, -59, -58, -58, -6,
+ -36, -59, -58, -34, -58, -9, -10, -33, -32, -12,
+ -59, -23, -30, -24, 97, -59, -25, -5, -8, -7,
+ -14, -3, -4, -58, -58, -58, -57, -59, -29, -59,
+ -1, -47, -59, -47, -56, -58, -28, -48, -52, -53,
+ -59, -54, -49, -58, -50, -51, -21, -59, -59, -19,
+ -59, -20, -55, -58, -58, -45, -46 ]
+
+racc_goto_table = [
+ 41, 19, 8, 80, 20, 87, 48, 22, 6, 29,
+ 49, 32, 46, 55, 40, 45, 43, 36, 57, 58,
+ 59, 24, 61, 62, 75, nil, nil, 66, nil, 67,
+ 65, nil, nil, nil, nil, nil, nil, nil, 60, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 71, 72,
+ 73, nil, nil, nil, nil, nil, nil, 70, nil, nil,
+ 88, nil, nil, nil, nil, nil, nil, 74, 90, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 95, 96 ]
+
+racc_goto_check = [
+ 2, 11, 3, 13, 11, 13, 9, 14, 1, 14,
+ 10, 11, 8, 2, 11, 7, 11, 4, 2, 2,
+ 2, 15, 2, 2, 19, nil, nil, 2, nil, 2,
+ 9, nil, nil, nil, nil, nil, nil, nil, 3, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 2, 2,
+ 2, nil, nil, nil, nil, nil, nil, 3, nil, nil,
+ 2, nil, nil, nil, nil, nil, nil, 11, 2, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 2, 2 ]
+
+racc_goto_pointer = [
+ nil, 8, -15, 2, 4, nil, nil, -1, -4, -11,
+ -8, 0, nil, -68, 2, 16, nil, nil, nil, -43 ]
+
+racc_goto_default = [
+ nil, nil, nil, nil, nil, 13, 16, nil, nil, 18,
+ 1, 3, 4, nil, nil, nil, 11, 14, 83, nil ]
+
+racc_token_table = {
+ false => 0,
+ Object.new => 1,
+ :FUNCTION => 2,
+ :INCLUDES => 3,
+ :DASHMATCH => 4,
+ :LBRACE => 5,
+ :HASH => 6,
+ :PLUS => 7,
+ :GREATER => 8,
+ :S => 9,
+ :STRING => 10,
+ :IDENT => 11,
+ :COMMA => 12,
+ :URI => 13,
+ :CDO => 14,
+ :CDC => 15,
+ :NUMBER => 16,
+ :PERCENTAGE => 17,
+ :LENGTH => 18,
+ :EMS => 19,
+ :EXS => 20,
+ :ANGLE => 21,
+ :TIME => 22,
+ :FREQ => 23,
+ :IMPORTANT_SYM => 24,
+ :IMPORT_SYM => 25,
+ :MEDIA_SYM => 26,
+ :PAGE_SYM => 27,
+ :CHARSET_SYM => 28,
+ :DIMENSION => 29,
+ :PREFIXMATCH => 30,
+ :SUFFIXMATCH => 31,
+ :SUBSTRINGMATCH => 32,
+ :TILDE => 33,
+ :NOT_EQUAL => 34,
+ :SLASH => 35,
+ :DOUBLESLASH => 36,
+ :NOT => 37,
+ "." => 38,
+ "*" => 39,
+ "[" => 40,
+ "]" => 41,
+ ")" => 42,
+ ":" => 43,
+ "=" => 44 }
+
+racc_use_result_var = true
+
+racc_nt_base = 45
+
+Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+
+Racc_token_to_s_table = [
+'$end',
+'error',
+'FUNCTION',
+'INCLUDES',
+'DASHMATCH',
+'LBRACE',
+'HASH',
+'PLUS',
+'GREATER',
+'S',
+'STRING',
+'IDENT',
+'COMMA',
+'URI',
+'CDO',
+'CDC',
+'NUMBER',
+'PERCENTAGE',
+'LENGTH',
+'EMS',
+'EXS',
+'ANGLE',
+'TIME',
+'FREQ',
+'IMPORTANT_SYM',
+'IMPORT_SYM',
+'MEDIA_SYM',
+'PAGE_SYM',
+'CHARSET_SYM',
+'DIMENSION',
+'PREFIXMATCH',
+'SUFFIXMATCH',
+'SUBSTRINGMATCH',
+'TILDE',
+'NOT_EQUAL',
+'SLASH',
+'DOUBLESLASH',
+'NOT',
+'"."',
+'"*"',
+'"["',
+'"]"',
+'")"',
+'":"',
+'"="',
+'$start',
+'selector',
+'s_0toN',
+'simple_selector_1toN',
+'combinator',
+'simple_selector',
+'element_name',
+'hcap_0toN',
+'negation',
+'function',
+'attrib',
+'hcap_1toN',
+'class',
+'attrib_val_0or1',
+'expr',
+'an_plus_b',
+'pseudo',
+'attribute_id',
+'eql_incl_dash',
+'negation_arg']
+
+Racc_debug_parser = false
+
+##### racc system variables end #####
+
+ # reduce 0 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 13
+ def _reduce_1( val, _values, result )
+ result = [val.first, val.last].flatten
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 13
+ def _reduce_2( val, _values, result )
+ result = val.flatten
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 16
+ def _reduce_3( val, _values, result )
+ result = :DIRECT_ADJACENT_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 17
+ def _reduce_4( val, _values, result )
+ result = :CHILD_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 18
+ def _reduce_5( val, _values, result )
+ result = :PRECEDING_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 19
+ def _reduce_6( val, _values, result )
+ result = :DESCENDANT_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 20
+ def _reduce_7( val, _values, result )
+ result = :DESCENDANT_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 21
+ def _reduce_8( val, _values, result )
+ result = :CHILD_SELECTOR
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 31
+ def _reduce_9( val, _values, result )
+ result = if val[1].nil?
+ val.first
+ else
+ Node.new(:CONDITIONAL_SELECTOR, [val.first, val[1]])
+ end
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 34
+ def _reduce_10( val, _values, result )
+ result = Node.new(:CONDITIONAL_SELECTOR, val)
+ result
+ end
+.,.,
+
+ # reduce 11 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 38
+ def _reduce_12( val, _values, result )
+ result = Node.new(:CONDITIONAL_SELECTOR, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 43
+ def _reduce_13( val, _values, result )
+ result = Node.new(:CONDITIONAL_SELECTOR,
+ [Node.new(:ELEMENT_NAME, ['*']), val.first]
+ )
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 48
+ def _reduce_14( val, _values, result )
+ result = Node.new(val[1], [val.first, val.last])
+ result
+ end
+.,.,
+
+ # reduce 15 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 51
+ def _reduce_16( val, _values, result )
+ result = Node.new(:CLASS_CONDITION, [val[1]])
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 54
+ def _reduce_17( val, _values, result )
+ result = Node.new(:ELEMENT_NAME, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 55
+ def _reduce_18( val, _values, result )
+ result = Node.new(:ELEMENT_NAME, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 63
+ def _reduce_19( val, _values, result )
+ result = Node.new(:ATTRIBUTE_CONDITION,
+ [Node.new(:ELEMENT_NAME, [val[2]])] + (val[4] || [])
+ )
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 68
+ def _reduce_20( val, _values, result )
+ result = Node.new(:ATTRIBUTE_CONDITION,
+ [val[2]] + (val[4] || [])
+ )
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 74
+ def _reduce_21( val, _values, result )
+ # Non standard, but hpricot supports it.
+ result = Node.new(:PSEUDO_CLASS,
+ [Node.new(:FUNCTION, ['nth-child(', val[2]])]
+ )
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 79
+ def _reduce_22( val, _values, result )
+ result = Node.new(:FUNCTION, [val.first.strip])
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 82
+ def _reduce_23( val, _values, result )
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 85
+ def _reduce_24( val, _values, result )
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 88
+ def _reduce_25( val, _values, result )
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
+ result
+ end
+.,.,
+
+ # reduce 26 omitted
+
+ # reduce 27 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 102
+ def _reduce_28( val, _values, result )
+ if val[1] == 'n'
+ result = Node.new(:AN_PLUS_B, val)
+ else
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
+ end
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 113
+ def _reduce_29( val, _values, result )
+ # n+3, -n+3
+ if val[0] == 'n'
+ val.unshift("1")
+ result = Node.new(:AN_PLUS_B, val)
+ elsif val[0] == '-n'
+ val[0] = 'n'
+ val.unshift("-1")
+ result = Node.new(:AN_PLUS_B, val)
+ else
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
+ end
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 124
+ def _reduce_30( val, _values, result )
+ if val[1] == 'n'
+ val << "+"
+ val << "0"
+ result = Node.new(:AN_PLUS_B, val)
+ else
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
+ end
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 136
+ def _reduce_31( val, _values, result )
+ if val[0] == 'even'
+ val = ["2","n","+","0"]
+ result = Node.new(:AN_PLUS_B, val)
+ elsif val[0] == 'odd'
+ val = ["2","n","+","1"]
+ result = Node.new(:AN_PLUS_B, val)
+ else
+ raise Racc::ParseError, "parse error on IDENT '#{val[0]}'"
+ end
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 141
+ def _reduce_32( val, _values, result )
+ result = Node.new(:PSEUDO_CLASS, [val[1]])
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 141
+ def _reduce_33( val, _values, result )
+ result = Node.new(:PSEUDO_CLASS, [val[1]])
+ result
+ end
+.,.,
+
+ # reduce 34 omitted
+
+ # reduce 35 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 151
+ def _reduce_36( val, _values, result )
+ result = Node.new(:COMBINATOR, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 154
+ def _reduce_37( val, _values, result )
+ result = Node.new(:COMBINATOR, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 157
+ def _reduce_38( val, _values, result )
+ result = Node.new(:COMBINATOR, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 160
+ def _reduce_39( val, _values, result )
+ result = Node.new(:COMBINATOR, val)
+ result
+ end
+.,.,
+
+ # reduce 40 omitted
+
+ # reduce 41 omitted
+
+ # reduce 42 omitted
+
+ # reduce 43 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 166
+ def _reduce_44( val, _values, result )
+ result = Node.new(:ID, val)
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 169
+ def _reduce_45( val, _values, result )
+ result = [val.first, val[2]]
+ result
+ end
+.,.,
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 170
+ def _reduce_46( val, _values, result )
+ result = [val.first, val[2]]
+ result
+ end
+.,.,
+
+ # reduce 47 omitted
+
+ # reduce 48 omitted
+
+ # reduce 49 omitted
+
+ # reduce 50 omitted
+
+ # reduce 51 omitted
+
+ # reduce 52 omitted
+
+ # reduce 53 omitted
+
+ # reduce 54 omitted
+
+module_eval <<'.,.,', 'lib/nokogiri/css/parser.y', 186
+ def _reduce_55( val, _values, result )
+ result = Node.new(:NOT, [val[2]])
+ result
+ end
+.,.,
+
+ # reduce 56 omitted
+
+ # reduce 57 omitted
+
+ # reduce 58 omitted
+
+ def _reduce_none( val, _values, result )
+ result
+ end
+
+ end # class GeneratedParser
+
+ end # module CSS
+
+end # module Nokogiri
159 css/generated_tokenizer.rb
@@ -0,0 +1,159 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by rex 1.0.1
+# from lexical definition file "lib/nokogiri/css/tokenizer.rex".
+#
+
+module Nokogiri
+module CSS
+class GeneratedTokenizer
+ require 'strscan'
+
+ class ScanError < StandardError ; end
+
+ attr_reader :lineno
+ attr_reader :filename
+
+ def scan_setup ; end
+
+ def action &block
+ yield
+ end
+
+ def scan_str( str )
+ scan_evaluate str
+ do_parse
+ end
+
+ def load_file( filename )
+ @filename = filename
+ open(filename, "r") do |f|
+ scan_evaluate f.read
+ end
+ end
+
+ def scan_file( filename )
+ load_file filename
+ do_parse
+ end
+
+ def next_token
+ @rex_tokens.shift
+ end
+
+ def scan_evaluate( str )
+ scan_setup
+ @rex_tokens = []
+ @lineno = 1
+ ss = StringScanner.new(str)
+ state = nil
+ until ss.eos?
+ text = ss.peek(1)
+ @lineno += 1 if text == "\n"
+ case state
+ when nil
+ case
+ when (text = ss.scan(/~=/i))
+ @rex_tokens.push action { [:INCLUDES, text] }
+
+ when (text = ss.scan(/\|=/i))
+ @rex_tokens.push action { [:DASHMATCH, text] }
+
+ when (text = ss.scan(/\^=/i))
+ @rex_tokens.push action { [:PREFIXMATCH, text] }
+
+ when (text = ss.scan(/\$=/i))
+ @rex_tokens.push action { [:SUFFIXMATCH, text] }
+
+ when (text = ss.scan(/\*=/i))
+ @rex_tokens.push action { [:SUBSTRINGMATCH, text] }
+
+ when (text = ss.scan(/!=/i))
+ @rex_tokens.push action { [:NOT_EQUAL, text] }
+
+ when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*\(\s*/i))
+ @rex_tokens.push action { [:FUNCTION, text] }
+
+ when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
+ @rex_tokens.push action { [:IDENT, text] }
+
+ when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
+ @rex_tokens.push action { [:IDENT, text] }
+
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)/i))
+ @rex_tokens.push action { [:NUMBER, text] }
+
+ when (text = ss.scan(/\#([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])+/i))
+ @rex_tokens.push action { [:HASH, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*\+/i))
+ @rex_tokens.push action { [:PLUS, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*>/i))
+ @rex_tokens.push action { [:GREATER, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*,/i))
+ @rex_tokens.push action { [:COMMA, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*~/i))
+ @rex_tokens.push action { [:TILDE, text] }
+
+ when (text = ss.scan(/\:not\(/i))
+ @rex_tokens.push action { [:NOT, text] }
+
+ when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
+ @rex_tokens.push action { [:ATKEYWORD, text] }
+
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)%/i))
+ @rex_tokens.push action { [:PERCENTAGE, text] }
+
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
+ @rex_tokens.push action { [:DIMENSION, text] }
+
+ when (text = ss.scan(/<!--/i))
+ @rex_tokens.push action { [:CDO, text] }
+
+ when (text = ss.scan(/-->/i))
+ @rex_tokens.push action { [:CDC, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*\/\//i))
+ @rex_tokens.push action { [:DOUBLESLASH, text] }
+
+ when (text = ss.scan(/[\s\r\n\f]*\//i))
+ @rex_tokens.push action { [:SLASH, text] }
+
+ when (text = ss.scan(/U\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?/i))
+ @rex_tokens.push action {[:UNICODE_RANGE, text] }
+
+ when (text = ss.scan(/\/\*(.|[\r\n])*?\*\//i))
+ ;
+
+ when (text = ss.scan(/[\s\t\r\n\f]+/i))
+ @rex_tokens.push action { [:S, text] }
+
+ when (text = ss.scan(/[\.*:\[\]=\)]/i))
+ @rex_tokens.push action { [text, text] }
+
+ when (text = ss.scan(/"([^\n\r\f"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*"|'([^\n\r\f']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*'/i))
+ @rex_tokens.push action { [:STRING, text] }
+
+ when (text = ss.scan(/\"([^\n\r\f\"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*|([^\n\r\f\']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
+ @rex_tokens.push action { [:INVALID, text] }
+
+ when (text = ss.scan(/./i))
+ @rex_tokens.push action { [text, text] }
+
+ else
+ text = ss.string[ss.pos .. -1]
+ raise ScanError, "can not match: '" + text + "'"
+ end # if
+
+ else
+ raise ScanError, "undefined state: '" + state.to_s + "'"
+ end # case state
+ end # until ss
+ end # def scan_evaluate
+
+end # class
+end
+end
95 css/node.rb
@@ -0,0 +1,95 @@
+module Nokogiri
+ module CSS
+ class Node
+ attr_accessor :type, :value
+ def initialize type, value
+ @type = type
+ @value = value
+ end
+
+ def accept visitor
+ visitor.send(:"visit_#{type.to_s.downcase}", self)
+ end
+
+ def to_xpath prefix = '//', preprocess = true
+ self.preprocess! if preprocess
+ prefix + XPathVisitor.new.accept(self)
+ end
+
+ def preprocess!
+ ### Deal with nth-child
+ matches = find_by_type(
+ [:CONDITIONAL_SELECTOR,
+ [:ELEMENT_NAME],
+ [:PSEUDO_CLASS,
+ [:FUNCTION]
+ ]
+ ]
+ )
+ matches.each do |match|
+ if match.value[1].value[0].value[0] =~ /^nth-child/
+ tag_name = match.value[0].value.first
+ match.value[0].value = ['*']
+ match.value[1] = Node.new(:COMBINATOR, [
+ match.value[1].value[0],
+ Node.new(:FUNCTION, ['self(', tag_name])
+ ])
+ end
+ if match.value[1].value[0].value[0] =~ /^nth-last-child/
+ tag_name = match.value[0].value.first
+ match.value[0].value = ['*']
+ match.value[1] = Node.new(:COMBINATOR, [
+ match.value[1].value[0],
+ Node.new(:FUNCTION, ['self(', tag_name])
+ ])
+ end
+ end
+
+ ### Deal with first-child, last-child
+ matches = find_by_type(
+ [:CONDITIONAL_SELECTOR,
+ [:ELEMENT_NAME], [:PSEUDO_CLASS]
+ ])
+ matches.each do |match|
+ if ['first-child', 'last-child'].include?(match.value[1].value.first)
+ which = match.value[1].value.first.gsub(/-\w*$/, '')
+ tag_name = match.value[0].value.first
+ match.value[0].value = ['*']
+ match.value[1] = Node.new(:COMBINATOR, [
+ Node.new(:FUNCTION, ["#{which}("]),
+ Node.new(:FUNCTION, ['self(', tag_name])
+ ])
+ elsif 'only-child' == match.value[1].value.first
+ tag_name = match.value[0].value.first
+ match.value[0].value = ['*']
+ match.value[1] = Node.new(:COMBINATOR, [
+ Node.new(:FUNCTION, ["#{match.value[1].value.first}("]),
+ Node.new(:FUNCTION, ['self(', tag_name])
+ ])
+ end
+ end
+
+ self
+ end
+
+ def find_by_type(types)
+ matches = []
+ matches << self if to_type == types
+ @value.each do |v|
+ matches += v.find_by_type(types) if v.respond_to?(:find_by_type)
+ end
+ matches
+ end
+
+ def to_type
+ [@type] + @value.map { |n|
+ n.to_type if n.respond_to?(:to_type)
+ }.compact
+ end
+
+ def to_a
+ [@type] + @value.map { |n| n.to_a }
+ end
+ end
+ end
+end
24 css/parser.rb
@@ -0,0 +1,24 @@
+module Nokogiri
+ module CSS
+ class Parser < GeneratedParser
+ class << self
+ def parse string
+ new.parse(string)
+ end
+ end
+
+ def initialize
+ @tokenizer = Tokenizer.new
+ end
+
+ def parse string
+ @tokenizer.scan string
+ do_parse
+ end
+
+ def next_token
+ @tokenizer.next_token
+ end
+ end
+ end
+end
9 css/tokenizer.rb
@@ -0,0 +1,9 @@
+module Nokogiri
+ module CSS
+ class Tokenizer < GeneratedTokenizer
+ def scan(str)
+ scan_evaluate(str)
+ end
+ end
+ end
+end
155 css/xpath_visitor.rb
@@ -0,0 +1,155 @@
+module Nokogiri
+ module CSS
+ class XPathVisitor
+ def visit_function node
+ # note that nth-child and nth-last-child are preprocessed in css/node.rb.
+ case node.value.first
+ when /^text\(/
+ 'child::text()'
+ when /^self\(/
+ "self::#{node.value[1]}"
+ when /^(eq|nth|nth-of-type|nth-child)\(/
+ if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :AN_PLUS_B
+ an_plus_b(node.value[1])
+ else
+ "position() = " + node.value[1]
+ end
+ when /^(first|first-of-type)\(/
+ "position() = 1"
+ when /^(last|last-of-type)\(/
+ "position() = last()"
+ when /^(nth-last-child|nth-last-of-type)\(/
+ "position() = last() - #{node.value[1]}"
+ when /^contains\(/
+ "contains(., #{node.value[1]})"
+ when /^gt\(/
+ "position() > #{node.value[1]}"
+ when /^only-child\(/
+ "last() = 1"
+ else
+ node.value.first + ')'
+ end
+ end
+
+ def visit_not node
+ 'not(' + node.value.first.accept(self) + ')'
+ end
+
+ def visit_preceding_selector node
+ node.value.last.accept(self) +
+ '[preceding-sibling::' +
+ node.value.first.accept(self) +
+ ']'
+ end
+
+ def visit_direct_adjacent_selector node
+ node.value.last.accept(self) +
+ '[preceding-sibling::' +
+ node.value.first.accept(self) +
+ '][position()=1]'
+ end
+
+ def visit_id node
+ node.value.first =~ /^#(.*)$/
+ "@id = '#{$1}'"
+ end
+
+ def visit_attribute_condition node
+ attribute = if (node.value.first.type == :FUNCTION) or (node.value.first.value.first =~ /^@/)
+ ''
+ else
+ 'child::'
+ end
+ attribute += node.value.first.accept(self)
+
+ # Support non-standard css
+ attribute.gsub!(/^@@/, '@')
+
+ return attribute unless node.value.length == 3
+
+ value = node.value.last
+ value = "'#{value}'" if value !~ /^['"]/
+
+ case node.value[1]
+ when '*='
+ "contains(#{attribute}, #{value})"
+ when '~='
+ "contains(concat(\" \", #{attribute}, \" \"),concat(\" \", #{value}, \" \"))"
+ when '$='
+ "substring(#{attribute}, string-length(#{attribute}) - " +
+ "string-length(#{value}) + 1, string-length(#{value})) = #{value}"
+ else
+ attribute + " #{node.value[1]} " + "#{value}"
+ end
+ end
+
+ def visit_pseudo_class node
+ if node.value.first.is_a?(Nokogiri::CSS::Node) and node.value.first.type == :FUNCTION
+ node.value.first.accept(self)
+ else
+ case node.value.first
+ when "first" then "position() = 1"
+ when "last" then "position() = last()"
+ when "first-of-type" then "position() = 1"
+ when "last-of-type" then "position() = last()"
+ when "only-of-type" then "last() = 1"
+ when "empty" then "not(node())"
+ when "parent" then "node()"
+ else
+ '1 = 1'
+ end
+ end
+ end
+
+ def visit_class_condition node
+ "contains(concat(' ', @class, ' '), ' #{node.value.first} ')"
+ end
+
+ def visit_combinator node
+ node.value.first.accept(self) + ' and ' +
+ node.value.last.accept(self)
+ end
+
+ def visit_conditional_selector node
+ node.value.first.accept(self) + '[' +
+ node.value.last.accept(self) + ']'
+ end
+
+ def visit_descendant_selector node
+ node.value.first.accept(self) +
+ '//' +
+ node.value.last.accept(self)
+ end
+
+ def visit_child_selector node
+ node.value.first.accept(self) +
+ '/' +
+ node.value.last.accept(self)
+ end
+
+ def visit_element_name node
+ node.value.first
+ end
+
+ def accept node
+ node.accept(self)
+ end
+
+ private
+ def an_plus_b node
+ raise ArgumentError, "expected an+b node to contain 4 tokens, but is #{node.value.inspect}" unless node.value.size == 4
+
+ a = node.value[0].to_i
+ b = node.value[3].to_i
+
+ if (b == 0)
+ return "(position() mod #{a}) = 0"
+ else
+ compare = (a < 0) ? "<=" : ">="
+ return "(position() #{compare} #{b}) and (((position()-#{b}) mod #{a.abs}) = 0)"
+ end
+ end
+
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.