xmlhasher 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.idea
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ bundler_args: "--without development"
3
+ before_install:
4
+ - gem install bundler
5
+ rvm:
6
+ - 1.8.7
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - 2.0.0
10
+ - jruby-18mode
11
+ - jruby-19mode
12
+ - rbx
13
+ - rbx-19mode
14
+ - ree
15
+ - ruby-head
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'minitest'
7
+ gem 'test-unit'
8
+ gem 'simplecov', :require => false
9
+ gem 'coveralls', :require => false
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Gene Drabkin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # XmlHasher
2
+
3
+ [![Build Status](https://travis-ci.org/cloocher/xmlhasher.png)](https://travis-ci.org/cloocher/xmlhasher)
4
+
5
+ Xml to Ruby Hash converter
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'xmlhasher'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install xmlhasher
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'lib' << 'test'
6
+ t.pattern = 'test/*/*_test.rb'
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,20 @@
1
+ module XmlHasher
2
+ module Configurable
3
+
4
+ attr_writer :snakecase, :ignore_namespaces
5
+
6
+ KEYS = [:snakecase, :ignore_namespaces]
7
+
8
+ def configure
9
+ yield self
10
+ self
11
+ end
12
+
13
+ private
14
+
15
+ def options
16
+ XmlHasher::Configurable::KEYS.inject({}) { |hash, key| hash[key] = instance_variable_get(:"@#{key}"); hash }
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ require 'ox'
2
+
3
+ module XmlHasher
4
+ class Handler < ::Ox::Sax
5
+ def initialize(options = {})
6
+ @options = options
7
+ @stack = []
8
+ end
9
+
10
+ def to_hash
11
+ @hash || {}
12
+ end
13
+
14
+ def start_element(name)
15
+ @stack.push(Node.new(transform(name)))
16
+ end
17
+
18
+ def attr(name, value)
19
+ unless ignore_attribute?(name)
20
+ @stack.last.attributes[transform(name)] = value unless @stack.empty?
21
+ end
22
+ end
23
+
24
+ def text(value)
25
+ @stack.last.text = value
26
+ end
27
+
28
+ def end_element(name)
29
+ if @stack.size == 1
30
+ @hash = @stack.pop.to_hash
31
+ else
32
+ node = @stack.pop
33
+ @stack.last.children << node
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def transform(name)
40
+ name = name.to_s.split(':').last if @options[:ignore_namespaces]
41
+ name = Util.snakecase(name) if @options[:snakecase]
42
+ name
43
+ end
44
+
45
+ def ignore_attribute?(name)
46
+ @options[:ignore_namespaces] ? !name.to_s[/^(xmlns|xsi)/].nil? : false
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ module XmlHasher
2
+ class Node
3
+ attr_accessor :name, :attributes, :children, :text
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ @attributes = {}
8
+ @children = []
9
+ end
10
+
11
+ def to_hash
12
+ h = {}
13
+ if text
14
+ h[name] = text
15
+ else
16
+ if children.size == 1
17
+ child = children.first
18
+ h[name] = child.to_hash
19
+ else
20
+ if children.map(&:name).uniq.size == 1
21
+ h[name] = children.map { |child| child.to_hash }
22
+ else
23
+ h[name] = children.inject({}) { |r, child| r.merge!(child.to_hash); r }
24
+ end
25
+ end
26
+ end
27
+ attributes.each do |key, value|
28
+ h[key] = value if value
29
+ end
30
+ h
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,22 @@
1
+ require 'stringio'
2
+
3
+ module XmlHasher
4
+ class Parser
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+ end
9
+
10
+ def parse(xml)
11
+ handler = Handler.new(@options)
12
+ Ox.sax_parse(handler, convert(xml))
13
+ handler.to_hash
14
+ end
15
+
16
+ private
17
+
18
+ def convert(xml)
19
+ xml.respond_to?(:read) || xml.respond_to?(:readpartial) ? xml : StringIO.new(xml)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ module XmlHasher
2
+ module Util
3
+ def self.snakecase(str)
4
+ str.to_s.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase.tr('-', '_').to_sym
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module XmlHasher
2
+ VERSION = '0.0.1'
3
+ end
data/lib/xmlhasher.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'xmlhasher/configurable'
2
+ require 'xmlhasher/handler'
3
+ require 'xmlhasher/parser'
4
+ require 'xmlhasher/node'
5
+ require 'xmlhasher/util'
6
+ require 'xmlhasher/version'
7
+
8
+ module XmlHasher
9
+ class << self
10
+ include XmlHasher::Configurable
11
+
12
+ def parser
13
+ @parser ||= XmlHasher::Parser.new(options)
14
+ end
15
+
16
+ private
17
+
18
+ def method_missing(method_name, *args, &block)
19
+ return super unless parser.respond_to?(method_name)
20
+ parser.send(method_name, *args, &block)
21
+ end
22
+
23
+ end
24
+
25
+ end