# File lib/action_controller/vendor/html-scanner/html/selector.rb, line 520
    def simple_selector(statement, values, can_negate = true)
      tag_name = nil
      attributes = []
      pseudo = []
      negation = []

      # Element name. (Note that in negation, this can come at
      # any order, but for simplicity we allow if only first).
      statement.sub!(/^(\*|[[:alpha:]][\w\-]*)/) do |match|
        match.strip!
        tag_name = match.downcase unless match == "*"
        @source << match
        "" # Remove
      end

      # Get identifier, class, attribute name, pseudo or negation.
      while true
        # Element identifier.
        next if statement.sub!(/^#(\?|[\w\-]+)/) do |match|
          id = $1
          if id == "?"
            id = values.shift
          end
          @source << "##{id}"
          id = Regexp.new("^#{Regexp.escape(id.to_s)}$") unless id.is_a?(Regexp)
          attributes << ["id", id]
          "" # Remove
        end

        # Class name.
        next if statement.sub!(/^\.([\w\-]+)/) do |match|
          class_name = $1
          @source << ".#{class_name}"
          class_name = Regexp.new("(^|\s)#{Regexp.escape(class_name)}($|\s)") unless class_name.is_a?(Regexp)
          attributes << ["class", class_name]
          "" # Remove
        end

        # Attribute value.
        next if statement.sub!(/^\[\s*([[:alpha:]][\w\-:]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match|
          name, equality, value = $1, $2, $3
          if value == "?"
            value = values.shift
          else
            # Handle single and double quotes.
            value.strip!
            if (value[0] == ?" || value[0] == ?') && value[0] == value[-1]
              value = value[1..-2]
            end
          end
          @source << "[#{name}#{equality}'#{value}']"
          attributes << [name.downcase.strip, attribute_match(equality, value)]
          "" # Remove
        end

        # Root element only.
        next if statement.sub!(/^:root/) do |match|
          pseudo << lambda do |element|
            element.parent.nil? || !element.parent.tag?
          end
          @source << ":root"
          "" # Remove
        end

        # Nth-child including last and of-type.
        next if statement.sub!(/^:nth-(last-)?(child|of-type)\((odd|even|(\d+|\?)|(-?\d*|\?)?n([+\-]\d+|\?)?)\)/) do |match|
          reverse = $1 == "last-"
          of_type = $2 == "of-type"
          @source << ":nth-#{$1}#{$2}("
          case $3
            when "odd"
              pseudo << nth_child(2, 1, of_type, reverse)
              @source << "odd)"
            when "even"
              pseudo << nth_child(2, 2, of_type, reverse)
              @source << "even)"
            when /^(\d+|\?)$/  # b only
              b = ($1 == "?" ? values.shift : $1).to_i
              pseudo << nth_child(0, b, of_type, reverse)
              @source << "#{b})"
            when /^(-?\d*|\?)?n([+\-]\d+|\?)?$/
              a = ($1 == "?" ? values.shift :
                   $1 == "" ? 1 : $1 == "-" ? -1 : $1).to_i
              b = ($2 == "?" ? values.shift : $2).to_i
              pseudo << nth_child(a, b, of_type, reverse)
              @source << (b >= 0 ? "#{a}n+#{b})" : "#{a}n#{b})")
            else
              raise ArgumentError, "Invalid nth-child #{match}"
          end
          "" # Remove
        end
        # First/last child (of type).
        next if statement.sub!(/^:(first|last)-(child|of-type)/) do |match|
          reverse = $1 == "last"
          of_type = $2 == "of-type"
          pseudo << nth_child(0, 1, of_type, reverse)
          @source << ":#{$1}-#{$2}"
          "" # Remove
        end
        # Only child (of type).
        next if statement.sub!(/^:only-(child|of-type)/) do |match|
          of_type = $1 == "of-type"
          pseudo << only_child(of_type)
          @source << ":only-#{$1}"
          "" # Remove
        end

        # Empty: no child elements or meaningful content (whitespaces
        # are ignored).
        next if statement.sub!(/^:empty/) do |match|
          pseudo << lambda do |element|
            empty = true
            for child in element.children
              if child.tag? || !child.content.strip.empty?
                empty = false
                break
              end
            end
            empty
          end
          @source << ":empty"
          "" # Remove
        end
        # Content: match the text content of the element, stripping
        # leading and trailing spaces.
        next if statement.sub!(/^:content\(\s*(\?|'[^']*'|"[^"]*"|[^)]*)\s*\)/) do |match|
          content = $1
          if content == "?"
            content = values.shift
          elsif (content[0] == ?" || content[0] == ?') && content[0] == content[-1]
            content = content[1..-2]
          end
          @source << ":content('#{content}')"
          content = Regexp.new("^#{Regexp.escape(content.to_s)}$") unless content.is_a?(Regexp)
          pseudo << lambda do |element|
            text = ""
            for child in element.children
              unless child.tag?
                text << child.content
              end
            end
            text.strip =~ content
          end
          "" # Remove
        end

        # Negation. Create another simple selector to handle it.
        if statement.sub!(/^:not\(\s*/, "")
          raise ArgumentError, "Double negatives are not missing feature" unless can_negate
          @source << ":not("
          negation << simple_selector(statement, values, false)
          raise ArgumentError, "Negation not closed" unless statement.sub!(/^\s*\)/, "")
          @source << ")"
          next
        end

        # No match: moving on.
        break
      end

      # Return hash. The keys are mapped to instance variables.
      {:tag_name=>tag_name, :attributes=>attributes, :pseudo=>pseudo, :negation=>negation}
    end