xml_schema_mapper 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +8 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +459 -0
- data/.idea/xml_schema_mapper.iml +29 -0
- data/.rspec +2 -0
- data/Gemfile +8 -0
- data/Guardfile +9 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/xml_schema_mapper +7 -0
- data/lib/thor/templates/converter_class.erb +13 -0
- data/lib/thor/templates/converter_spec.erb +11 -0
- data/lib/thor/templates/mapper_class.erb +16 -0
- data/lib/thor/templates/mapper_spec.erb +16 -0
- data/lib/thor/xsd_mappers.rb +91 -0
- data/lib/xml_schema_mapper/builder.rb +105 -0
- data/lib/xml_schema_mapper/element.rb +78 -0
- data/lib/xml_schema_mapper/parser.rb +30 -0
- data/lib/xml_schema_mapper/version.rb +3 -0
- data/lib/xml_schema_mapper.rb +77 -0
- data/spec/build_xml_spec.rb +34 -0
- data/spec/builder_spec.rb +126 -0
- data/spec/element_spec.rb +10 -0
- data/spec/fixtures/LocalUserService.xsd +17 -0
- data/spec/fixtures/UserService.xsd +67 -0
- data/spec/fixtures/common.xsd +23 -0
- data/spec/fixtures/get_first_name.xml +13 -0
- data/spec/fixtures/instance1.xml +14 -0
- data/spec/fixtures/user_service.rb +23 -0
- data/spec/parse_xml_spec.rb +36 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/xml_schema_mapper_spec.rb +28 -0
- data/xml_schema_mapper.gemspec +26 -0
- metadata +193 -0
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# XmlSchemaMapper
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'xml_schema_mapper'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install xml_schema_mapper
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
<%- if options[:module_name].present? -%>
|
2
|
+
class <%= options[:module_name] %>::<%= name.camelize %>Converter
|
3
|
+
<% else -%>
|
4
|
+
class <%= name.camelize %>Converter
|
5
|
+
<% end -%>
|
6
|
+
include ModelConverter
|
7
|
+
|
8
|
+
converter do
|
9
|
+
<%- attributes.each do |attr| -%>
|
10
|
+
convert_attr :<%= attr.underscore %>
|
11
|
+
<%- end %>
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
<%- if options[:module_name].present? -%>
|
4
|
+
describe <%= options[:module_name] %>::<%= name.camelize %> do
|
5
|
+
<% else -%>
|
6
|
+
describe <%= name.camelize %> do
|
7
|
+
<% end -%>
|
8
|
+
it { should be_a XmlSchemaMapper }
|
9
|
+
it { _schema.should be_a LibXML::XML::Schema }
|
10
|
+
it { _type.name.should eql '<%= name %>' }
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# @note <%= type.annotation.to_s.gsub("\n", "\n# ") %>
|
3
|
+
|
4
|
+
<%- elements.each do |element| -%>
|
5
|
+
# @attr <%= element.name %> [<%= element.type.name %>] <%= element.annotation || element.type.annotation %>
|
6
|
+
<%- end -%>
|
7
|
+
|
8
|
+
<%- if options[:module_name].present? -%>
|
9
|
+
class <%= options[:module_name] %>::<%= name.camelize %>Mapper
|
10
|
+
<% else -%>
|
11
|
+
class <%= name.camelize %>Mapper
|
12
|
+
<% end -%>
|
13
|
+
include XmlSchemaMapper
|
14
|
+
schema '<%= schema_path %>'
|
15
|
+
type '<%= name %>'
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# <%= type.annotation.to_s.gsub("\n", "\n# ") %>
|
3
|
+
|
4
|
+
<%- elements.each do |element| -%>
|
5
|
+
# @attr <%= element.name %> [<%= element.type.name %>] <%= element.type.annotation %>
|
6
|
+
<%- end %>
|
7
|
+
|
8
|
+
require 'spec_helper'
|
9
|
+
|
10
|
+
<%- if options[:module_name].present? -%>
|
11
|
+
describe <%= options[:module_name] %>::<%= name.camelize %> do
|
12
|
+
<% else -%>
|
13
|
+
describe <%= name.camelize %> do
|
14
|
+
<% end -%>
|
15
|
+
it { should be_a ModelConverter }
|
16
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "thor/group"
|
3
|
+
|
4
|
+
module XsdMappers
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
desc 'mappers path/to/xsd path/to/generate/classes', 'generate classes for xsd types'
|
8
|
+
method_option :module_name, default: ''
|
9
|
+
def mappers(schema_path, destination = './')
|
10
|
+
schema(schema_path).types.each do |name, type|
|
11
|
+
Mappers.new([name, schema_path, destination]).invoke_all
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'converters path/to/xsd path/to/generate/classes', 'generate converters for xsd types'
|
16
|
+
method_option :module_name, default: ''
|
17
|
+
def converters(schema_path, destination = './')
|
18
|
+
schema(schema_path).types.each do |name, type|
|
19
|
+
Converters.new([name, schema_path, destination], options.merge(attributes: type.elements.keys)).invoke_all
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def schema(path)
|
26
|
+
@schema ||= LibXML::XML::Schema.cached(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class Mappers < Thor::Group
|
32
|
+
include Thor::Actions
|
33
|
+
|
34
|
+
# Define arguments and options
|
35
|
+
argument :name
|
36
|
+
argument :schema_path
|
37
|
+
argument :destination, default: './'
|
38
|
+
class_option :module_name, default: ''
|
39
|
+
class_option :override, default: false
|
40
|
+
class_option :base_type, default: nil
|
41
|
+
class_option :force, default: true
|
42
|
+
|
43
|
+
def self.source_root
|
44
|
+
File.dirname(__FILE__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_lib_file
|
48
|
+
template('templates/mapper_class.erb', "app/#{destination}/#{name.underscore}_mapper.rb")
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_test_file
|
52
|
+
test = options[:test_framework] == "test" ? :test : :spec
|
53
|
+
with_padding do
|
54
|
+
template 'templates/mapper_spec.erb', "spec/#{destination}/#{name.underscore}_mapper_#{test}.rb"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
def attributes
|
60
|
+
options[:attributes]
|
61
|
+
end
|
62
|
+
|
63
|
+
def schema
|
64
|
+
@schema ||= LibXML::XML::Schema.cached(schema_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def elements
|
68
|
+
@elements ||= type.elements.values
|
69
|
+
end
|
70
|
+
|
71
|
+
def type
|
72
|
+
@type ||= schema.types[name]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Converters < Mappers
|
77
|
+
class_option :attributes, type: :array
|
78
|
+
class_option :force, default: false
|
79
|
+
|
80
|
+
def create_lib_file
|
81
|
+
template('templates/converter_class.erb', "app/#{destination}/#{name.underscore}_converter.rb")
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_test_file
|
85
|
+
test = options[:test_framework] == "test" ? :test : :spec
|
86
|
+
with_padding do
|
87
|
+
template 'templates/converter_spec.erb', "spec/#{destination}/#{name.underscore}_converter_#{test}.rb"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class NoToXmlError < NoMethodError
|
2
|
+
end
|
3
|
+
|
4
|
+
module XmlSchemaMapper
|
5
|
+
class Builder
|
6
|
+
|
7
|
+
attr_reader :document, :parent
|
8
|
+
|
9
|
+
delegate :elements, :to => :@klass
|
10
|
+
|
11
|
+
def initialize(source, parent)
|
12
|
+
@parent = parent.is_a?(Nokogiri::XML::Document) ? parent.root : parent
|
13
|
+
@document = parent.document
|
14
|
+
@source = source
|
15
|
+
@klass = source.class
|
16
|
+
@schema = @klass._schema
|
17
|
+
end
|
18
|
+
|
19
|
+
def build
|
20
|
+
elements.each do |element|
|
21
|
+
add_element_namespace_to_root!(element)
|
22
|
+
node = create_node(element)
|
23
|
+
parent << node unless node.content.blank?
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def clean!
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :source, :schema
|
35
|
+
|
36
|
+
def create_node(element)
|
37
|
+
setup_namespace(element) do
|
38
|
+
element.simple? ? simple_node(element) : complex_node(element)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_namespace(element)
|
43
|
+
yield.tap do |node|
|
44
|
+
return if node.nil?
|
45
|
+
node.namespace = find_namespace_definition(element.namespace)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def simple_node(element)
|
50
|
+
document.create_element(element.name, element.content_from(source))
|
51
|
+
end
|
52
|
+
|
53
|
+
def complex_node(element)
|
54
|
+
object = source.send(element.reader)
|
55
|
+
complex_root_node = document.create_element(element.name)
|
56
|
+
|
57
|
+
if object.is_a?(XmlSchemaMapper)
|
58
|
+
complex_node_from_mapper(complex_root_node, object)
|
59
|
+
else
|
60
|
+
complex_node_from_xml(complex_root_node, object)
|
61
|
+
end
|
62
|
+
rescue NoToXmlError
|
63
|
+
raise("object of #{source.class}##{element.reader} should respond to :to_xml")
|
64
|
+
end
|
65
|
+
|
66
|
+
def complex_node_from_xml(root, object)
|
67
|
+
return root if object.nil?
|
68
|
+
if object.respond_to?(:to_xml)
|
69
|
+
root << object.to_xml
|
70
|
+
else
|
71
|
+
raise NoToXmlError
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def complex_node_from_mapper(root, object)
|
76
|
+
XmlSchemaMapper::Builder.build(object, root).parent
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_element_namespace_to_root!(element)
|
80
|
+
if element.namespace
|
81
|
+
ns = schema.namespaces.find_by_href(element.namespace)
|
82
|
+
raise "prefix for namespace #{element.namespace.inspect} not found" unless ns
|
83
|
+
|
84
|
+
document.root.add_namespace(ns.prefix, ns.href)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def find_namespace_definition(href)
|
89
|
+
document.root.namespace_definitions.find { |ns| ns.href == href }
|
90
|
+
end
|
91
|
+
|
92
|
+
# CLASS_METHODS
|
93
|
+
|
94
|
+
def self.create_document(xtype)
|
95
|
+
Nokogiri::XML::Document.new.tap do |doc|
|
96
|
+
doc.root = doc.create_element(xtype.name.camelize(:lower))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.build(mapper, parent)
|
101
|
+
XmlSchemaMapper::Builder.new(mapper, parent).build
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
Int = Integer
|
2
|
+
Double = Float
|
3
|
+
Decimal = Integer
|
4
|
+
|
5
|
+
module XmlSchemaMapper
|
6
|
+
class Element
|
7
|
+
attr_reader :xsd
|
8
|
+
|
9
|
+
delegate :name, :namespace, :type, to: :xsd
|
10
|
+
|
11
|
+
def initialize(xsd_element, klass=nil)
|
12
|
+
@xsd = xsd_element
|
13
|
+
@klass = klass
|
14
|
+
end
|
15
|
+
|
16
|
+
def klass
|
17
|
+
@klass ||= begin
|
18
|
+
name = (klass_name || base_klass_name)
|
19
|
+
name ? (name+"Mapper").constantize : XmlSchemaMapper.default_class
|
20
|
+
rescue NameError
|
21
|
+
name.constantize
|
22
|
+
rescue NameError => e
|
23
|
+
raise e, "NotImplimented type #{name.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def simple?
|
28
|
+
[
|
29
|
+
LibXML::XML::Schema::Types::XML_SCHEMA_TYPE_SIMPLE,
|
30
|
+
LibXML::XML::Schema::Types::XML_SCHEMA_TYPE_BASIC
|
31
|
+
].include? @xsd.type.kind
|
32
|
+
end
|
33
|
+
|
34
|
+
def content_from(object)
|
35
|
+
data = object.send(reader)
|
36
|
+
data.respond_to?(:to_xml) ? data.to_xml : data
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_name
|
40
|
+
name.underscore
|
41
|
+
end
|
42
|
+
|
43
|
+
def writer
|
44
|
+
"#{method_name}="
|
45
|
+
end
|
46
|
+
|
47
|
+
def reader
|
48
|
+
"#{method_name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def xpath(xml)
|
52
|
+
if namespace
|
53
|
+
xml.at_xpath("./foo:#{name}", { 'foo' => @xsd.namespace })
|
54
|
+
else
|
55
|
+
xml.at_xpath("./#{name}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def elements
|
60
|
+
@xsd.elements.keys.map(&:to_sym)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def klass_name
|
66
|
+
@xsd.type.name.camelize
|
67
|
+
rescue NameError
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def base_klass_name
|
72
|
+
@xsd.base.name.camelize
|
73
|
+
rescue NameError
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module XmlSchemaMapper
|
2
|
+
class Parser
|
3
|
+
def initialize(klass)
|
4
|
+
@klass = klass
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse(xml)
|
8
|
+
instance = @klass.new
|
9
|
+
xml = document(xml)
|
10
|
+
@klass.elements.each do |e|
|
11
|
+
if e.simple?
|
12
|
+
instance.send(e.writer, content_for(e, xml))
|
13
|
+
else
|
14
|
+
instance.send(e.writer, e.klass.parse(e.xpath(xml)))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
instance
|
18
|
+
end
|
19
|
+
|
20
|
+
def content_for(element, xml)
|
21
|
+
node = element.xpath(xml)
|
22
|
+
node.content if node
|
23
|
+
end
|
24
|
+
|
25
|
+
def document(xml)
|
26
|
+
return xml if xml.is_a?(Nokogiri::XML::Node)
|
27
|
+
Nokogiri::XML(xml).root
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "xml_schema_mapper/version"
|
2
|
+
require "xml"
|
3
|
+
require "nokogiri"
|
4
|
+
require "active_support/concern"
|
5
|
+
require "active_support/core_ext/class"
|
6
|
+
require "active_support/core_ext/module/delegation"
|
7
|
+
require "virtus"
|
8
|
+
|
9
|
+
require "xml_schema_mapper/element"
|
10
|
+
require "xml_schema_mapper/parser"
|
11
|
+
require "xml_schema_mapper/builder"
|
12
|
+
|
13
|
+
module XmlSchemaMapper
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
mattr_accessor :default_class
|
16
|
+
self.default_class = String
|
17
|
+
|
18
|
+
included do
|
19
|
+
class_attribute :_schema
|
20
|
+
class_attribute :_type
|
21
|
+
class_attribute :elements
|
22
|
+
self.elements = []
|
23
|
+
include Virtus
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def schema(location)
|
28
|
+
self._schema = LibXML::XML::Schema.cached(location)
|
29
|
+
end
|
30
|
+
|
31
|
+
def type(name)
|
32
|
+
raise(%Q{call "schema 'path/to/your/File.xsd'" before calling "type"}) unless _schema
|
33
|
+
self._type = _schema.types[name]
|
34
|
+
define_elements!
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_elements!
|
38
|
+
_type.elements.values.each do |element|
|
39
|
+
e = XmlSchemaMapper::Element.new(element)
|
40
|
+
elements << e
|
41
|
+
begin
|
42
|
+
attr_accessor e.method_name
|
43
|
+
rescue
|
44
|
+
raise [e.method_name, e.klass, e.type.name].inspect
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse(string_or_node)
|
50
|
+
return if string_or_node.nil?
|
51
|
+
case string_or_node
|
52
|
+
when String
|
53
|
+
string = File.exist?(string_or_node) ? File.read(string_or_node) : string_or_node
|
54
|
+
XmlSchemaMapper::Parser.new(self).parse(string)
|
55
|
+
when Nokogiri::XML::Node
|
56
|
+
XmlSchemaMapper::Parser.new(self).parse(string_or_node)
|
57
|
+
else
|
58
|
+
raise(ArgumentError, "param must be a String or Nokogiri::XML::Node, but \"#{string_or_node.inspect}\" given")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def element_names
|
64
|
+
elements.map(&:name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_xml(options = {})
|
68
|
+
xml_document.root.to_xml({:encoding => 'UTF-8'}.merge(options))
|
69
|
+
end
|
70
|
+
|
71
|
+
def xml_document
|
72
|
+
document = XmlSchemaMapper::Builder.create_document(_type)
|
73
|
+
builder = XmlSchemaMapper::Builder.new(self, document.root)
|
74
|
+
builder.build
|
75
|
+
builder.document
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Build XML" do
|
4
|
+
|
5
|
+
context "by GetFirstName" do
|
6
|
+
let(:xml) { File.read('spec/fixtures/get_first_name.xml') }
|
7
|
+
|
8
|
+
context "valid data" do
|
9
|
+
let(:object) do
|
10
|
+
o = Options.new
|
11
|
+
o.one = 'one'
|
12
|
+
o.two = 'two'
|
13
|
+
|
14
|
+
f = Filter.new
|
15
|
+
f.age = 50
|
16
|
+
f.gender = 'male'
|
17
|
+
|
18
|
+
g = GetFirstName.new
|
19
|
+
g.user_identifier = '001'
|
20
|
+
g.is_out = 'a'
|
21
|
+
g.zone = 'b'
|
22
|
+
g.filter = f
|
23
|
+
g.options = o
|
24
|
+
|
25
|
+
g
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should build xml" do
|
29
|
+
object.to_xml.should eql xml
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlSchemaMapper::Builder do
|
4
|
+
let(:options) { o = Options.new; o.one = 'one'; o.two = 'two'; o }
|
5
|
+
let(:object) do
|
6
|
+
f = Filter.new; f.age = 50; f.gender = 'male'
|
7
|
+
g = GetFirstName.new; g.user_identifier = '001'; g.is_out = 'a'; g.zone = 'b'; g.filter = f; g.options = options
|
8
|
+
g
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:document) { XmlSchemaMapper::Builder.create_document(object._type) }
|
12
|
+
subject { XmlSchemaMapper::Builder.new(object, document.root) }
|
13
|
+
|
14
|
+
context 'after initialize' do
|
15
|
+
its(:source) { should be object }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'on build' do
|
19
|
+
let(:element) { stub(namespace: 'http://example.com/common/', name: 'element', simple?: true, content_from: 1) }
|
20
|
+
let(:complex_element) { stub(namespace: 'http://example.com/common/', name: 'element', simple?: false) }
|
21
|
+
let(:stub_node) { document.create_element('element') }
|
22
|
+
|
23
|
+
before do
|
24
|
+
subject.stub(elements: [element], value: 1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should create node for each element" do
|
28
|
+
subject.should_receive(:create_node).with(element).and_return(stub_node)
|
29
|
+
subject.build
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should create simple_node if element#simple?" do
|
33
|
+
element.should_receive(:simple?).and_return(true)
|
34
|
+
subject.should_receive(:simple_node).and_return(stub_node)
|
35
|
+
subject.build
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should create complex_node unless element#simple?" do
|
39
|
+
element.should_receive(:simple?).and_return(false)
|
40
|
+
subject.should_receive(:complex_node).and_return(stub_node)
|
41
|
+
subject.build
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should add namespace to root node" do
|
45
|
+
namespace = stub(prefix: 'w', href: 'namespace')
|
46
|
+
element.stub(namespace: 'namespace')
|
47
|
+
subject.stub_chain('schema.namespaces.find_by_href').and_return(namespace)
|
48
|
+
|
49
|
+
subject.build
|
50
|
+
|
51
|
+
subject.document.root.namespaces.should include "xmlns:w" => "namespace"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise error when element namespace not found" do
|
55
|
+
element.stub(namespace: 'namespace')
|
56
|
+
subject.stub_chain('schema.namespaces.find_by_href').and_return(nil)
|
57
|
+
|
58
|
+
expect { subject.build }.to raise_error("prefix for namespace \"namespace\" not found")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should set namespace for node" do
|
62
|
+
subject.stub(simple_node: stub_node)
|
63
|
+
subject.build
|
64
|
+
stub_node.namespace.prefix.should eql 'cm'
|
65
|
+
stub_node.namespace.href.should eql 'http://example.com/common/'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should create complex element with namespace" do
|
69
|
+
complex_element.stub(reader: 'filter')
|
70
|
+
element_node = document.create_element('element')
|
71
|
+
age_node = document.create_element('age', '50')
|
72
|
+
gender_node = document.create_element('gender', 'male')
|
73
|
+
subject.stub(elements: [complex_element])
|
74
|
+
|
75
|
+
subject.document.should_receive(:create_element).with('element').and_return(element_node)
|
76
|
+
subject.document.should_receive(:create_element).with('age', 50).and_return(age_node)
|
77
|
+
subject.document.should_receive(:create_element).with('gender', 'male').and_return(gender_node)
|
78
|
+
|
79
|
+
subject.build
|
80
|
+
|
81
|
+
element_node.namespace.prefix.should eql 'cm'
|
82
|
+
gender_node.namespace.prefix.should eql 'tns'
|
83
|
+
age_node.namespace.prefix.should eql 'tns'
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should create complex element without namespace" do
|
87
|
+
complex_element.stub(namespace: nil, reader: 'options')
|
88
|
+
subject.stub(elements: [complex_element])
|
89
|
+
|
90
|
+
element_node = document.create_element('element')
|
91
|
+
one_node = document.create_element('one', 'one')
|
92
|
+
two_node = document.create_element('two', 'two')
|
93
|
+
|
94
|
+
subject.document.should_receive(:create_element).with('element').and_return(element_node)
|
95
|
+
subject.document.should_receive(:create_element).with('one', 'one').and_return(one_node)
|
96
|
+
subject.document.should_receive(:create_element).with('two', 'two').and_return(two_node)
|
97
|
+
|
98
|
+
subject.build
|
99
|
+
|
100
|
+
element_node.namespace.should be_nil
|
101
|
+
one_node.namespace.should be_nil
|
102
|
+
two_node.namespace.should be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should accept not a XmlSchemaMapper for node" do
|
106
|
+
object.stub(not_a_mapper: document.create_element('not_a_mapper'))
|
107
|
+
complex_element.stub(namespace: 'http://example.com/common/', reader: 'not_a_mapper')
|
108
|
+
subject.stub(elements: [complex_element])
|
109
|
+
element_node = document.create_element('element') << object.not_a_mapper.to_xml
|
110
|
+
|
111
|
+
element_node.should_receive(:<<).with(object.not_a_mapper.to_xml).and_return(element_node)
|
112
|
+
subject.document.should_receive(:create_element).with('element').and_return(element_node)
|
113
|
+
|
114
|
+
subject.build
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should raise error when don't respond to :to_xml'" do
|
118
|
+
object.stub(not_a_mapper: [])
|
119
|
+
complex_element.stub(namespace: nil, reader: 'not_a_mapper')
|
120
|
+
subject.stub(elements: [complex_element])
|
121
|
+
|
122
|
+
expect { subject.build }.to raise_error("object of GetFirstName#not_a_mapper should respond to :to_xml")
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<xs:schema xmlns:tns="http://example.com/UserService/type/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
3
|
+
targetNamespace="http://example.com/UserService/type/loc" version="1.0">
|
4
|
+
|
5
|
+
<xs:import namespace="http://example.com/UserService/type/" schemaLocation="UserService.xsd"/>
|
6
|
+
|
7
|
+
|
8
|
+
<xs:element name="getFirstNameObj">
|
9
|
+
<xs:complexType>
|
10
|
+
<xs:sequence>
|
11
|
+
<xs:element ref="tns:getFirstName"/>
|
12
|
+
<xs:element ref="tns:getLastName"/>
|
13
|
+
</xs:sequence>
|
14
|
+
</xs:complexType>
|
15
|
+
</xs:element>
|
16
|
+
|
17
|
+
</xs:schema>
|