class Plist::StreamParser

Constants

COMMENT_END
COMMENT_START
DOCTYPE_PATTERN
TEXT
XMLDECL_PATTERN

Public Class Methods

new(plist_data_or_file, listener) click to toggle source
# File lib/plist/parser.rb, line 63
def initialize(plist_data_or_file, listener)
  if plist_data_or_file.respond_to? :read
    @xml = plist_data_or_file.read
  elsif File.exist? plist_data_or_file
    @xml = File.read(plist_data_or_file)
  else
    @xml = plist_data_or_file
  end

  @listener = listener
end

Public Instance Methods

parse() click to toggle source
# File lib/plist/parser.rb, line 81
def parse
  plist_tags = PTag.mappings.keys.join('|')
  start_tag  = /<(#{plist_tags})([^>]*)>/i
  end_tag    = /<\/(#{plist_tags})[^>]*>/i

  require 'strscan'

  @scanner = StringScanner.new(@xml)
  until @scanner.eos?
    if @scanner.scan(COMMENT_START)
      @scanner.scan(COMMENT_END)
    elsif @scanner.scan(XMLDECL_PATTERN)
      encoding = parse_encoding_from_xml_declaration(@scanner[1])
      next if encoding.nil?

      # use the specified encoding for the rest of the file
      next unless String.method_defined?(:force_encoding)
      @scanner.string = @scanner.rest.force_encoding(encoding)
    elsif @scanner.scan(DOCTYPE_PATTERN)
      next
    elsif @scanner.scan(start_tag)
      @listener.tag_start(@scanner[1], nil)
      if (@scanner[2] =~ /\/$/)
        @listener.tag_end(@scanner[1])
      end
    elsif @scanner.scan(TEXT)
      @listener.text(@scanner[1])
    elsif @scanner.scan(end_tag)
      @listener.tag_end(@scanner[1])
    else
      raise "Unimplemented element"
    end
  end
end

Private Instance Methods

parse_encoding_from_xml_declaration(xml_declaration) click to toggle source
# File lib/plist/parser.rb, line 118
def parse_encoding_from_xml_declaration(xml_declaration)
  return unless defined?(Encoding)

  xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/)

  return if xml_encoding.nil?

  begin
    Encoding.find(xml_encoding[1])
  rescue ArgumentError
    nil
  end
end