xml_schema_mapper 0.0.1 → 0.0.5
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/.gitignore +1 -0
- data/lib/thor/templates/converter_class.erb +17 -10
- data/lib/thor/templates/converter_spec.erb +8 -7
- data/lib/thor/templates/mapper_class.erb +28 -9
- data/lib/thor/templates/mapper_spec.erb +15 -9
- data/lib/thor/xsd_mappers.rb +66 -21
- data/lib/xml_schema_mapper.rb +99 -23
- data/lib/xml_schema_mapper/builder.rb +69 -27
- data/lib/xml_schema_mapper/element.rb +39 -34
- data/lib/xml_schema_mapper/namespace_resolver.rb +33 -0
- data/lib/xml_schema_mapper/parser.rb +68 -8
- data/lib/xml_schema_mapper/test_builder.rb +84 -0
- data/lib/xml_schema_mapper/version.rb +1 -1
- data/spec/build_xml_spec.rb +3 -3
- data/spec/builder_spec.rb +23 -8
- data/spec/fixtures/UserService.xsd +23 -2
- data/spec/fixtures/common.xsd +1 -1
- data/spec/fixtures/get_first_name.xml +8 -8
- data/spec/fixtures/instance1.xml +8 -8
- data/spec/fixtures/instance_with_arrays.xml +29 -0
- data/spec/fixtures/user_service.rb +113 -4
- data/spec/parse_xml_spec.rb +51 -9
- data/spec/visitor_spec.rb +167 -0
- data/spec/xml_schema_mapper_spec.rb +2 -2
- metadata +40 -42
- data/.idea/.rakeTasks +0 -7
- data/.idea/encodings.xml +0 -5
- data/.idea/misc.xml +0 -8
- data/.idea/modules.xml +0 -9
- data/.idea/scopes/scope_settings.xml +0 -5
- data/.idea/vcs.xml +0 -7
- data/.idea/workspace.xml +0 -459
- data/.idea/xml_schema_mapper.iml +0 -29
data/spec/fixtures/common.xsd
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
2
|
<xs:schema xmlns:cm="http://example.com/common/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
3
|
-
targetNamespace="http://example.com/common/" version="1.0">
|
3
|
+
targetNamespace="http://example.com/common/" elementFormDefault="qualified" version="1.0">
|
4
4
|
|
5
5
|
<xs:simpleType name="ZONE">
|
6
6
|
<xs:restriction base="xs:string">
|
@@ -1,13 +1,13 @@
|
|
1
|
-
<getFirstName xmlns:tns="http://example.com/UserService/type/" xmlns:cm="http://example.com/common/">
|
2
|
-
<userIdentifier>001</userIdentifier>
|
1
|
+
<tns:getFirstName xmlns:tns="http://example.com/UserService/type/" xmlns:cm="http://example.com/common/">
|
2
|
+
<tns:userIdentifier>001</tns:userIdentifier>
|
3
3
|
<tns:filter>
|
4
4
|
<tns:age>50</tns:age>
|
5
5
|
<tns:gender>male</tns:gender>
|
6
6
|
</tns:filter>
|
7
|
-
<isOut>a</isOut>
|
7
|
+
<tns:isOut>a</tns:isOut>
|
8
8
|
<cm:zone>b</cm:zone>
|
9
|
-
<options>
|
10
|
-
<one>one</one>
|
11
|
-
<two>two</two>
|
12
|
-
</options>
|
13
|
-
</getFirstName>
|
9
|
+
<tns:options>
|
10
|
+
<cm:one>one</cm:one>
|
11
|
+
<cm:two>two</cm:two>
|
12
|
+
</tns:options>
|
13
|
+
</tns:getFirstName>
|
data/spec/fixtures/instance1.xml
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<getFirstName xmlns:cm="http://example.com/common/" xmlns:tns="http://example.com/UserService/type/">
|
3
|
-
<userIdentifier>xoMPRY</userIdentifier>
|
2
|
+
<tns:getFirstName xmlns:cm="http://example.com/common/" xmlns:tns="http://example.com/UserService/type/">
|
3
|
+
<tns:userIdentifier>xoMPRY</tns:userIdentifier>
|
4
4
|
<tns:filter>
|
5
5
|
<tns:age>94</tns:age>
|
6
6
|
<tns:gender>male</tns:gender>
|
7
7
|
</tns:filter>
|
8
|
-
<isOut>a</isOut>
|
8
|
+
<tns:isOut>a</tns:isOut>
|
9
9
|
<cm:zone>b</cm:zone>
|
10
|
-
<options>
|
11
|
-
<one>p6E58</one>
|
12
|
-
<two>Vm1sk87pkU0pE4EKKSY</two>
|
13
|
-
</options>
|
14
|
-
</getFirstName>
|
10
|
+
<tns:options>
|
11
|
+
<cm:one>p6E58</cm:one>
|
12
|
+
<cm:two>Vm1sk87pkU0pE4EKKSY</cm:two>
|
13
|
+
</tns:options>
|
14
|
+
</tns:getFirstName>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<tns:getFirstNames xmlns:cm="http://example.com/common/" xmlns:tns="http://example.com/UserService/type/">
|
3
|
+
<tns:query>
|
4
|
+
<tns:userIdentifier>xoMPRY</tns:userIdentifier>
|
5
|
+
<tns:filter>
|
6
|
+
<tns:age>94</tns:age>
|
7
|
+
<tns:gender>male</tns:gender>
|
8
|
+
</tns:filter>
|
9
|
+
<tns:isOut>a</tns:isOut>
|
10
|
+
<cm:zone>b</cm:zone>
|
11
|
+
<tns:options>
|
12
|
+
<cm:one>p6E58</cm:one>
|
13
|
+
<cm:two>Vm1sk87pkU0pE4EKKSY</cm:two>
|
14
|
+
</tns:options>
|
15
|
+
</tns:query>
|
16
|
+
<tns:query>
|
17
|
+
<tns:userIdentifier>xoMPRY</tns:userIdentifier>
|
18
|
+
<tns:filter>
|
19
|
+
<tns:age>94</tns:age>
|
20
|
+
<tns:gender>male</tns:gender>
|
21
|
+
</tns:filter>
|
22
|
+
<tns:isOut>a</tns:isOut>
|
23
|
+
<cm:zone>b</cm:zone>
|
24
|
+
<tns:options>
|
25
|
+
<cm:one>p6E58</cm:one>
|
26
|
+
<cm:two>Vm1sk87pkU0pE4EKKSY</cm:two>
|
27
|
+
</tns:options>
|
28
|
+
</tns:query>
|
29
|
+
</tns:getFirstNames>
|
@@ -1,23 +1,132 @@
|
|
1
|
-
class
|
1
|
+
class ZONEMapper
|
2
2
|
include XmlSchemaMapper
|
3
3
|
schema 'spec/fixtures/UserService.xsd'
|
4
4
|
type 'ZONE'
|
5
|
+
elements.each do |e|
|
6
|
+
attr_accessor e.reader
|
7
|
+
end
|
5
8
|
end
|
6
9
|
|
7
|
-
class
|
10
|
+
class FilterMapper
|
8
11
|
include XmlSchemaMapper
|
9
12
|
schema 'spec/fixtures/UserService.xsd'
|
10
13
|
type 'Filter'
|
14
|
+
elements.each do |e|
|
15
|
+
attr_accessor e.reader
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
|
-
class
|
19
|
+
class OptionsMapper
|
14
20
|
include XmlSchemaMapper
|
15
21
|
schema 'spec/fixtures/UserService.xsd'
|
16
22
|
type 'Options'
|
23
|
+
elements.each do |e|
|
24
|
+
attr_accessor e.reader
|
25
|
+
end
|
17
26
|
end
|
18
27
|
|
19
|
-
class
|
28
|
+
class GetFirstNameMapper
|
20
29
|
include XmlSchemaMapper
|
21
30
|
schema 'spec/fixtures/UserService.xsd'
|
22
31
|
type 'GetFirstName'
|
32
|
+
elements.each do |e|
|
33
|
+
attr_accessor e.reader
|
34
|
+
end
|
23
35
|
end
|
36
|
+
|
37
|
+
|
38
|
+
module AnotherNamespace
|
39
|
+
class ZONEMapper
|
40
|
+
include XmlSchemaMapper
|
41
|
+
schema 'spec/fixtures/UserService.xsd'
|
42
|
+
type 'ZONE'
|
43
|
+
elements.each do |e|
|
44
|
+
attr_accessor e.reader
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class FilterMapper
|
49
|
+
include XmlSchemaMapper
|
50
|
+
schema 'spec/fixtures/UserService.xsd'
|
51
|
+
type 'Filter'
|
52
|
+
elements.each do |e|
|
53
|
+
attr_accessor e.reader
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class OptionsMapper
|
58
|
+
include XmlSchemaMapper
|
59
|
+
schema 'spec/fixtures/UserService.xsd'
|
60
|
+
type 'Options'
|
61
|
+
elements.each do |e|
|
62
|
+
attr_accessor e.reader
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class GetFirstNameMapper
|
67
|
+
include XmlSchemaMapper
|
68
|
+
schema 'spec/fixtures/UserService.xsd'
|
69
|
+
type 'GetFirstName'
|
70
|
+
elements.each do |e|
|
71
|
+
attr_accessor e.reader
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
module ArrayNamespace
|
79
|
+
class ZONEMapper
|
80
|
+
include XmlSchemaMapper
|
81
|
+
schema 'spec/fixtures/UserService.xsd'
|
82
|
+
type 'ZONE'
|
83
|
+
elements.each do |e|
|
84
|
+
attr_accessor e.reader
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class FilterMapper
|
89
|
+
include XmlSchemaMapper
|
90
|
+
schema 'spec/fixtures/UserService.xsd'
|
91
|
+
type 'Filter'
|
92
|
+
elements.each do |e|
|
93
|
+
attr_accessor e.reader
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class OptionsMapper
|
98
|
+
include XmlSchemaMapper
|
99
|
+
schema 'spec/fixtures/UserService.xsd'
|
100
|
+
type 'Options'
|
101
|
+
elements.each do |e|
|
102
|
+
attr_accessor e.reader
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class GetFirstNameMapper
|
107
|
+
include XmlSchemaMapper
|
108
|
+
schema 'spec/fixtures/UserService.xsd'
|
109
|
+
type 'GetFirstName'
|
110
|
+
elements.each do |e|
|
111
|
+
attr_accessor e.reader
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class ArrayOfGetFirstNameMapper
|
116
|
+
include XmlSchemaMapper
|
117
|
+
schema 'spec/fixtures/UserService.xsd'
|
118
|
+
type 'ArrayOfGetFirstName'
|
119
|
+
elements.each do |e|
|
120
|
+
attr_accessor e.reader
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class ArrayOfStringsMapper
|
125
|
+
include XmlSchemaMapper
|
126
|
+
schema 'spec/fixtures/UserService.xsd'
|
127
|
+
type 'ArrayOfStrings'
|
128
|
+
elements.each do |e|
|
129
|
+
attr_accessor e.reader
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/parse_xml_spec.rb
CHANGED
@@ -2,35 +2,77 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Parse XML" do
|
4
4
|
|
5
|
-
context "by
|
5
|
+
context "by GetFirstNameMapper" do
|
6
6
|
let(:xml) { File.read('spec/fixtures/instance1.xml') }
|
7
7
|
|
8
8
|
it "should parse with XmlSchemaMapper::Parser" do
|
9
9
|
XmlSchemaMapper::Parser.any_instance.should_receive(:parse).with(xml)
|
10
|
-
|
10
|
+
GetFirstNameMapper.parse(xml)
|
11
11
|
end
|
12
12
|
|
13
|
-
it "should return instance of
|
14
|
-
|
13
|
+
it "should return instance of GetFirstNameMapper" do
|
14
|
+
GetFirstNameMapper.parse(xml).should be_a GetFirstNameMapper
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should lookup all elements" do
|
18
|
-
|
19
|
-
|
18
|
+
GetFirstNameMapper.elements.should_receive(:each)
|
19
|
+
GetFirstNameMapper.parse(xml)
|
20
20
|
end
|
21
21
|
|
22
22
|
context "its" do
|
23
|
-
subject {
|
23
|
+
subject { GetFirstNameMapper.parse(xml) }
|
24
24
|
its(:user_identifier) { should be_eql 'xoMPRY' }
|
25
|
-
its(:filter) { should be_a
|
25
|
+
its(:filter) { should be_a FilterMapper }
|
26
26
|
its(:'filter.age') { should eql '94' }
|
27
27
|
its(:'filter.gender') { should eql 'male' }
|
28
28
|
its(:is_out) { should eql 'a' }
|
29
29
|
its(:zone) { should eql 'b' }
|
30
|
-
its(:options) { should be_a
|
30
|
+
its(:options) { should be_a OptionsMapper }
|
31
31
|
its(:'options.one') { should eql 'p6E58' }
|
32
32
|
its(:'options.two') { should eql 'Vm1sk87pkU0pE4EKKSY' }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
context "by AnotherNamespace::GetFirstNameMapper" do
|
37
|
+
let(:xml) { File.read('spec/fixtures/instance1.xml') }
|
38
|
+
|
39
|
+
it "should parse with XmlSchemaMapper::Parser" do
|
40
|
+
XmlSchemaMapper::Parser.any_instance.should_receive(:parse).with(xml)
|
41
|
+
AnotherNamespace::GetFirstNameMapper.parse(xml)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return instance of GetFirstNameMapper" do
|
45
|
+
AnotherNamespace::GetFirstNameMapper.parse(xml).should be_a AnotherNamespace::GetFirstNameMapper
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should lookup all elements" do
|
49
|
+
AnotherNamespace::GetFirstNameMapper.elements.should_receive(:each)
|
50
|
+
AnotherNamespace::GetFirstNameMapper.parse(xml)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "its" do
|
54
|
+
subject { AnotherNamespace::GetFirstNameMapper.parse(xml) }
|
55
|
+
its(:user_identifier) { should be_eql 'xoMPRY' }
|
56
|
+
its(:filter) { should be_a AnotherNamespace::FilterMapper }
|
57
|
+
its(:'filter.age') { should eql '94' }
|
58
|
+
its(:'filter.gender') { should eql 'male' }
|
59
|
+
its(:is_out) { should eql 'a' }
|
60
|
+
its(:zone) { should eql 'b' }
|
61
|
+
its(:options) { should be_a AnotherNamespace::OptionsMapper }
|
62
|
+
its(:'options.one') { should eql 'p6E58' }
|
63
|
+
its(:'options.two') { should eql 'Vm1sk87pkU0pE4EKKSY' }
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
context "parse arrays" do
|
68
|
+
let(:xml) { File.read('spec/fixtures/instance_with_arrays.xml') }
|
69
|
+
subject { ArrayNamespace::ArrayOfGetFirstNameMapper.parse(xml) }
|
70
|
+
|
71
|
+
it do
|
72
|
+
subject.query.should have(2).elements
|
73
|
+
ArrayNamespace::ArrayOfGetFirstNameMapper.parse(subject.to_xml).query.should have(2).elements
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
36
78
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
describe "Generate XML by Visitor Pattern" do
|
5
|
+
|
6
|
+
class MarshalVisitor
|
7
|
+
|
8
|
+
attr_reader :namespace_mapper
|
9
|
+
|
10
|
+
def initialize(data, namespace_mapper)
|
11
|
+
@data = data
|
12
|
+
@namespace_mapper = namespace_mapper
|
13
|
+
@tab = 0
|
14
|
+
@buf = ""
|
15
|
+
@io = StringIO.new @buf
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_array(element, data, *args)
|
19
|
+
data.each { |d| element.accept(self, d) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit(element, data, *args)
|
23
|
+
@io.print tag_open(element, data)
|
24
|
+
|
25
|
+
with_padding(element) do
|
26
|
+
element.elements.each do |e|
|
27
|
+
e.accept(self, data.elements[e.reader])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@io.print tag_close(element)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_xml
|
35
|
+
@data.class.elements.each do |e|
|
36
|
+
e.accept(self, @data.elements[e.reader])
|
37
|
+
end
|
38
|
+
@buf
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def tag_name(element)
|
44
|
+
prefix = namespace_mapper.prefix(element.namespace)
|
45
|
+
if prefix.present?
|
46
|
+
"#{prefix}:#{element.name}"
|
47
|
+
else
|
48
|
+
element.name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def tag_open(element, data)
|
53
|
+
if element.type.attributes.empty?
|
54
|
+
attrs = ""
|
55
|
+
else
|
56
|
+
attrs = " " << data.attrs.map { |name, val| %Q{#{name}="#{val}"} }.join(' ')
|
57
|
+
end
|
58
|
+
|
59
|
+
if element.simple?
|
60
|
+
padding << "<#{tag_name(element)}#{attrs}>" << "#{data}"
|
61
|
+
else
|
62
|
+
padding << "<#{tag_name(element)}#{attrs}>\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def tag_close(element)
|
67
|
+
if element.simple?
|
68
|
+
"</#{tag_name(element)}>\n"
|
69
|
+
else
|
70
|
+
padding << "</#{tag_name(element)}>\n"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def padding
|
75
|
+
(" " * @tab)
|
76
|
+
end
|
77
|
+
|
78
|
+
def with_padding(element)
|
79
|
+
inc_tab! if element.elements.present?
|
80
|
+
yield
|
81
|
+
dec_tab! if element.elements.present?
|
82
|
+
end
|
83
|
+
|
84
|
+
def inc_tab!
|
85
|
+
@tab = @tab + 1
|
86
|
+
end
|
87
|
+
|
88
|
+
def dec_tab!
|
89
|
+
@tab = @tab - 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class NamespacePrefixMapper
|
94
|
+
class_attribute :map
|
95
|
+
self.map = { }
|
96
|
+
|
97
|
+
map["ds"] = "http://www.w3.org/2000/09/xmldsig#"
|
98
|
+
map["xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
|
99
|
+
map["xml"] = "http://www.w3.org/XML/1998/namespace"
|
100
|
+
map["xs"] = "http://www.w3.org/2001/XMLSchema"
|
101
|
+
map["xop"] = "http://www.w3.org/2004/08/xop/include"
|
102
|
+
map["xmime"] = "http://www.w3.org/2005/05/xmlmime"
|
103
|
+
|
104
|
+
def self.add(hash = { })
|
105
|
+
map.merge! hash.stringify_keys
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.prefix(uri)
|
109
|
+
map.invert[uri] or ''
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.uri(prefix)
|
113
|
+
map[prefix]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
let(:options) { o = OptionsMapper.new; o.one = 'one'; o.two = 'two'; o }
|
118
|
+
let(:object) do
|
119
|
+
f = FilterMapper.new; f.age = 50; f.gender = 'male'
|
120
|
+
g = GetFirstNameMapper.new; g.user_identifier = '001'; g.is_out = 'a'; g.zone = 'b'; g.filter = f; g.options = options
|
121
|
+
g.attrs = { 'id' => '1000', 'default' => '1' }
|
122
|
+
g
|
123
|
+
end
|
124
|
+
|
125
|
+
it "" do
|
126
|
+
mapper = ArrayNamespace::ArrayOfGetFirstNameMapper.new
|
127
|
+
mapper.query = [object, object.dup]
|
128
|
+
|
129
|
+
class UserNamespaceMapper < NamespacePrefixMapper
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
UserNamespaceMapper.add type: "http://example.com/UserService/type/",
|
134
|
+
com: "http://example.com/common/"
|
135
|
+
|
136
|
+
visitor = MarshalVisitor.new(mapper, UserNamespaceMapper)
|
137
|
+
visitor.to_xml.should eql <<-X
|
138
|
+
<type:query id="1000" default="1">
|
139
|
+
<type:userIdentifier>001</type:userIdentifier>
|
140
|
+
<type:filter>
|
141
|
+
<type:age>50</type:age>
|
142
|
+
<type:gender>male</type:gender>
|
143
|
+
</type:filter>
|
144
|
+
<type:isOut>a</type:isOut>
|
145
|
+
<com:zone>b</com:zone>
|
146
|
+
<type:options>
|
147
|
+
<com:one>one</com:one>
|
148
|
+
<com:two>two</com:two>
|
149
|
+
</type:options>
|
150
|
+
</type:query>
|
151
|
+
<type:query id="1000" default="1">
|
152
|
+
<type:userIdentifier>001</type:userIdentifier>
|
153
|
+
<type:filter>
|
154
|
+
<type:age>50</type:age>
|
155
|
+
<type:gender>male</type:gender>
|
156
|
+
</type:filter>
|
157
|
+
<type:isOut>a</type:isOut>
|
158
|
+
<com:zone>b</com:zone>
|
159
|
+
<type:options>
|
160
|
+
<com:one>one</com:one>
|
161
|
+
<com:two>two</com:two>
|
162
|
+
</type:options>
|
163
|
+
</type:query>
|
164
|
+
X
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|