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.
@@ -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: []