Class: Kronk::XMLParser

Inherits:
Object
  • Object
show all
Defined in:
lib/kronk/xml_parser.rb

Overview

Rails-like XML parser.

Class Method Summary collapse

Class Method Details

.array?(node_set, parent_name = nil) ⇒ Boolean

Checks if a given node set should be interpreted as an Array.

Returns:

  • (Boolean)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/kronk/xml_parser.rb', line 129

def self.array? node_set, parent_name=nil
  names = node_set.map do |n|
    return unless Nokogiri::XML::Element === n
    n.name
  end

  return false unless names.uniq.length == 1
  return true  if     names.length > 1
  return false unless parent_name

  names.first == parent_name             ||
  names.first.respond_to?(:pluralize) &&
    names.first.pluralize == parent_name ||
  pluralize(names.first) == parent_name
end

.element_node_value(xml_node) ⇒ Object

Returns an Array containing the value of an element node and its name.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/kronk/xml_parser.rb', line 105

def self.element_node_value xml_node
  name     = xml_node.name
  datatype = xml_node.attr :type
  is_array = array? xml_node.children, name
  data     = node_value xml_node.children, is_array

  data = case datatype
         when 'array'   then data.to_a
         when 'symbol'  then data.to_sym
         when 'integer' then data.to_i
         when 'float'   then data.to_f
         when 'boolean'
           data == 'true' ? true : false
         else
           data
         end

  [data, name]
end

.node_set_value(xml_node, as_array = false) ⇒ Object

Returns the value for an xml node set. Can be a Hash, Array, or String



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
# File 'lib/kronk/xml_parser.rb', line 74

def self.node_set_value xml_node, as_array=false
  orig = {}
  data = as_array ? Array.new : Hash.new

  xml_node.each do |node|
    node_data, name = node_value node
    return node_data unless name

    case data
    when Array
      data << node_data
    when Hash
      orig[name] ||= node_data

      if data.has_key?(name)
        data[name] = [data[name]] if data[name] == orig[name]
        data[name] << node_data
      else
        data[name] = node_data
      end
    end
  end

  data
end

.node_value(xml_node, as_array = false) ⇒ Object

Build a hash from a nokogiri xml node.



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/kronk/xml_parser.rb', line 57

def self.node_value xml_node, as_array=false
  case xml_node
  when Nokogiri::XML::Text    then xml_node.text

  # Returns hash or array
  when Nokogiri::XML::NodeSet then node_set_value(xml_node, as_array)

  # Returns node name and value
  when Nokogiri::XML::Element then element_node_value(xml_node)
  end
end

.parse(str) ⇒ Object

Takes an xml string and returns a data hash. Ignores blank spaces between tags.



42
43
44
45
46
47
48
49
50
51
# File 'lib/kronk/xml_parser.rb', line 42

def self.parse str
  require_gems

  root_node = Nokogiri.XML str do |config|
    config.default_xml.noblanks
  end

  hash = node_value root_node.children
  hash.values.first || raise(ParserError, "invalid XML")
end

.pluralize(str) ⇒ Object

Naïve pluralization used if String#pluralize isn’t defined.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/kronk/xml_parser.rb', line 149

def self.pluralize str
  case str
  when /z$/             then "#{str}zes"
  when /f$/             then "#{str}ves"
  when /y$/             then "#{str}ies"
  when /is$/            then str.sub(/is$/, "es")
  when "child"          then "children"
  when "person"         then "people"
  when "foot"           then "feet"
  when "photo"          then "photos"
  when /([sxo]|[cs]h)$/ then "#{str}es"
  else
    "#{str}s"
  end
end

.require_gemsObject

Load required gems. Loads Nokogiri. ActiveSupport will attempt to be loaded if String#pluralize is not defined.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/kronk/xml_parser.rb', line 12

def self.require_gems
  begin
    require 'nokogiri'
  rescue LoadError => e
    raise unless e.message =~ /-- nokogiri/
    raise MissingDependency, "Please install the nokogiri gem and try again"
  end


  return if "".respond_to?(:pluralize)

  # Support for new and old versions of ActiveSupport
  active_support_versions = %w{active_support/inflector activesupport}
  asupp_i = 0

  begin
    require active_support_versions[asupp_i]

  rescue LoadError => e
    raise unless e.message =~ /-- active_?support/
    asupp_i = asupp_i.next
    retry if asupp_i < active_support_versions.length
  end
end