xml_schema_mapper 0.0.1
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 +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>
|