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.
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>