class HTML::Node

def parse(parent, line, pos, content, strict=true)

def parse(parent, line, pos, content, strict=true)
  if content !~ /^<\S/
    Text.new(parent, line, pos, content)
  else
    scanner = StringScanner.new(content)
    unless scanner.skip(/</)
      if strict
        raise "expected <"
      else
        return Text.new(parent, line, pos, content)
      end
    end
    if scanner.skip(/!\[CDATA\[/)
      unless scanner.skip_until(/\]\]>/)
        if strict
          raise "expected ]]> (got #{scanner.rest.inspect} for #{content})"
        else
          scanner.skip_until(/\Z/)
        end
      end
      return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
    end
    closing = ( scanner.scan(/\//) ? :close : nil )
    return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
    name.downcase!
    unless closing
      scanner.skip(/\s*/)
      attributes = {}
      while attr = scanner.scan(/[-\w:]+/)
        value = true
        if scanner.scan(/\s*=\s*/)
          if delim = scanner.scan(/['"]/)
            value = ""
            while text = scanner.scan(/[^#{delim}\\]+|./)
              case text
                when "\\" then
                  value << text
                  break if scanner.eos?
                  value << scanner.getch
                when delim
                  break
                else value << text
              end
            end
          else
            value = scanner.scan(/[^\s>\/]+/)
          end
        end
        attributes[attr.downcase] = value
        scanner.skip(/\s*/)
      end
      closing = ( scanner.scan(/\//) ? :self : nil )
    end
    unless scanner.scan(/\s*>/)
      if strict
        raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
      else
        # throw away all text until we find what we're looking for
        scanner.skip_until(/>/) or scanner.terminate
      end
    end
    Tag.new(parent, line, pos, name, attributes, closing)
  end
end