# -*- coding: utf-8 -*- require 'rexml/document' module CFPropertyList228 # XML parser class ReXMLParser < ParserInterface # read a XML file # opts:: # * :file - The filename of the file to load # * :data - The data to parse def load(opts) doc = nil if(opts.has_key?(:file)) then File.open(opts[:file], "rb") { |fd| doc = REXML::Document.new(fd) } else doc = REXML::Document.new(opts[:data]) end if doc root = doc.root.elements[1] return import_xml(root) end rescue REXML::ParseException => e raise CFFormatError.new('invalid XML: ' + e.message) end # serialize CFPropertyList228 object to XML # opts = {}:: Specify options: :formatted - Use indention and line breaks def to_str(opts={}) doc = REXML::Document.new @doc = doc doc.context[:attribute_quote] = :quote doc.add_element 'plist', {'version' => '1.0'} doc.root << opts[:root].to_xml(self) formatter = if opts[:formatted] then f = REXML::Formatters::Pretty.new(2) f.compact = true f else REXML::Formatters::Default.new end str = formatter.write(doc.root, "") str1 = "\n\n" + str + "\n" str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding) return str1 end def new_node(name) REXML::Element.new(name) end def new_text(val) val end def append_node(parent, child) if child.is_a?(String) then parent.add_text child else parent.elements << child end parent end protected # get the value of a DOM node def get_value(n) content = n.text content.force_encoding('UTF-8') if content.respond_to?(:force_encoding) content end # import the XML values def import_xml(node) ret = nil case node.name when 'dict' hsh = Hash.new key = nil if node.has_elements? then node.elements.each do |n| next if n.name == '#text' # avoid a bug of libxml next if n.name == '#comment' if n.name == "key" then key = get_value(n) key = '' if key.nil? # REXML returns nil if key is empty else raise CFFormatError.new("Format error!") if key.nil? hsh[key] = import_xml(n) key = nil end end end if hsh['CF$UID'] and hsh.keys.length == 1 ret = CFUid.new(hsh['CF$UID'].value) else ret = CFDictionary.new(hsh) end when 'array' ary = Array.new if node.has_elements? then node.elements.each do |n| next if n.name == '#text' # avoid a bug of libxml ary.push import_xml(n) end end ret = CFArray.new(ary) when 'true' ret = CFBoolean.new(true) when 'false' ret = CFBoolean.new(false) when 'real' ret = CFReal.new(get_value(node).to_f) when 'integer' ret = CFInteger.new(get_value(node).to_i) when 'string' ret = CFString.new(get_value(node)) ret.value = '' if ret.value.nil? # REXML returns nil for empty elements' .text attribute when 'data' ret = CFData.new(get_value(node)) when 'date' ret = CFDate.new(CFDate.parse_date(get_value(node))) end return ret end end end # eof