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
@@ -14,10 +14,22 @@ nowxml=Time.now.save_to_xml
14
14
  => <time> ... </>
15
15
  nowxml.write($stdout,2)
16
16
  <time>
17
- <year>2005</year>
18
- <month>12</month>
19
- <mday>7</mday>
20
- <hours>20</hours>
21
- <minutes>52</minutes>
22
- <seconds>4</seconds>
23
- </time>
17
+ <year>
18
+ 2010
19
+ </year>
20
+ <month>
21
+ 5
22
+ </month>
23
+ <mday>
24
+ 21
25
+ </mday>
26
+ <hours>
27
+ 16
28
+ </hours>
29
+ <minutes>
30
+ 42
31
+ </minutes>
32
+ <seconds>
33
+ 15
34
+ </seconds>
35
+ </time>
@@ -0,0 +1,44 @@
1
+ #:invisible:
2
+ $:.unshift "../lib"
3
+ require 'xml/mapping'
4
+ require 'xml/xxpath_methods'
5
+
6
+ class Time
7
+ include XML::Mapping
8
+
9
+ numeric_node :year, "year"
10
+ numeric_node :month, "month"
11
+ numeric_node :day, "mday"
12
+ numeric_node :hour, "hours"
13
+ numeric_node :min, "minutes"
14
+ numeric_node :sec, "seconds"
15
+ end
16
+
17
+ #<=
18
+ #:invisible_retval:
19
+ #:visible:
20
+
21
+ def Time.load_from_xml(xml, options={:mapping=>:_default})
22
+ year,month,day,hour,min,sec =
23
+ [xml.first_xpath("year").text.to_i,
24
+ xml.first_xpath("month").text.to_i,
25
+ xml.first_xpath("mday").text.to_i,
26
+ xml.first_xpath("hours").text.to_i,
27
+ xml.first_xpath("minutes").text.to_i,
28
+ xml.first_xpath("seconds").text.to_i]
29
+ Time.local(year,month,day,hour,min,sec)
30
+ end
31
+ #<=
32
+ #:invisible:
33
+ require 'test/unit/assertions'
34
+ include Test::Unit::Assertions
35
+
36
+ t = Time.now
37
+ t2 = Time.load_from_xml(t.save_to_xml)
38
+
39
+ assert_equal t.year, t2.year
40
+ assert_equal t.month, t2.month
41
+ assert_equal t.day, t2.day
42
+ assert_equal t.hour, t2.hour
43
+ assert_equal t.min, t2.min
44
+ assert_equal t.sec, t2.sec
@@ -0,0 +1,12 @@
1
+
2
+ def Time.load_from_xml(xml, options={:mapping=>:_default})
3
+ year,month,day,hour,min,sec =
4
+ [xml.first_xpath("year").text.to_i,
5
+ xml.first_xpath("month").text.to_i,
6
+ xml.first_xpath("mday").text.to_i,
7
+ xml.first_xpath("hours").text.to_i,
8
+ xml.first_xpath("minutes").text.to_i,
9
+ xml.first_xpath("seconds").text.to_i]
10
+ Time.local(year,month,day,hour,min,sec)
11
+ end
12
+
@@ -0,0 +1,79 @@
1
+ #:invisible:
2
+ $:.unshift "../lib"
3
+ #<=
4
+ #:visible:
5
+ #:invisible_retval:
6
+ STDERR.puts "time_node top:\n#{$:.inspect}"
7
+
8
+ require 'xml/mapping/base'
9
+
10
+ STDERR.puts "time_node after require:\n#{$:.inspect}"
11
+
12
+ class TimeNode < XML::Mapping::SingleAttributeNode
13
+ def initialize(*args)
14
+ STDERR.puts "TimeNode#initialize top:\n#{$:.inspect}"
15
+ path,*args = super(*args)
16
+ @y_path = XML::XXPath.new(path+"/year")
17
+ @m_path = XML::XXPath.new(path+"/month")
18
+ @d_path = XML::XXPath.new(path+"/day")
19
+ args
20
+ end
21
+
22
+ def extract_attr_value(xml)
23
+ y,m,d = default_when_xpath_err{ [@y_path.first(xml).text.to_i,
24
+ @m_path.first(xml).text.to_i,
25
+ @d_path.first(xml).text.to_i]
26
+ }
27
+ Time.local(y,m,d)
28
+ end
29
+
30
+ def set_attr_value(xml, value)
31
+ @y_path.first(xml,:ensure_created=>true).text = value.year
32
+ @m_path.first(xml,:ensure_created=>true).text = value.month
33
+ @d_path.first(xml,:ensure_created=>true).text = value.day
34
+ end
35
+ end
36
+
37
+ XML::Mapping.add_node_class TimeNode
38
+
39
+ #<=
40
+ #:invisible:
41
+ require 'xml/mapping'
42
+
43
+ class Signature
44
+ include XML::Mapping
45
+
46
+ text_node :name, "Name"
47
+ text_node :position, "Position", :default_value=>"Some Employee"
48
+ time_node :signed_on, "signed-on", :default_value=>Time.now
49
+ end
50
+
51
+
52
+ require 'test/unit/assertions'
53
+ include Test::Unit::Assertions
54
+
55
+ xml = REXML::Document.new('
56
+ <Signature>
57
+ <Name>John Doe</Name>
58
+ <Position>product manager</Position>
59
+ <signed-on>
60
+ <day>13</day>
61
+ <month>2</month>
62
+ <year>2005</year>
63
+ </signed-on>
64
+ </Signature>
65
+ ').root
66
+
67
+
68
+ s = Signature.load_from_xml xml
69
+ assert_equal Time.local(2005,2,13), s.signed_on
70
+
71
+ s.signed_on = Time.local(2006,6,15)
72
+ xml2 = s.save_to_xml
73
+
74
+ require 'xml/xxpath_methods'
75
+ assert_equal "15", xml2.first_xpath("signed-on/day").text
76
+ assert_equal "6", xml2.first_xpath("signed-on/month").text
77
+ assert_equal "2006", xml2.first_xpath("signed-on/year").text
78
+
79
+ #<=
@@ -1,10 +1,12 @@
1
1
  require 'xml/mapping/base'
2
2
 
3
3
  class TimeNode < XML::Mapping::SingleAttributeNode
4
- def initialize_impl(path)
4
+ def initialize(*args)
5
+ path,*args = super(*args)
5
6
  @y_path = XML::XXPath.new(path+"/year")
6
7
  @m_path = XML::XXPath.new(path+"/month")
7
8
  @d_path = XML::XXPath.new(path+"/day")
9
+ args
8
10
  end
9
11
 
10
12
  def extract_attr_value(xml)
@@ -16,7 +18,6 @@ class TimeNode < XML::Mapping::SingleAttributeNode
16
18
  end
17
19
 
18
20
  def set_attr_value(xml, value)
19
- raise "Not a Time: #{value}" unless Time===value
20
21
  @y_path.first(xml,:ensure_created=>true).text = value.year
21
22
  @m_path.first(xml,:ensure_created=>true).text = value.month
22
23
  @d_path.first(xml,:ensure_created=>true).text = value.day
@@ -0,0 +1,48 @@
1
+ #:invisible:
2
+ #:invisible_retval:
3
+ $:.unshift "../lib" #<=
4
+ #:visible:
5
+ require 'xml/mapping'
6
+ require 'xml/xxpath_methods'
7
+
8
+ class Signature
9
+ include XML::Mapping
10
+
11
+ text_node :name, "Name"
12
+ text_node :position, "Position", :default_value=>"Some Employee"
13
+ object_node :signed_on, "signed-on",
14
+ :unmarshaller=>proc{|xml|
15
+ y,m,d = [xml.first_xpath("year").text.to_i,
16
+ xml.first_xpath("month").text.to_i,
17
+ xml.first_xpath("day").text.to_i]
18
+ Time.local(y,m,d)
19
+ },
20
+ :marshaller=>proc{|xml,value|
21
+ e = xml.elements.add; e.name = "year"; e.text = value.year
22
+ e = xml.elements.add; e.name = "month"; e.text = value.month
23
+ e = xml.elements.add; e.name = "day"; e.text = value.day
24
+
25
+ # xml.first("year",:ensure_created=>true).text = value.year
26
+ # xml.first("month",:ensure_created=>true).text = value.month
27
+ # xml.first("day",:ensure_created=>true).text = value.day
28
+ }
29
+ end #<=
30
+ #:invisible:
31
+ require 'test/unit/assertions'
32
+
33
+ include Test::Unit::Assertions
34
+
35
+ t=Time.local(2005,12,1)
36
+
37
+ s=Signature.new
38
+ s.name = "Olaf Klischat"; s.position="chief"; s.signed_on=t
39
+ xml = s.save_to_xml
40
+
41
+ assert_equal "2005", xml.first_xpath("signed-on/year").text
42
+ assert_equal "12", xml.first_xpath("signed-on/month").text
43
+ assert_equal "1", xml.first_xpath("signed-on/day").text
44
+
45
+ s2 = Signature.load_from_xml xml
46
+ assert_equal "Olaf Klischat", s2.name
47
+ assert_equal "chief", s2.position
48
+ assert_equal t, s2.signed_on
@@ -0,0 +1,25 @@
1
+ require 'xml/mapping'
2
+ require 'xml/xxpath_methods'
3
+
4
+ class Signature
5
+ include XML::Mapping
6
+
7
+ text_node :name, "Name"
8
+ text_node :position, "Position", :default_value=>"Some Employee"
9
+ object_node :signed_on, "signed-on",
10
+ :unmarshaller=>proc{|xml|
11
+ y,m,d = [xml.first_xpath("year").text.to_i,
12
+ xml.first_xpath("month").text.to_i,
13
+ xml.first_xpath("day").text.to_i]
14
+ Time.local(y,m,d)
15
+ },
16
+ :marshaller=>proc{|xml,value|
17
+ e = xml.elements.add; e.name = "year"; e.text = value.year
18
+ e = xml.elements.add; e.name = "month"; e.text = value.month
19
+ e = xml.elements.add; e.name = "day"; e.text = value.day
20
+
21
+ # xml.first("year",:ensure_created=>true).text = value.year
22
+ # xml.first("month",:ensure_created=>true).text = value.month
23
+ # xml.first("day",:ensure_created=>true).text = value.day
24
+ }
25
+ end
@@ -0,0 +1,9 @@
1
+ <Signature>
2
+ <Name>John Doe</Name>
3
+ <Position>product manager</Position>
4
+ <signed-on>
5
+ <day>13</day>
6
+ <month>2</month>
7
+ <year>2005</year>
8
+ </signed-on>
9
+ </Signature>
@@ -17,17 +17,20 @@ path1=XML::XXPath.new("/bar/baz[@key='work']")
17
17
  path1.create_new(rootelt)
18
18
  => <baz key='work'/>
19
19
  d.write($stdout,2)
20
- <foo>
21
- <bar>
22
- <baz key='work'>Java</baz>
23
- <baz key='play'>Ruby</baz>
24
- </bar>
20
+
21
+ <foo>
25
22
  <bar>
26
- <baz key='work'/>
27
- </bar>
28
- </foo>
29
-
30
- ### a new element is created for *each* path element, regardless of
23
+ <baz key='work'>
24
+ Java
25
+ </baz>
26
+ <baz key='play'>
27
+ Ruby
28
+ </baz>
29
+ </bar>
30
+ <bar>
31
+ <baz key='work'/>
32
+ </bar>
33
+ </foo>### a new element is created for *each* path element, regardless of
31
34
  ### what existed before. So a new "bar" element was added, with a new
32
35
  ### "baz" element inside it
33
36
 
@@ -35,20 +38,23 @@ d.write($stdout,2)
35
38
  path1.create_new(rootelt)
36
39
  => <baz key='work'/>
37
40
  d.write($stdout,2)
38
- <foo>
39
- <bar>
40
- <baz key='work'>Java</baz>
41
- <baz key='play'>Ruby</baz>
42
- </bar>
41
+
42
+ <foo>
43
43
  <bar>
44
- <baz key='work'/>
45
- </bar>
46
- <bar>
47
- <baz key='work'/>
48
- </bar>
49
- </foo>
50
-
51
- ### same procedure -- new elements added for each path element
44
+ <baz key='work'>
45
+ Java
46
+ </baz>
47
+ <baz key='play'>
48
+ Ruby
49
+ </baz>
50
+ </bar>
51
+ <bar>
52
+ <baz key='work'/>
53
+ </bar>
54
+ <bar>
55
+ <baz key='work'/>
56
+ </bar>
57
+ </foo>### same procedure -- new elements added for each path element
52
58
 
53
59
 
54
60
  ## get reference to 1st "baz" element
@@ -58,89 +64,98 @@ firstbazelt=XML::XXPath.new("/bar/baz").first(rootelt)
58
64
  path2=XML::XXPath.new("@key2")
59
65
 
60
66
  path2.create_new(firstbazelt)
61
- => #<XML::XXPath::Accessors::Attribute:0x314bf8 @parent=<baz key2='[unset]' key='work'> ... </>, @name="key2">
67
+ => #<XML::XXPath::Accessors::Attribute:0x7f48764e8688 @name="key2", @parent=<baz key='work' key2='[unset]'> ... </>>
62
68
  d.write($stdout,2)
63
- <foo>
64
- <bar>
65
- <baz key2='[unset]' key='work'>Java</baz>
66
- <baz key='play'>Ruby</baz>
67
- </bar>
69
+
70
+ <foo>
68
71
  <bar>
69
- <baz key='work'/>
70
- </bar>
71
- <bar>
72
- <baz key='work'/>
73
- </bar>
74
- </foo>
75
-
76
- ### ok, new attribute node added
72
+ <baz key='work' key2='[unset]'>
73
+ Java
74
+ </baz>
75
+ <baz key='play'>
76
+ Ruby
77
+ </baz>
78
+ </bar>
79
+ <bar>
80
+ <baz key='work'/>
81
+ </bar>
82
+ <bar>
83
+ <baz key='work'/>
84
+ </bar>
85
+ </foo>### ok, new attribute node added
77
86
 
78
87
  ### same call again...
79
88
  path2.create_new(firstbazelt)
80
- XML::XXPathError: XPath (): @key2: create_new and attribute already exists
81
- from ../lib/xml/../xml/xxpath.rb:341:in `create_subnode_by_attr_name'
82
- from ../lib/xml/../xml/xxpath.rb:68:in `initialize'
83
- from ../lib/xml/../xml/xxpath.rb:67:in `call'
84
- from ../lib/xml/../xml/xxpath.rb:146:in `all'
85
- from ../lib/xml/../xml/xxpath.rb:125:in `first'
86
- from ../lib/xml/../xml/xxpath.rb:167:in `create_new'
89
+ XML::XXPathError: XPath (@key2): create_new and attribute already exists
90
+ from ../lib/xml/../xml/xxpath/steps.rb:215:in `create_on'
91
+ from ../lib/xml/../xml/xxpath/steps.rb:80:in `creator'
92
+ from ../lib/xml/xxpath.rb:91:in `call'
93
+ from ../lib/xml/xxpath.rb:91:in `all'
94
+ from ../lib/xml/xxpath.rb:70:in `first'
95
+ from ../lib/xml/xxpath.rb:112:in `create_new'
87
96
  ### can't create that path anew again -- an element can't have more
88
97
  ### than one attribute with the same name
89
98
 
90
99
  ### the document hasn't changed
91
100
  d.write($stdout,2)
92
- <foo>
93
- <bar>
94
- <baz key2='[unset]' key='work'>Java</baz>
95
- <baz key='play'>Ruby</baz>
96
- </bar>
101
+
102
+ <foo>
97
103
  <bar>
98
- <baz key='work'/>
99
- </bar>
100
- <bar>
101
- <baz key='work'/>
102
- </bar>
103
- </foo>
104
-
105
-
104
+ <baz key='work' key2='[unset]'>
105
+ Java
106
+ </baz>
107
+ <baz key='play'>
108
+ Ruby
109
+ </baz>
110
+ </bar>
111
+ <bar>
112
+ <baz key='work'/>
113
+ </bar>
114
+ <bar>
115
+ <baz key='work'/>
116
+ </bar>
117
+ </foo>
106
118
 
107
119
 
108
120
  ### create_new the same path as in the ensure_created example
109
121
  baz6elt=XML::XXPath.new("/bar/baz[6]").create_new(rootelt)
110
122
  => <baz/>
111
123
  d.write($stdout,2)
112
- <foo>
113
- <bar>
114
- <baz key2='[unset]' key='work'>Java</baz>
115
- <baz key='play'>Ruby</baz>
116
- </bar>
124
+
125
+ <foo>
117
126
  <bar>
118
- <baz key='work'/>
119
- </bar>
120
- <bar>
121
- <baz key='work'/>
122
- </bar>
123
- <bar>
124
- <baz/>
125
- <baz/>
126
- <baz/>
127
- <baz/>
128
- <baz/>
129
- <baz/>
130
- </bar>
131
- </foo>
132
-
133
- ### ok, new "bar" element and 6th "baz" element inside it created
127
+ <baz key='work' key2='[unset]'>
128
+ Java
129
+ </baz>
130
+ <baz key='play'>
131
+ Ruby
132
+ </baz>
133
+ </bar>
134
+ <bar>
135
+ <baz key='work'/>
136
+ </bar>
137
+ <bar>
138
+ <baz key='work'/>
139
+ </bar>
140
+ <bar>
141
+ <baz/>
142
+ <baz/>
143
+ <baz/>
144
+ <baz/>
145
+ <baz/>
146
+ <baz/>
147
+ </bar>
148
+ </foo>### ok, new "bar" element and 6th "baz" element inside it created
134
149
 
135
150
 
136
151
  XML::XXPath.new("baz[6]").create_new(baz6elt.parent)
137
- XML::XXPathError: XPath (): baz[6]: create_new and element already exists
138
- from ../lib/xml/../xml/xxpath.rb:330:in `create_subnode_by_name_and_index'
139
- from ../lib/xml/../xml/xxpath.rb:52:in `initialize'
140
- from ../lib/xml/../xml/xxpath.rb:51:in `call'
141
- from ../lib/xml/../xml/xxpath.rb:146:in `all'
142
- from ../lib/xml/../xml/xxpath.rb:125:in `first'
143
- from ../lib/xml/../xml/xxpath.rb:167:in `create_new'
152
+ XML::XXPathError: XPath: baz[6]: create_new and element already exists
153
+ from ../lib/xml/../xml/xxpath/steps.rb:167:in `create_on'
154
+ from ../lib/xml/../xml/xxpath/steps.rb:80:in `creator'
155
+ from ../lib/xml/xxpath.rb:91:in `call'
156
+ from ../lib/xml/xxpath.rb:91:in `all'
157
+ from ../lib/xml/xxpath.rb:70:in `first'
158
+ from ../lib/xml/xxpath.rb:112:in `create_new'
144
159
  ### yep, baz[6] already existed and thus couldn't be created once
145
160
  ### again
146
161
 
@@ -148,34 +163,37 @@ XML::XXPathError: XPath (): baz[6]: create_new and element already exists
148
163
  XML::XXPath.new("/bar/baz[6]").create_new(rootelt)
149
164
  => <baz/>
150
165
  d.write($stdout,2)
151
- <foo>
152
- <bar>
153
- <baz key2='[unset]' key='work'>Java</baz>
154
- <baz key='play'>Ruby</baz>
155
- </bar>
166
+
167
+ <foo>
168
+ <bar>
169
+ <baz key='work' key2='[unset]'>
170
+ Java
171
+ </baz>
172
+ <baz key='play'>
173
+ Ruby
174
+ </baz>
175
+ </bar>
176
+ <bar>
177
+ <baz key='work'/>
178
+ </bar>
179
+ <bar>
180
+ <baz key='work'/>
181
+ </bar>
182
+ <bar>
183
+ <baz/>
184
+ <baz/>
185
+ <baz/>
186
+ <baz/>
187
+ <baz/>
188
+ <baz/>
189
+ </bar>
156
190
  <bar>
157
- <baz key='work'/>
158
- </bar>
159
- <bar>
160
- <baz key='work'/>
161
- </bar>
162
- <bar>
163
- <baz/>
164
- <baz/>
165
- <baz/>
166
- <baz/>
167
- <baz/>
168
- <baz/>
169
- </bar>
170
- <bar>
171
- <baz/>
172
- <baz/>
173
- <baz/>
174
- <baz/>
175
- <baz/>
176
- <baz/>
177
- </bar>
178
- </foo>
179
-
180
- ### this works because *all* path elements are newly created
191
+ <baz/>
192
+ <baz/>
193
+ <baz/>
194
+ <baz/>
195
+ <baz/>
196
+ <baz/>
197
+ </bar>
198
+ </foo>### this works because *all* path elements are newly created
181
199