1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
# -*- coding: utf-8 -*-
require 'libxml'
module CFPropertyList
# XML parser
class LibXMLParser < XMLParserInterface
# 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
doc = LibXML::XML::Document.file(opts[:file],:options => LibXML::XML::Parser::Options::NOBLANKS|LibXML::XML::Parser::Options::NOENT)
else
doc = LibXML::XML::Document.string(opts[:data],:options => LibXML::XML::Parser::Options::NOBLANKS|LibXML::XML::Parser::Options::NOENT)
end
if doc
root = doc.root.first
return import_xml(root)
end
rescue LibXML::XML::Error => e
raise CFFormatError.new('invalid XML: ' + e.message)
end
# serialize CFPropertyList object to XML
# opts = {}:: Specify options: :formatted - Use indention and line breaks
def to_str(opts={})
doc = LibXML::XML::Document.new
doc.root = LibXML::XML::Node.new('plist')
doc.encoding = LibXML::XML::Encoding::UTF_8
doc.root['version'] = '1.0'
doc.root << opts[:root].to_xml(self)
# ugly hack, but there's no other possibility I know
str = doc.to_s(:indent => opts[:formatted])
str1 = String.new
first = false
str.each_line do |line|
str1 << line
unless(first) then
str1 << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" if line =~ /^\s*<\?xml/
end
first = true
end
str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
return str1
end
def new_node(name)
LibXML::XML::Node.new(name)
end
def new_text(val)
LibXML::XML::Node.new_text(val)
end
def append_node(parent, child)
parent << child
end
protected
# get the value of a DOM node
def get_value(n)
content = if n.children?
n.first.content
else
n.content
end
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.children? then
node.children.each do |n|
next if n.text? # avoid a bug of libxml
next if n.comment?
if n.name == "key" then
key = get_value(n)
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.children? then
node.children.each do |n|
next if n.text? # avoid a bug of libxml
next if n.comment?
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))
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
|