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.
Files changed (71) hide show
  1. data/ChangeLog +64 -3
  2. data/README +871 -173
  3. data/README_XPATH +40 -13
  4. data/Rakefile +37 -26
  5. data/TODO.txt +39 -8
  6. data/examples/README +5 -0
  7. data/examples/company_usage.intout +34 -22
  8. data/examples/documents_folders.rb +31 -0
  9. data/examples/documents_folders.xml +16 -0
  10. data/examples/documents_folders_usage.intin.rb +18 -0
  11. data/examples/documents_folders_usage.intout +46 -0
  12. data/examples/order_signature_enhanced_usage.intout +21 -11
  13. data/examples/order_usage.intin.rb +52 -5
  14. data/examples/order_usage.intout +154 -80
  15. data/examples/person.intin.rb +44 -0
  16. data/examples/person.intout +27 -0
  17. data/examples/person_mm.intin.rb +119 -0
  18. data/examples/person_mm.intout +114 -0
  19. data/examples/publication.intin.rb +44 -0
  20. data/examples/publication.intout +20 -0
  21. data/examples/reader.intin.rb +33 -0
  22. data/examples/reader.intout +19 -0
  23. data/examples/stringarray.rb +5 -0
  24. data/examples/stringarray.xml +10 -0
  25. data/examples/stringarray_usage.intin.rb +11 -0
  26. data/examples/stringarray_usage.intout +31 -0
  27. data/examples/time_augm.intout +19 -7
  28. data/examples/time_augm_loading.intin.rb +44 -0
  29. data/examples/time_augm_loading.intout +12 -0
  30. data/examples/time_node.intin.rb +79 -0
  31. data/examples/time_node.rb +3 -2
  32. data/examples/time_node_w_marshallers.intin.rb +48 -0
  33. data/examples/time_node_w_marshallers.intout +25 -0
  34. data/examples/time_node_w_marshallers.xml +9 -0
  35. data/examples/xpath_create_new.intout +132 -114
  36. data/examples/xpath_ensure_created.intout +86 -65
  37. data/examples/xpath_pathological.intout +16 -16
  38. data/examples/xpath_usage.intout +1 -1
  39. data/install.rb +1 -0
  40. data/lib/xml/mapping.rb +3 -1
  41. data/lib/xml/mapping/base.rb +442 -272
  42. data/lib/xml/mapping/core_classes_mapping.rb +32 -0
  43. data/lib/xml/mapping/standard_nodes.rb +176 -86
  44. data/lib/xml/mapping/version.rb +2 -2
  45. data/lib/xml/rexml_ext.rb +186 -0
  46. data/lib/xml/xxpath.rb +28 -265
  47. data/lib/xml/xxpath/steps.rb +345 -0
  48. data/lib/xml/xxpath_methods.rb +96 -0
  49. data/test/all_tests.rb +4 -1
  50. data/test/benchmark_fixtures.rb +14 -0
  51. data/test/{multiple_mappings.rb → bookmarks.rb} +0 -0
  52. data/test/company.rb +47 -0
  53. data/test/documents_folders.rb +11 -1
  54. data/test/examples_test.rb +29 -0
  55. data/test/fixtures/benchmark.xml +77 -0
  56. data/test/fixtures/company1.xml +9 -0
  57. data/test/fixtures/documents_folders.xml +0 -8
  58. data/test/fixtures/documents_folders2.xml +13 -19
  59. data/test/fixtures/triangle_m1.xml +17 -0
  60. data/test/fixtures/triangle_m2.xml +19 -0
  61. data/test/inheritance_test.rb +50 -0
  62. data/test/multiple_mappings_test.rb +155 -0
  63. data/test/rexml_xpath_benchmark.rb +29 -0
  64. data/test/triangle_mm.rb +57 -0
  65. data/test/xml_mapping_adv_test.rb +36 -1
  66. data/test/xml_mapping_test.rb +136 -7
  67. data/test/xpath_test.rb +154 -0
  68. data/test/xxpath_benchmark.rb +36 -0
  69. data/test/xxpath_benchmark.result1.txt +17 -0
  70. data/test/xxpath_methods_test.rb +61 -0
  71. 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,5 @@
1
+ require 'xml/mapping'
2
+ class People
3
+ include XML::Mapping
4
+ array_node :names, "names", "name", :class=>String
5
+ end
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+
3
+ <people>
4
+ <names>
5
+ <name>Jim</name>
6
+ <name>Susan</name>
7
+ <name>Herbie</name>
8
+ <name>Nancy</name>
9
+ </names>
10
+ </people>
@@ -0,0 +1,11 @@
1
+ #:invisible:
2
+ $:.unshift "../lib"
3
+ require 'stringarray' #<=
4
+ #:visible:
5
+ ppl=People.load_from_file("stringarray.xml") #<=
6
+ ppl.names #<=
7
+
8
+ ppl.names.concat ["Mary","Arnold"] #<=
9
+ #:invisible_retval:
10
+ ppl.save_to_xml.write $stdout,2
11
+ #<=
@@ -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>