rsxml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Trampoline Systems Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,47 @@
1
+ = rsxml
2
+
3
+ A Ruby library to translate XML documents into an s-expression representation, and back again
4
+
5
+ Rsxml represents XML documents as s-expressions thus :
6
+
7
+ ["Foo", {"foofoo"=>"10"}, ["Bar", "barbar"], ["Baz"]]
8
+
9
+ represents the XML document :
10
+ <Foo foofoo="10"><Bar>barbar</Bar><Baz></Baz></Foo>
11
+
12
+ It is easy to convert XML docuemnts to Rsxml representation and back again :
13
+
14
+ xml = Rsxml.to_xml(["Foo", {"foofoo"=>"10"}, ["Bar", "barbar"]])
15
+ => '<Foo foofoo="10"><Bar>barbar</Bar></Foo>'
16
+
17
+ Rsxml.to_rsxml(xml)
18
+ => ["Foo", {"foofoo"=>"10"}, ["Bar", "barbar"]]
19
+
20
+ If present, namespaces and namespace prefixes are retained :
21
+
22
+ xml = Rsxml.to_xml(["foo:foofoo", {"xmlns"=>"http://bar.com/bar", "xmlns:foo"=>"http://foo.com/foo", "foo:bar"=>1, "foo:baz"=>"baz"}])
23
+ => '<foo:foofoo foo:baz="baz" foo:bar="1" xmlns="http://bar.com/bar" xmlns:foo="http://foo.com/foo"></foo:foofoo>'
24
+
25
+
26
+ Rsxml.to_rsxml(xml)
27
+ => ["foo:foofoo", {"foo:baz"=>"baz", "foo:bar"=>"1", "xmlns:foo"=>"http://foo.com/foo", "xmlns"=>"http://bar.com/bar"}]
28
+
29
+ == Install
30
+
31
+ gem install rsxml
32
+
33
+ == Contributing to rsxml
34
+
35
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
36
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
37
+ * Fork the project
38
+ * Start a feature/bugfix branch
39
+ * Commit and push until you are happy with your contribution
40
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
41
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
42
+
43
+ == Copyright
44
+
45
+ Copyright (c) 2011 Trampoline Systems Ltd. See LICENSE.txt for
46
+ further details.
47
+
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gem|
6
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
7
+ gem.name = "rsxml"
8
+ gem.homepage = "http://github.com/trampoline/rsxml"
9
+ gem.license = "MIT"
10
+ gem.summary = %Q{an s-expression representation of XML documents in Ruby}
11
+ gem.description = %Q{convert XML documents to an s-expression representation and back again in Ruby}
12
+ gem.email = "craig@trampolinesystems.com"
13
+ gem.authors = ["Trampoline Systems Ltd"]
14
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
15
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
16
+ gem.add_runtime_dependency "nokogiri", ">= 1.4.4"
17
+ gem.add_development_dependency "rspec", "~> 1.3.1"
18
+ gem.add_development_dependency "rr", ">= 0.10.5"
19
+ gem.add_development_dependency "jeweler", "~> 1.5.2"
20
+ gem.add_development_dependency "rcov", ">= 0"
21
+ end
22
+ Jeweler::RubygemsDotOrgTasks.new
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ require 'rake/rdoctask'
41
+ Rake::RDocTask.new do |rdoc|
42
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "rsxml #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/rsxml.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'nokogiri'
2
+ require 'builder'
3
+
4
+ module Rsxml
5
+ module_function
6
+
7
+ # convert an s-expression representation of an XML document to XML
8
+ # Rsxml.to_xml(["Foo", {"foofoo"=>"10"}, ["Bar", "barbar"] ["Baz"]])
9
+ # => '<Foo foofoo="10"><Bar>barbar</Bar><Baz></Baz></Foo>'
10
+ def to_xml(rsxml)
11
+ xml = Builder::XmlMarkup.new
12
+ Sexp.write_xml(xml, rsxml)
13
+ xml.target!
14
+ end
15
+
16
+ # convert an XML string to an s-expression representation
17
+ # Rsxml.to_rsxml('<Foo foofoo="10"><Bar>barbar</Bar><Baz></Baz></Foo>')
18
+ # => ["Foo", {"foofoo"=>"10"}, ["Bar", "barbar"], ["Baz"]]
19
+ def to_rsxml(doc)
20
+ root = Nokogiri::XML(doc).children.first
21
+ Xml.read_xml(root, [])
22
+ end
23
+
24
+ module Sexp
25
+ module_function
26
+
27
+ def write_xml(xml, sexp)
28
+ tag, attrs, children = decompose_sexp(sexp)
29
+
30
+ xml.__send__(tag, attrs) do
31
+ children.each do |child|
32
+ if child.is_a?(Array)
33
+ write_xml(xml, child)
34
+ else
35
+ xml << child
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def decompose_sexp(sexp)
42
+ raise "invalid rsxml: #{rsxml.inspect}" if sexp.length<1
43
+ tag = sexp[0].to_s
44
+ if sexp[1].is_a?(Hash)
45
+ attrs = sexp[1]
46
+ children = sexp[2..-1]
47
+ else
48
+ attrs = {}
49
+ children = sexp[1..-1]
50
+ end
51
+ [tag, attrs, children]
52
+ end
53
+ end
54
+
55
+ module Xml
56
+ module_function
57
+
58
+ def read_xml(node, ns_stack)
59
+ prefix = node.namespace.prefix if node.namespace
60
+ tag = node.name
61
+ ns_tag = [prefix,tag].compact.join(":")
62
+
63
+ attrs = read_attributes(node.attributes)
64
+ attrs = attrs.merge(namespace_attributes(node.namespaces, ns_stack))
65
+ attrs = nil if attrs.empty?
66
+
67
+ children = node.children.map do |child|
68
+ if child.text?
69
+ child.text
70
+ else
71
+ begin
72
+ ns_stack.push(node.namespaces)
73
+ read_xml(child, ns_stack)
74
+ ensure
75
+ ns_stack.pop
76
+ end
77
+ end
78
+ end
79
+
80
+ [ns_tag, attrs, *children].compact
81
+ end
82
+
83
+ def read_attributes(attrs)
84
+ Hash[*attrs.map do |n, attr|
85
+ prefix = attr.namespace.prefix if attr.namespace
86
+ name = attr.name
87
+ ns_name = [prefix,name].compact.join(":")
88
+ [ns_name, attr.value]
89
+ end.flatten]
90
+ end
91
+
92
+ def namespace_attributes(namespaces, ns_stack)
93
+ Hash[*namespaces.map do |prefix,href|
94
+ [prefix, href] if !find_namespace(prefix, ns_stack)
95
+ end.compact.flatten]
96
+ end
97
+
98
+ def find_namespace(prefix, ns_stack)
99
+ ns_stack.reverse.find{ |nsh| nsh.has_key?(prefix)}
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,103 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Rsxml do
4
+ describe "to_xml" do
5
+ it "should produce a single-element document" do
6
+ Rsxml.to_xml([:foo]).should == "<foo></foo>"
7
+ end
8
+
9
+ it "should produce a single-element doc with attrs" do
10
+ xml = Rsxml.to_xml([:foo, {:bar=>1, :baz=>"baz"}])
11
+ r = Nokogiri::XML(xml).children.first
12
+ r.name.should == "foo"
13
+ r["bar"].should == "1"
14
+ r["baz"].should == "baz"
15
+ end
16
+
17
+ it "should produce a doc with text content" do
18
+ xml = Rsxml.to_xml([:foo, "foofoo"])
19
+ r = Nokogiri::XML(xml).children.first
20
+ r.name.should == "foo"
21
+ r.children.size.should == 1
22
+ txt = r.children.first
23
+ txt.text?.should == true
24
+ txt.text.should == "foofoo"
25
+ end
26
+
27
+ it "should produce a doc with child elements" do
28
+ xml = Rsxml.to_xml([:foo, [:bar], [:baz]])
29
+ r = Nokogiri::XML(xml).children.first
30
+ r.name.should == "foo"
31
+ r.children.length.should == 2
32
+ bar = r.children.first
33
+ bar.name.should == "bar"
34
+ bar.children.length.should == 0
35
+ baz = r.children[1]
36
+ baz.name.should == "baz"
37
+ baz.children.length.should == 0
38
+ end
39
+
40
+ it "should produce a doc with child elements and attributes" do
41
+ xml = Rsxml.to_xml([:foo, [:bar, {:barbar=>"boo", :bazbaz=>"baz"}]])
42
+ r = Nokogiri::XML(xml).children.first
43
+ r.name.should == "foo"
44
+ r.children.length.should == 1
45
+ bar = r.children.first
46
+ bar.name.should == "bar"
47
+ bar.children.length.should == 0
48
+ bar["barbar"].should == "boo"
49
+ bar["bazbaz"].should == "baz"
50
+ end
51
+
52
+ it "should treat namespace prefixes reasonably" do
53
+ xml = Rsxml.to_xml(["foo:foofoo", {"xmlns:foo"=>"http://foo.com/foo", "foo:bar"=>1, "foo:baz"=>"baz"}])
54
+
55
+ r = Nokogiri::XML(xml).children.first
56
+ r.namespaces["xmlns:foo"].should == "http://foo.com/foo"
57
+
58
+ r.name.should == "foofoo"
59
+ r.namespace.href.should == "http://foo.com/foo"
60
+ r.namespace.prefix.should == "foo"
61
+
62
+ r["bar"].should == "1"
63
+ r.attributes["bar"].namespace.href.should == "http://foo.com/foo"
64
+ r.attributes["bar"].namespace.prefix.should == "foo"
65
+
66
+ r["baz"].should == "baz"
67
+ r.attributes["baz"].namespace.href.should == "http://foo.com/foo"
68
+ r.attributes["baz"].namespace.prefix.should == "foo"
69
+ end
70
+ end
71
+
72
+ describe "to_rsxml" do
73
+ def test_roundtrip(org)
74
+ xml = Rsxml.to_xml(org)
75
+ rsxml = Rsxml.to_rsxml(xml)
76
+ rsxml.should == org
77
+ end
78
+
79
+ it "should parse a single-element doc" do
80
+ test_roundtrip(["foo"])
81
+ end
82
+
83
+ it "should parse a single-element doc with attributes" do
84
+ test_roundtrip(["foo", {"bar"=>"1", "baz"=>"bazbaz"}])
85
+ end
86
+
87
+ it "should parse a doc with child elements" do
88
+ test_roundtrip(["foo", ["bar"], ["baz", ["boo"]]])
89
+ end
90
+
91
+ it "should parse a doc with text content" do
92
+ test_roundtrip(["foo", "foofoo"])
93
+ end
94
+
95
+ it "should parse a doc with child elements and attributes" do
96
+ test_roundtrip(["foo", {"bar"=>"1", "baz"=>"bazbaz"}, ["foofoo", {"foobar"=>"3", "barbaz"=>"4"}, "foofoofoo"]])
97
+ end
98
+
99
+ it "should parse a doc with namespaces" do
100
+ test_roundtrip(["foo:foofoo", {"xmlns:foo"=>"http://foo.com/foo", "foo:bar"=>"1", "foo:baz"=>"baz"}])
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'rr'
7
+ require 'nokogiri'
8
+ require 'rsxml'
9
+
10
+ Spec::Runner.configure do |config|
11
+ config.mock_with RR::Adapters::Rspec
12
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsxml
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Trampoline Systems Ltd
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-04 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: nokogiri
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 4
34
+ version: 1.4.4
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 25
46
+ segments:
47
+ - 1
48
+ - 3
49
+ - 1
50
+ version: 1.3.1
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rr
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 61
62
+ segments:
63
+ - 0
64
+ - 10
65
+ - 5
66
+ version: 0.10.5
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 7
78
+ segments:
79
+ - 1
80
+ - 5
81
+ - 2
82
+ version: 1.5.2
83
+ type: :development
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: rcov
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ type: :development
98
+ version_requirements: *id005
99
+ description: convert XML documents to an s-expression representation and back again in Ruby
100
+ email: craig@trampolinesystems.com
101
+ executables: []
102
+
103
+ extensions: []
104
+
105
+ extra_rdoc_files:
106
+ - LICENSE.txt
107
+ - README.rdoc
108
+ files:
109
+ - .document
110
+ - .rspec
111
+ - LICENSE.txt
112
+ - README.rdoc
113
+ - Rakefile
114
+ - VERSION
115
+ - lib/rsxml.rb
116
+ - spec/rsxml_spec.rb
117
+ - spec/spec_helper.rb
118
+ has_rdoc: true
119
+ homepage: http://github.com/trampoline/rsxml
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 3
142
+ segments:
143
+ - 0
144
+ version: "0"
145
+ requirements: []
146
+
147
+ rubyforge_project:
148
+ rubygems_version: 1.6.2
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: an s-expression representation of XML documents in Ruby
152
+ test_files:
153
+ - spec/rsxml_spec.rb
154
+ - spec/spec_helper.rb