xml-mapping 0.8.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +64 -3
- data/README +871 -173
- data/README_XPATH +40 -13
- data/Rakefile +37 -26
- data/TODO.txt +39 -8
- data/examples/README +5 -0
- data/examples/company_usage.intout +34 -22
- data/examples/documents_folders.rb +31 -0
- data/examples/documents_folders.xml +16 -0
- data/examples/documents_folders_usage.intin.rb +18 -0
- data/examples/documents_folders_usage.intout +46 -0
- data/examples/order_signature_enhanced_usage.intout +21 -11
- data/examples/order_usage.intin.rb +52 -5
- data/examples/order_usage.intout +154 -80
- data/examples/person.intin.rb +44 -0
- data/examples/person.intout +27 -0
- data/examples/person_mm.intin.rb +119 -0
- data/examples/person_mm.intout +114 -0
- data/examples/publication.intin.rb +44 -0
- data/examples/publication.intout +20 -0
- data/examples/reader.intin.rb +33 -0
- data/examples/reader.intout +19 -0
- data/examples/stringarray.rb +5 -0
- data/examples/stringarray.xml +10 -0
- data/examples/stringarray_usage.intin.rb +11 -0
- data/examples/stringarray_usage.intout +31 -0
- data/examples/time_augm.intout +19 -7
- data/examples/time_augm_loading.intin.rb +44 -0
- data/examples/time_augm_loading.intout +12 -0
- data/examples/time_node.intin.rb +79 -0
- data/examples/time_node.rb +3 -2
- data/examples/time_node_w_marshallers.intin.rb +48 -0
- data/examples/time_node_w_marshallers.intout +25 -0
- data/examples/time_node_w_marshallers.xml +9 -0
- data/examples/xpath_create_new.intout +132 -114
- data/examples/xpath_ensure_created.intout +86 -65
- data/examples/xpath_pathological.intout +16 -16
- data/examples/xpath_usage.intout +1 -1
- data/install.rb +1 -0
- data/lib/xml/mapping.rb +3 -1
- data/lib/xml/mapping/base.rb +442 -272
- data/lib/xml/mapping/core_classes_mapping.rb +32 -0
- data/lib/xml/mapping/standard_nodes.rb +176 -86
- data/lib/xml/mapping/version.rb +2 -2
- data/lib/xml/rexml_ext.rb +186 -0
- data/lib/xml/xxpath.rb +28 -265
- data/lib/xml/xxpath/steps.rb +345 -0
- data/lib/xml/xxpath_methods.rb +96 -0
- data/test/all_tests.rb +4 -1
- data/test/benchmark_fixtures.rb +14 -0
- data/test/{multiple_mappings.rb → bookmarks.rb} +0 -0
- data/test/company.rb +47 -0
- data/test/documents_folders.rb +11 -1
- data/test/examples_test.rb +29 -0
- data/test/fixtures/benchmark.xml +77 -0
- data/test/fixtures/company1.xml +9 -0
- data/test/fixtures/documents_folders.xml +0 -8
- data/test/fixtures/documents_folders2.xml +13 -19
- data/test/fixtures/triangle_m1.xml +17 -0
- data/test/fixtures/triangle_m2.xml +19 -0
- data/test/inheritance_test.rb +50 -0
- data/test/multiple_mappings_test.rb +155 -0
- data/test/rexml_xpath_benchmark.rb +29 -0
- data/test/triangle_mm.rb +57 -0
- data/test/xml_mapping_adv_test.rb +36 -1
- data/test/xml_mapping_test.rb +136 -7
- data/test/xpath_test.rb +154 -0
- data/test/xxpath_benchmark.rb +36 -0
- data/test/xxpath_benchmark.result1.txt +17 -0
- data/test/xxpath_methods_test.rb +61 -0
- metadata +139 -90
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
class Person
|
3
|
+
include XML::Mapping
|
4
|
+
|
5
|
+
choice_node :if, 'name', :then, (text_node :name, 'name'),
|
6
|
+
:elsif, '@name', :then, (text_node :name, '@name'),
|
7
|
+
:else, (text_node :name, '.')
|
8
|
+
end
|
9
|
+
|
10
|
+
### usage
|
11
|
+
|
12
|
+
p1 = Person.load_from_xml(REXML::Document.new('<person name="Jim"/>').root)
|
13
|
+
=> #<Person:0x7f48763d3360 @name="Jim">
|
14
|
+
|
15
|
+
p2 = Person.load_from_xml(REXML::Document.new('<person><name>James</name></person>').root)
|
16
|
+
=> #<Person:0x7f48763ce900 @name="James">
|
17
|
+
|
18
|
+
p3 = Person.load_from_xml(REXML::Document.new('<person>Suzy</person>').root)
|
19
|
+
=> #<Person:0x7f48763c99f0 @name="Suzy">
|
20
|
+
|
21
|
+
|
22
|
+
p1.save_to_xml.write($stdout)
|
23
|
+
<person><name>Jim</name></person>
|
24
|
+
p2.save_to_xml.write($stdout)
|
25
|
+
<person><name>James</name></person>
|
26
|
+
p3.save_to_xml.write($stdout)
|
27
|
+
<person><name>Suzy</name></person>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#:invisible:
|
2
|
+
$:.unshift "../lib"
|
3
|
+
begin
|
4
|
+
Object.send(:remove_const, "Address") # remove any previous definitions
|
5
|
+
Object.send(:remove_const, "Person") # remove any previous definitions
|
6
|
+
rescue
|
7
|
+
end
|
8
|
+
#<=
|
9
|
+
#:visible:
|
10
|
+
require 'xml/mapping'
|
11
|
+
|
12
|
+
class Address; end
|
13
|
+
|
14
|
+
class Person
|
15
|
+
include XML::Mapping
|
16
|
+
|
17
|
+
# the default mapping. Stores the name and age in XML attributes,
|
18
|
+
# and the address in a sub-element "address".
|
19
|
+
|
20
|
+
text_node :name, "@name"
|
21
|
+
numeric_node :age, "@age"
|
22
|
+
object_node :address, "address", :class=>Address
|
23
|
+
|
24
|
+
use_mapping :other
|
25
|
+
|
26
|
+
# the ":other" mapping. Non-default root element name; name and age
|
27
|
+
# stored in XML elements; address stored in the person's element
|
28
|
+
# itself
|
29
|
+
|
30
|
+
root_element_name "individual"
|
31
|
+
text_node :name, "name"
|
32
|
+
numeric_node :age, "age"
|
33
|
+
object_node :address, ".", :class=>Address
|
34
|
+
|
35
|
+
# you could also specify the mapping on a per-node basis with the
|
36
|
+
# :mapping option, e.g.:
|
37
|
+
#
|
38
|
+
# numeric_node :age, "age", :mapping=>:other
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class Address
|
43
|
+
include XML::Mapping
|
44
|
+
|
45
|
+
# the default mapping.
|
46
|
+
|
47
|
+
text_node :street, "street"
|
48
|
+
numeric_node :number, "number"
|
49
|
+
text_node :city, "city"
|
50
|
+
numeric_node :zip, "zip"
|
51
|
+
|
52
|
+
use_mapping :other
|
53
|
+
|
54
|
+
# the ":other" mapping.
|
55
|
+
|
56
|
+
text_node :street, "street-name"
|
57
|
+
numeric_node :number, "street-name/@number"
|
58
|
+
text_node :city, "city-name"
|
59
|
+
numeric_node :zip, "city-name/@zip-code"
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
### usage
|
64
|
+
|
65
|
+
## XML representation of a person in the default mapping
|
66
|
+
xml = REXML::Document.new('
|
67
|
+
<person name="Suzy" age="28">
|
68
|
+
<address>
|
69
|
+
<street>Abbey Road</street>
|
70
|
+
<number>72</number>
|
71
|
+
<city>London</city>
|
72
|
+
<zip>18827</zip>
|
73
|
+
</address>
|
74
|
+
</person>').root
|
75
|
+
|
76
|
+
## load using the default mapping
|
77
|
+
p = Person.load_from_xml xml #<=
|
78
|
+
|
79
|
+
#:invisible_retval:
|
80
|
+
## save using the default mapping
|
81
|
+
xml2 = p.save_to_xml
|
82
|
+
xml2.write $stdout,2 #<=
|
83
|
+
|
84
|
+
## xml2 identical to xml
|
85
|
+
|
86
|
+
|
87
|
+
## now, save the same person to XML using the :other mapping...
|
88
|
+
other_xml = p.save_to_xml :mapping=>:other
|
89
|
+
other_xml.write $stdout,2 #<=
|
90
|
+
|
91
|
+
#:visible_retval:
|
92
|
+
## load it again using the :other mapping
|
93
|
+
p2 = Person.load_from_xml other_xml, :mapping=>:other #<=
|
94
|
+
|
95
|
+
#:invisible_retval:
|
96
|
+
## p2 identical to p #<=
|
97
|
+
|
98
|
+
#:invisible:
|
99
|
+
require 'test/unit/assertions'
|
100
|
+
include Test::Unit::Assertions
|
101
|
+
|
102
|
+
require 'xml/xxpath_methods'
|
103
|
+
|
104
|
+
assert_equal "Suzy", p.name
|
105
|
+
assert_equal 28, p.age
|
106
|
+
assert_equal "Abbey Road", p.address.street
|
107
|
+
assert_equal 72, p.address.number
|
108
|
+
assert_equal "London", p.address.city
|
109
|
+
assert_equal 18827, p.address.zip
|
110
|
+
|
111
|
+
assert_equal "individual", other_xml.name
|
112
|
+
assert_equal p.name, other_xml.first_xpath("name").text
|
113
|
+
assert_equal p.age, other_xml.first_xpath("age").text.to_i
|
114
|
+
assert_equal p.address.street, other_xml.first_xpath("street-name").text
|
115
|
+
assert_equal p.address.number, other_xml.first_xpath("street-name/@number").text.to_i
|
116
|
+
assert_equal p.address.city, other_xml.first_xpath("city-name").text
|
117
|
+
assert_equal p.address.zip, other_xml.first_xpath("city-name/@zip-code").text.to_i
|
118
|
+
|
119
|
+
#<=
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'xml/mapping'
|
2
|
+
|
3
|
+
class Address; end
|
4
|
+
|
5
|
+
class Person
|
6
|
+
include XML::Mapping
|
7
|
+
|
8
|
+
# the default mapping. Stores the name and age in XML attributes,
|
9
|
+
# and the address in a sub-element "address".
|
10
|
+
|
11
|
+
text_node :name, "@name"
|
12
|
+
numeric_node :age, "@age"
|
13
|
+
object_node :address, "address", :class=>Address
|
14
|
+
|
15
|
+
use_mapping :other
|
16
|
+
|
17
|
+
# the ":other" mapping. Non-default root element name; name and age
|
18
|
+
# stored in XML elements; address stored in the person's element
|
19
|
+
# itself
|
20
|
+
|
21
|
+
root_element_name "individual"
|
22
|
+
text_node :name, "name"
|
23
|
+
numeric_node :age, "age"
|
24
|
+
object_node :address, ".", :class=>Address
|
25
|
+
|
26
|
+
# you could also specify the mapping on a per-node basis with the
|
27
|
+
# :mapping option, e.g.:
|
28
|
+
#
|
29
|
+
# numeric_node :age, "age", :mapping=>:other
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class Address
|
34
|
+
include XML::Mapping
|
35
|
+
|
36
|
+
# the default mapping.
|
37
|
+
|
38
|
+
text_node :street, "street"
|
39
|
+
numeric_node :number, "number"
|
40
|
+
text_node :city, "city"
|
41
|
+
numeric_node :zip, "zip"
|
42
|
+
|
43
|
+
use_mapping :other
|
44
|
+
|
45
|
+
# the ":other" mapping.
|
46
|
+
|
47
|
+
text_node :street, "street-name"
|
48
|
+
numeric_node :number, "street-name/@number"
|
49
|
+
text_node :city, "city-name"
|
50
|
+
numeric_node :zip, "city-name/@zip-code"
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
### usage
|
55
|
+
|
56
|
+
## XML representation of a person in the default mapping
|
57
|
+
xml = REXML::Document.new('
|
58
|
+
<person name="Suzy" age="28">
|
59
|
+
<address>
|
60
|
+
<street>Abbey Road</street>
|
61
|
+
<number>72</number>
|
62
|
+
<city>London</city>
|
63
|
+
<zip>18827</zip>
|
64
|
+
</address>
|
65
|
+
</person>').root
|
66
|
+
|
67
|
+
## load using the default mapping
|
68
|
+
p = Person.load_from_xml xml
|
69
|
+
=> #<Person:0x7f487663af90 @address=#<Address:0x7f4876637250 @number=72, @zip=18827, @city="London", @street="Abbey Road">, @name="Suzy", @age=28>
|
70
|
+
|
71
|
+
## save using the default mapping
|
72
|
+
xml2 = p.save_to_xml
|
73
|
+
xml2.write $stdout,2
|
74
|
+
<person name='Suzy' age='28'>
|
75
|
+
<address>
|
76
|
+
<street>
|
77
|
+
Abbey Road
|
78
|
+
</street>
|
79
|
+
<number>
|
80
|
+
72
|
81
|
+
</number>
|
82
|
+
<city>
|
83
|
+
London
|
84
|
+
</city>
|
85
|
+
<zip>
|
86
|
+
18827
|
87
|
+
</zip>
|
88
|
+
</address>
|
89
|
+
</person>
|
90
|
+
## xml2 identical to xml
|
91
|
+
|
92
|
+
|
93
|
+
## now, save the same person to XML using the :other mapping...
|
94
|
+
other_xml = p.save_to_xml :mapping=>:other
|
95
|
+
other_xml.write $stdout,2
|
96
|
+
<individual>
|
97
|
+
<name>
|
98
|
+
Suzy
|
99
|
+
</name>
|
100
|
+
<age>
|
101
|
+
28
|
102
|
+
</age>
|
103
|
+
<street-name number='72'>
|
104
|
+
Abbey Road
|
105
|
+
</street-name>
|
106
|
+
<city-name zip-code='18827'>
|
107
|
+
London
|
108
|
+
</city-name>
|
109
|
+
</individual>
|
110
|
+
## load it again using the :other mapping
|
111
|
+
p2 = Person.load_from_xml other_xml, :mapping=>:other
|
112
|
+
=> #<Person:0x7f4876600958 @address=#<Address:0x7f48765fdfc8 @number=72, @zip=18827, @city="London", @street="Abbey Road">, @name="Suzy", @age=28>
|
113
|
+
|
114
|
+
## p2 identical to p
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#:invisible:
|
2
|
+
$:.unshift "../lib"
|
3
|
+
require 'xml/mapping'
|
4
|
+
require 'xml/xxpath_methods'
|
5
|
+
#<=
|
6
|
+
#:visible:
|
7
|
+
|
8
|
+
class Publication
|
9
|
+
include XML::Mapping
|
10
|
+
|
11
|
+
choice_node :if, '@author', :then, (text_node :author, '@author'),
|
12
|
+
:elsif, 'contr', :then, (array_node :contributors, 'contr', :class=>String)
|
13
|
+
end
|
14
|
+
|
15
|
+
### usage
|
16
|
+
|
17
|
+
p1 = Publication.load_from_xml(REXML::Document.new('<publication author="Jim"/>').root)#<=
|
18
|
+
|
19
|
+
p2 = Publication.load_from_xml(REXML::Document.new('
|
20
|
+
<publication>
|
21
|
+
<contr>Chris</contr>
|
22
|
+
<contr>Mel</contr>
|
23
|
+
<contr>Toby</contr>
|
24
|
+
</publication>').root)#<=
|
25
|
+
|
26
|
+
#:invisible:
|
27
|
+
require 'test/unit/assertions'
|
28
|
+
include Test::Unit::Assertions
|
29
|
+
|
30
|
+
assert_equal "Jim", p1.author
|
31
|
+
assert_nil p1.contributors
|
32
|
+
|
33
|
+
assert_nil p2.author
|
34
|
+
assert_equal ["Chris", "Mel", "Toby"], p2.contributors
|
35
|
+
|
36
|
+
xml1 = p1.save_to_xml
|
37
|
+
xml2 = p2.save_to_xml
|
38
|
+
|
39
|
+
assert_equal p1.author, xml1.first_xpath("@author").text
|
40
|
+
assert_nil xml1.first_xpath("contr", :allow_nil=>true)
|
41
|
+
|
42
|
+
assert_nil xml2.first_xpath("@author", :allow_nil=>true)
|
43
|
+
assert_equal p2.contributors, xml2.all_xpath("contr").map{|elt|elt.text}
|
44
|
+
#<=
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
class Publication
|
3
|
+
include XML::Mapping
|
4
|
+
|
5
|
+
choice_node :if, '@author', :then, (text_node :author, '@author'),
|
6
|
+
:elsif, 'contr', :then, (array_node :contributors, 'contr', :class=>String)
|
7
|
+
end
|
8
|
+
|
9
|
+
### usage
|
10
|
+
|
11
|
+
p1 = Publication.load_from_xml(REXML::Document.new('<publication author="Jim"/>').root)
|
12
|
+
=> #<Publication:0x7f487656b308 @author="Jim">
|
13
|
+
|
14
|
+
p2 = Publication.load_from_xml(REXML::Document.new('
|
15
|
+
<publication>
|
16
|
+
<contr>Chris</contr>
|
17
|
+
<contr>Mel</contr>
|
18
|
+
<contr>Toby</contr>
|
19
|
+
</publication>').root)
|
20
|
+
=> #<Publication:0x7f48766be930 @contributors=["Chris", "Mel", "Toby"]>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#:invisible:
|
2
|
+
$:.unshift "../lib"
|
3
|
+
require 'xml/mapping'
|
4
|
+
require 'xml/xxpath_methods'
|
5
|
+
#<=
|
6
|
+
#:visible:
|
7
|
+
|
8
|
+
class Foo
|
9
|
+
include XML::Mapping
|
10
|
+
|
11
|
+
text_node :name, "@name", :reader=>proc{|obj,xml,default_reader|
|
12
|
+
default_reader.call(obj,xml)
|
13
|
+
obj.name += xml.attributes['more']
|
14
|
+
},
|
15
|
+
:writer=>proc{|obj,xml|
|
16
|
+
xml.attributes['bar'] = "hi #{obj.name} ho"
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
f = Foo.load_from_xml(REXML::Document.new('<foo name="Jim" more="XYZ"/>').root)#<=
|
21
|
+
|
22
|
+
#:invisible_retval:
|
23
|
+
xml = f.save_to_xml
|
24
|
+
xml.write $stdout,2 #<=
|
25
|
+
|
26
|
+
#:invisible:
|
27
|
+
require 'test/unit/assertions'
|
28
|
+
include Test::Unit::Assertions
|
29
|
+
|
30
|
+
assert_equal "JimXYZ", f.name
|
31
|
+
assert_equal "hi JimXYZ ho", xml.attributes['bar']
|
32
|
+
|
33
|
+
#<=
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
class Foo
|
3
|
+
include XML::Mapping
|
4
|
+
|
5
|
+
text_node :name, "@name", :reader=>proc{|obj,xml,default_reader|
|
6
|
+
default_reader.call(obj,xml)
|
7
|
+
obj.name += xml.attributes['more']
|
8
|
+
},
|
9
|
+
:writer=>proc{|obj,xml|
|
10
|
+
xml.attributes['bar'] = "hi #{obj.name} ho"
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
f = Foo.load_from_xml(REXML::Document.new('<foo name="Jim" more="XYZ"/>').root)
|
15
|
+
=> #<Foo:0x7f48766cdef8 @name="JimXYZ">
|
16
|
+
|
17
|
+
xml = f.save_to_xml
|
18
|
+
xml.write $stdout,2
|
19
|
+
<foo bar='hi JimXYZ ho'/>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
ppl=People.load_from_file("stringarray.xml")
|
2
|
+
=> #<People:0x7f487665ecd8 @names=["Jim", "Susan", "Herbie", "Nancy"]>
|
3
|
+
ppl.names
|
4
|
+
=> ["Jim", "Susan", "Herbie", "Nancy"]
|
5
|
+
|
6
|
+
ppl.names.concat ["Mary","Arnold"]
|
7
|
+
=> ["Jim", "Susan", "Herbie", "Nancy", "Mary", "Arnold"]
|
8
|
+
ppl.save_to_xml.write $stdout,2
|
9
|
+
|
10
|
+
<people>
|
11
|
+
<names>
|
12
|
+
<name>
|
13
|
+
Jim
|
14
|
+
</name>
|
15
|
+
<name>
|
16
|
+
Susan
|
17
|
+
</name>
|
18
|
+
<name>
|
19
|
+
Herbie
|
20
|
+
</name>
|
21
|
+
<name>
|
22
|
+
Nancy
|
23
|
+
</name>
|
24
|
+
<name>
|
25
|
+
Mary
|
26
|
+
</name>
|
27
|
+
<name>
|
28
|
+
Arnold
|
29
|
+
</name>
|
30
|
+
</names>
|
31
|
+
</people>
|