rtiss_libxml_to_hash 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ # USAGE: Hash.from_libxml(YOUR_XML_STRING)
4
+ require 'xml/libxml'
5
+ # adapted from
6
+ # http://movesonrails.com/articles/2008/02/25/libxml-for-active-resource-2-0
7
+
8
+ # This class is required to represent Nodes that contain
9
+ # attributes as well as other content, for example:
10
+ # <karin zak="lebt">schon</karin>
11
+ # We cannot non-ambigiously represent this node as a hash
12
+ # because Hashes may contain arbitrary keys.
13
+ # Having a separate class for representing such nodes
14
+ # allows for easy testing for the class (which we have
15
+ # to do anyway since hash values may be Strings, Arrays
16
+ # or other Hashes already)
17
+ # Update: No need for testing when using the iterable method.
18
+ # Usage: LibXmlNode.new("karin", "zak")
19
+
20
+ class LibXmlNode < Object
21
+ VERSION = '0.3.0'
22
+
23
+ attr_accessor :subnodes
24
+ attr_accessor :attributes
25
+ attr_accessor :text
26
+
27
+ def initialize
28
+ @subnodes = {}
29
+ @attributes = {}
30
+ @text = ""
31
+ end
32
+
33
+ def self.create(n, a, t)
34
+ l = LibXmlNode.new
35
+ l.subnodes = n
36
+ l.attributes = a
37
+ l.text = t
38
+ l
39
+ end
40
+
41
+ def add_attribute(key, value)
42
+ @attributes[key] = value
43
+ end
44
+
45
+ def add_node(key, value)
46
+ if @subnodes[key]
47
+ if @subnodes[key].is_a? Object::Array
48
+ @subnodes[key] << value
49
+ else
50
+ @subnodes[key] = [@subnodes[key], value]
51
+ end
52
+ else
53
+ @subnodes[key] = value
54
+ end
55
+ end
56
+
57
+ def add_text(t)
58
+ @text << t
59
+ end
60
+
61
+ def simplify
62
+ if @attributes.empty?
63
+ if @text == ""
64
+ return @subnodes
65
+ end
66
+ if @subnodes == {}
67
+ return @text
68
+ end
69
+ end
70
+ return self
71
+ end
72
+
73
+ def ==(other)
74
+ if other.class == LibXmlNode
75
+ if @subnodes == other.subnodes and @attributes == other.attributes and @text == other.text
76
+ return true
77
+ end
78
+ end
79
+ false
80
+ end
81
+
82
+ def iterable
83
+ [self]
84
+ end
85
+ end
86
+
87
+ class Hash
88
+ def iterable
89
+ [self]
90
+ end
91
+
92
+ def to_libxmlnode
93
+ LibXmlNode.create(self, {}, "")
94
+ end
95
+
96
+ class << self
97
+ def from_libxml!(xml, strict=true)
98
+ XML.default_load_external_dtd = false
99
+ XML.default_pedantic_parser = strict
100
+ result = XML::Parser.string(xml).parse
101
+ return { result.root.name.to_s => xml_node_to_hash(result.root)}
102
+ end
103
+
104
+ def from_libxml(xml, strict=true)
105
+ begin
106
+ from_libxml!(xml, strict)
107
+ rescue Exception => e
108
+ nil
109
+ end
110
+ end
111
+
112
+ def xml_node_to_hash(node)
113
+ n = LibXmlNode.new
114
+ if node.element?
115
+ node.attributes.each do |attribute|
116
+ n.add_attribute attribute.name.to_s, attribute.value
117
+ end
118
+
119
+ node.each_child do |child|
120
+ if child.text?
121
+ if not child.children?
122
+ n.add_text child.content.to_s.strip
123
+ end
124
+ else
125
+ n.add_node child.name.to_s, xml_node_to_hash(child)
126
+ end
127
+ end
128
+ end
129
+ return n.simplify
130
+ end
131
+ end
132
+ end
133
+
134
+ class String
135
+ def iterable
136
+ [self]
137
+ end
138
+
139
+ def to_b
140
+ self.upcase == 'TRUE' or self == '1'
141
+ end
142
+
143
+ def to_libxmlnode
144
+ LibXmlNode.create({}, {}, self)
145
+ end
146
+ end
147
+
148
+ class Array
149
+ def iterable
150
+ self
151
+ end
152
+
153
+ def to_libxmlnode
154
+ LibXmlNode.create(self, {}, "")
155
+ end
156
+ end
@@ -0,0 +1,86 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "test/unit"
3
+ require "./lib/rtiss_libxml_to_hash.rb"
4
+
5
+ class LibXmlToHashTest < Test::Unit::TestCase
6
+ def test_tiss_xml_node_class
7
+ assert_equal "karin", LibXmlNode.create("karin", "zak", "lebt").subnodes
8
+ assert_equal "zak", LibXmlNode.create("karin", "zak", "lebt").attributes
9
+ assert_equal "lebt", LibXmlNode.create("karin", "zak", "lebt").text
10
+ end
11
+
12
+ def test_from_libxml
13
+ assert_equal({"karin" => {}}, Hash.from_libxml("<karin/>"))
14
+ assert_equal({"karin" => {}}, Hash.from_libxml("<karin></karin>"))
15
+ assert_equal({"karin" => "zak"}, Hash.from_libxml("<karin>zak</karin>"))
16
+ assert_equal({"karin" => LibXmlNode.create({}, {"zak" => "lebt"}, "")}, Hash.from_libxml("<karin zak=\"lebt\"></karin>"))
17
+ assert_equal({"karin" => {"zak" => "lebt"}}, Hash.from_libxml("<karin><zak>lebt</zak></karin>"))
18
+ assert_equal({"karin" => LibXmlNode.create({"zak" => "nicht"}, {"zak" => "lebt"}, "")}, Hash.from_libxml("<karin zak=\"lebt\"><zak>nicht</zak></karin>"))
19
+ assert_equal({"karin" => {"zak" => ["nicht", "schon"] }}, Hash.from_libxml("<karin><zak>nicht</zak><zak>schon</zak></karin>"))
20
+ assert_equal({"karin" => {"zak" => ["nicht", "schon", "oder"] }}, Hash.from_libxml("<karin><zak>nicht</zak><zak>schon</zak><zak>oder</zak></karin>"))
21
+ assert_equal({"karin" => {"zak" => "nicht", "lebt" => "schon"}}, Hash.from_libxml("<karin><zak>nicht</zak><lebt>schon</lebt></karin>"))
22
+ assert_equal({"karin" => {"zak" => "nicht", "lebt" => "schon", "oder" => {"was" => "nicht" }}}, Hash.from_libxml("<karin><zak>nicht</zak><lebt>schon</lebt><oder><was>nicht</was></oder></karin>"))
23
+ assert_equal({"karin" => LibXmlNode.create({}, {"zak" => "lebt"}, "schon")}, Hash.from_libxml("<karin zak=\"lebt\">schon</karin>"))
24
+ assert_equal({"karin" => LibXmlNode.create({"zak"=>{}}, {}, "textmoretext")}, Hash.from_libxml("<karin>text<zak/>moretext</karin>"))
25
+ end
26
+
27
+ def test_exceptions
28
+ assert_nothing_raised { Hash.from_libxml("<karin") }
29
+ assert_nil Hash.from_libxml("<karin")
30
+ assert_raise LibXML::XML::Error do Hash.from_libxml!("<karin") end
31
+ end
32
+
33
+ def test_iterable
34
+ for s in "karin".iterable do
35
+ assert_equal "karin", s
36
+ end
37
+ for h in {"karin" => "zak"}.iterable do
38
+ assert_equal({"karin" => "zak"}, h)
39
+ end
40
+ for n in LibXmlNode.create({}, {"zak" => "lebt"}, "").iterable do
41
+ assert_equal LibXmlNode.create({}, {"zak" => "lebt"}, ""), n
42
+ end
43
+ for a in ["karin"].iterable do
44
+ assert_equal "karin", a
45
+ end
46
+ end
47
+
48
+ def test_to_b
49
+ assert not("false".to_b)
50
+ assert not("0".to_b)
51
+ assert "true".to_b
52
+ assert "1".to_b
53
+ assert not("karin".to_b)
54
+ end
55
+
56
+ def test_alex_xml
57
+ assert_equal(
58
+ {"tuvienna"=>
59
+ {"response"=>
60
+ [LibXmlNode.create({"confirmed"=>"false", "error"=>"invalid_persnr"}, {"employeeId"=>"1293191270"}, ""),
61
+ LibXmlNode.create({"confirmed"=>"true"}, {"employeeId"=>"VADE111111"}, ""),
62
+ LibXmlNode.create({"confirmed"=>"false",
63
+ "error"=>["invalid_hours", "unknown_person", "deleted"]}, {"employeeId"=>"SKYW111111"}, "")]}},
64
+ Hash.from_libxml('<?xml version="1.0" encoding="UTF-8"?>
65
+ <tuvienna xmlns="https://tiss.tuwien.ac.at/api/schemas/lecturerResponse/v10" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
66
+ <response employeeId="1293191270">
67
+ <confirmed>false</confirmed>
68
+ <error>invalid_persnr</error>
69
+ </response>
70
+ <response employeeId="VADE111111">
71
+ <confirmed>true</confirmed>
72
+ </response>
73
+ <response employeeId="SKYW111111">
74
+ <confirmed>false</confirmed>
75
+ <error>invalid_hours</error>
76
+ <error>unknown_person</error>
77
+ <error>deleted</error>
78
+ </response>
79
+ </tuvienna>'))
80
+ end
81
+
82
+ def test_to_libxmlnode
83
+ assert_equal "text".to_libxmlnode, LibXmlNode.create({}, {}, "text")
84
+ assert_equal({"karin" => "zak"}.to_libxmlnode, LibXmlNode.create({"karin" => "zak"}, {}, ""))
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rtiss_libxml_to_hash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Johannes Thoma
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: libxml-ruby
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: ! 'A simple library to convert XML strings to hashes using libxml
31
+
32
+
33
+ This adds to from_lib_xml method to the Hash class which uses libxml (which
34
+
35
+ is much faster than ReXML) to convert a XML string into a Hash'
36
+ email: johannes.thoma@gmx.at
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - lib/rtiss_libxml_to_hash.rb
42
+ - test/rtiss_libxml_to_hash_test.rb
43
+ homepage: https://github.com/rtiss/libxml-to-hash
44
+ licenses: []
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project: rtiss_libxml_to_hash
63
+ rubygems_version: 1.8.25
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: A simple library to convert XML strings to hashes using libxml
67
+ test_files: []