xml-mapping 0.8.1 → 0.9.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/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>
|