rtiss_libxml_to_hash 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rtiss_libxml_to_hash.rb +156 -0
- data/test/rtiss_libxml_to_hash_test.rb +86 -0
- metadata +67 -0
@@ -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: []
|