rubyang 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ # coding: utf-8
2
+
3
+ require 'strscan'
4
+
5
+ #require_relative 'parser/parser.tab.rb'
6
+
7
+ module Rubyang
8
+ module Cli
9
+ class Parser
10
+ def self.parse( str )
11
+ parser = self.new
12
+ parser.parse( str )
13
+ end
14
+
15
+ def initialize
16
+ end
17
+
18
+ def parse( str )
19
+ @tokens = Array.new
20
+
21
+ s = StringScanner.new( str )
22
+
23
+ keywords = {
24
+ }
25
+
26
+ scanre_list = [
27
+ ["dqstr", /^"(?:[^"]|\\.)*"/],
28
+ ["sqstr", /^'(?:[^']|\\.)*'/],
29
+ ["nqstr", /^[a-zA-Z0-9:\/\|\.=_-]+/],
30
+ ["wsp", /^[ \t]+/],
31
+ ]
32
+ scanres = scanre_list.to_h
33
+
34
+ scanre = Regexp.union( scanre_list.map{ |scanre| scanre[1] } )
35
+
36
+ last = ''
37
+ until s.eos?
38
+ token = s.scan( scanre )
39
+ case token
40
+ when scanres["dqstr"] then
41
+ token_ = token.gsub(/^"/,'').gsub(/"$/,'').gsub(/\\n/,"\n").gsub(/\\t/,"\t").gsub(/\\"/,"\"").gsub(/\\\\/,"\\")
42
+ @tokens.push token_
43
+ last = "dqstr"
44
+ when scanres["sqstr"] then
45
+ token_ = token.gsub(/^'/,'').gsub(/'$/,'')
46
+ @tokens.push token_
47
+ last = "sqstr"
48
+ when scanres["nqstr"] then
49
+ @tokens.push token
50
+ last = "nqstr"
51
+ when scanres["wsp"] then
52
+ last = "wsp"
53
+ else raise "token not match to any scanres: #{token.inspect}"
54
+ end
55
+ end
56
+ if last == "wsp"
57
+ @tokens.push ''
58
+ end
59
+
60
+ #result = self.do_parse
61
+ return @tokens
62
+ end
63
+
64
+ def next_token
65
+ #p @tokens.first
66
+ @tokens.shift
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ if __FILE__ == $0
73
+ p Rubyang::Cli::Parser.parse "set aaa "
74
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'model'
4
+ require_relative 'xpath'
5
+
6
+ require_relative 'database/schema_tree'
7
+ require_relative 'database/data_tree'
8
+
9
+ module Rubyang
10
+ class Database
11
+ def initialize
12
+ @yangs = Array.new
13
+ @schema_tree = SchemaTree.new @yangs
14
+ @data_tree = DataTree.new @schema_tree
15
+ end
16
+
17
+ def load_model model
18
+ @schema_tree.load model
19
+ end
20
+
21
+ def configure
22
+ @data_tree.root
23
+ end
24
+
25
+ def configuration
26
+ @data_tree.root
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,725 @@
1
+ # coding: utf-8
2
+
3
+ require 'rexml/document'
4
+ require 'rexml/formatters/pretty'
5
+ require 'json'
6
+
7
+ require_relative 'helper'
8
+
9
+ module Rubyang
10
+ class Database
11
+ class DataTree
12
+ class Node
13
+ attr_reader :parent, :schema_tree, :schema, :children
14
+ def initialize parent, schema_tree, schema
15
+ @parent = parent
16
+ @schema_tree = schema_tree
17
+ @schema = schema
18
+ @children = []
19
+ end
20
+ def load_merge_xml_recursive doc_xml
21
+ doc_xml.each_element{ |e|
22
+ child = edit( e.name )
23
+ unless e.has_elements?
24
+ if e.has_text?
25
+ child.set e.text
26
+ end
27
+ end
28
+ child.load_merge_xml_recursive e
29
+ }
30
+ end
31
+ def root
32
+ case @parent
33
+ when Rubyang::Database::DataTree::Root
34
+ @parent
35
+ else
36
+ @parent.root
37
+ end
38
+ end
39
+ def evaluate_xpath location_steps, current=self
40
+ location_step = location_steps.first
41
+ candidates_by_axis = self.evaluate_xpath_axis( location_step, current )
42
+ candidates_by_node_test = candidates_by_axis.inject([]){ |cs, c| cs + c.evaluate_xpath_node_test( location_step, current ) }
43
+ candidates_by_predicates = candidates_by_node_test.inject([]){ |cs, c| cs + c.evaluate_xpath_predicates( location_step, current ) }
44
+ if location_steps[1..-1].size == 0
45
+ candidates_by_predicates
46
+ else
47
+ candidates_by_predicates.inject([]){ |cs, c| c.evaluate_xpath( location_steps[1..-1], current ) }
48
+ end
49
+ end
50
+ def evaluate_xpath_axis location_step, current
51
+ case location_step.axis.name
52
+ when Rubyang::Xpath::Axis::SELF
53
+ [self]
54
+ when Rubyang::Xpath::Axis::PARENT
55
+ [@parent]
56
+ when Rubyang::Xpath::Axis::CHILD
57
+ @children.inject([]){ |cs, c|
58
+ cs + case c
59
+ when Rubyang::Database::DataTree::ListElement
60
+ c.children
61
+ else
62
+ [c]
63
+ end
64
+ }
65
+ else
66
+ raise "location_step.axis.name: #{location_step.axis.name} NOT implemented"
67
+ end
68
+ end
69
+ def evaluate_xpath_node_test location_step, current
70
+ case location_step.node_test.node_test_type
71
+ when Rubyang::Xpath::NodeTest::NodeTestType::NAME_TEST
72
+ if "/" == location_step.node_test.node_test
73
+ [self.root]
74
+ elsif self.schema.model.arg == location_step.node_test.node_test
75
+ [self]
76
+ else
77
+ []
78
+ end
79
+ when Rubyang::Xpath::NodeTest::NodeTestType::NODE_TYPE
80
+ case location_step.node_test.node_test
81
+ when Rubyang::Xpath::NodeTest::NodeType::COMMENT
82
+ raise "node-type: comment is not implemented"
83
+ when Rubyang::Xpath::NodeTest::NodeType::TEXT
84
+ raise "node-type: text is not implemented"
85
+ when Rubyang::Xpath::NodeTest::NodeType::NODE
86
+ [self]
87
+ else
88
+ raise "node-type not match to comment or text or node"
89
+ end
90
+ when Rubyang::Xpath::NodeTest::NodeTestType::PROCESSING_INSTRUCTION
91
+ raise "processing-instruction is not implemented"
92
+ else
93
+ raise ""
94
+ end
95
+ end
96
+ def evaluate_xpath_predicates location_step, current
97
+ case location_step.predicates.size
98
+ when 0
99
+ [self]
100
+ else
101
+ location_step.predicates.inject([]){ |cs, predicate|
102
+ self.evaluate_xpath_predicate_expr predicate.expr, current
103
+ }
104
+ end
105
+ end
106
+ def evaluate_xpath_predicate_expr expr, current
107
+ case expr
108
+ when Rubyang::Xpath::Predicate::OrExpr
109
+ if Rubyang::Xpath::Parser::DEBUG
110
+ puts
111
+ puts "in OrExpr"
112
+ puts "op1: #{expr.op1}"
113
+ puts "op2: #{expr.op2}"
114
+ puts
115
+ end
116
+ op1 = expr.op1
117
+ op2 = expr.op2
118
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
119
+ if op2 == nil
120
+ op1_result
121
+ else
122
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
123
+ op1_result | op2_result
124
+ end
125
+ when Rubyang::Xpath::Predicate::AndExpr
126
+ if Rubyang::Xpath::Parser::DEBUG
127
+ puts
128
+ puts "in AndExpr"
129
+ puts "op1: #{expr.op1}"
130
+ puts "op2: #{expr.op2}"
131
+ puts
132
+ end
133
+ op1 = expr.op1
134
+ op2 = expr.op2
135
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
136
+ if op2 == nil
137
+ op1_result
138
+ else
139
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
140
+ op1_result & op2_result
141
+ end
142
+ when Rubyang::Xpath::Predicate::EqualityExpr
143
+ if Rubyang::Xpath::Parser::DEBUG
144
+ puts
145
+ puts "in EqualityExpr"
146
+ puts "op1: #{expr.op1}"
147
+ puts "op2: #{expr.op2}"
148
+ puts "operator: #{expr.operator}"
149
+ puts
150
+ end
151
+ op1 = expr.op1
152
+ op2 = expr.op2
153
+ operator = expr.operator
154
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
155
+ if op2 == nil
156
+ op1_result
157
+ else
158
+ case operator
159
+ when /^\=$/
160
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
161
+ op1_result.select{ |a| op2_result.map{ |b| b.value }.include? a.value }.map{ |c| c.parent }
162
+ when /^\!\=$/
163
+ raise "Equality Expr: '!=' not implemented"
164
+ else
165
+ raise "Equality Expr: other than '=' and '!=' not implemented"
166
+ end
167
+ end
168
+ when Rubyang::Xpath::Predicate::RelationalExpr
169
+ if Rubyang::Xpath::Parser::DEBUG
170
+ puts
171
+ puts "in RelationalExpr"
172
+ puts "op1: #{expr.op1}"
173
+ puts "op2: #{expr.op2}"
174
+ puts "operator: #{expr.operator}"
175
+ puts
176
+ end
177
+ op1 = expr.op1
178
+ op2 = expr.op2
179
+ operator = expr.operator
180
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
181
+ if op2 == nil
182
+ op1_result
183
+ else
184
+ case operator
185
+ when /^\>$/
186
+ raise "Relational Expr: '>' not implemented"
187
+ when /^\<$/
188
+ raise "Relational Expr: '<' not implemented"
189
+ when /^\>\=$/
190
+ raise "Relational Expr: '>=' not implemented"
191
+ when /^\<\=$/
192
+ raise "Relational Expr: '<=' not implemented"
193
+ else
194
+ raise "Relational Expr: other than '>', '<', '>=' and '<=' not implemented"
195
+ end
196
+ end
197
+ when Rubyang::Xpath::Predicate::AdditiveExpr
198
+ if Rubyang::Xpath::Parser::DEBUG
199
+ puts
200
+ puts "in AdditiveExpr"
201
+ puts "op1: #{expr.op1}"
202
+ puts "op2: #{expr.op2}"
203
+ puts "operator: #{expr.operator}"
204
+ puts
205
+ end
206
+ op1 = expr.op1
207
+ op2 = expr.op2
208
+ operator = expr.operator
209
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
210
+ if op2 == nil
211
+ op1_result
212
+ else
213
+ case operator
214
+ when /^\+$/
215
+ raise "Additive Expr: '+' not implemented"
216
+ when /^\-$/
217
+ raise "Additive Expr: '-' not implemented"
218
+ else
219
+ raise "Additive Expr: other than '+' and '-' not implemented"
220
+ end
221
+ end
222
+ when Rubyang::Xpath::Predicate::MultiplicativeExpr
223
+ if Rubyang::Xpath::Parser::DEBUG
224
+ puts
225
+ puts "in MultiplicativeExpr"
226
+ puts "op1: #{expr.op1}"
227
+ puts "op2: #{expr.op2}"
228
+ puts "operator: #{expr.operator}"
229
+ puts
230
+ end
231
+ op1 = expr.op1
232
+ op2 = expr.op2
233
+ operator = expr.operator
234
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
235
+ if op2 == nil
236
+ op1_result
237
+ else
238
+ case operator
239
+ when /^\*$/
240
+ raise "Multiplicative Expr: '*' not implemented"
241
+ when /^\/$/
242
+ raise "Multiplicative Expr: '/' not implemented"
243
+ else
244
+ raise "Multiplicative Expr: other than '*' and '/' not implemented"
245
+ end
246
+ end
247
+ when Rubyang::Xpath::Predicate::UnaryExpr
248
+ if Rubyang::Xpath::Parser::DEBUG
249
+ puts
250
+ puts "in UnaryExpr"
251
+ puts "op1: #{expr.op1}"
252
+ puts "operator: #{expr.operator}"
253
+ puts
254
+ end
255
+ op1 = expr.op1
256
+ operator = expr.operator
257
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
258
+ case operator
259
+ when nil
260
+ op1_result
261
+ when /^\-$/
262
+ raise "Unary Expr: '-' not implemented"
263
+ else
264
+ raise "Unary Expr: other than '-' not implemented"
265
+ end
266
+ when Rubyang::Xpath::Predicate::UnionExpr
267
+ if Rubyang::Xpath::Parser::DEBUG
268
+ puts
269
+ puts "in UnionExpr"
270
+ puts "op1: #{expr.op1}"
271
+ puts "op2: #{expr.op2}"
272
+ puts "operator: #{expr.operator}"
273
+ puts
274
+ end
275
+ op1 = expr.op1
276
+ op2 = expr.op2
277
+ operator = expr.operator
278
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
279
+ if op2 == nil
280
+ op1_result
281
+ else
282
+ case operator
283
+ when /^\|$/
284
+ raise "Union Expr: '|' not implemented"
285
+ else
286
+ raise "Union Expr: other than '|' not implemented"
287
+ end
288
+ end
289
+ when Rubyang::Xpath::Predicate::PathExpr
290
+ if Rubyang::Xpath::Parser::DEBUG
291
+ puts
292
+ puts "in PathExpr"
293
+ puts "op1: #{expr.op1}"
294
+ puts "op2: #{expr.op2}"
295
+ puts "operator: #{expr.operator}"
296
+ puts
297
+ end
298
+ op1 = expr.op1
299
+ op2 = expr.op2
300
+ operator = expr.operator
301
+ case op1
302
+ when Rubyang::Xpath::LocationSteps
303
+ op1_result = self.evaluate_xpath( op1, current )
304
+ when Rubyang::Xpath::Predicate::FilterExpr
305
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
306
+ if op2 == nil
307
+ op1_result
308
+ else
309
+ case operator
310
+ when /^\/$/
311
+ case op2
312
+ when Rubyang::Xpath::LocationSteps
313
+ current.evaluate_xpath (op1_result + op2), current
314
+ else
315
+ raise "Path Expr: op1 is not LocationSteps"
316
+ end
317
+ when /^\/\/$/
318
+ raise "Path Expr: '//' not implemented"
319
+ else
320
+ raise "Path Expr: other than '/' and '//' not implemented"
321
+ end
322
+ end
323
+ else
324
+ raise ""
325
+ end
326
+ when Rubyang::Xpath::Predicate::FilterExpr
327
+ if Rubyang::Xpath::Parser::DEBUG
328
+ puts
329
+ puts "in FilterExpr"
330
+ puts "op1: #{expr.op1}"
331
+ puts "op2: #{expr.op2}"
332
+ puts
333
+ end
334
+ op1 = expr.op1
335
+ op2 = expr.op2
336
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
337
+ if op2 == nil
338
+ op1_result
339
+ else
340
+ op2_result = self.evaluate_xpath_predicate_expr( op2.expr, current )
341
+ raise "Filter Expr: Filter Predicate not implemented"
342
+ end
343
+ when Rubyang::Xpath::Predicate::PrimaryExpr
344
+ if Rubyang::Xpath::Parser::DEBUG
345
+ puts
346
+ puts "in PrimaryExpr"
347
+ puts "op1: #{expr.op1}"
348
+ puts
349
+ end
350
+ op1 = expr.op1
351
+ case op1
352
+ when Rubyang::Xpath::Predicate::Expr
353
+ raise "Primary Expr: '( Expr )' not implemented"
354
+ when Rubyang::Xpath::Predicate::FunctionCall
355
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
356
+ when /^\$.*$/
357
+ raise "Primary Expr: 'Variable Reference' not implemented"
358
+ else
359
+ raise "Primary Expr: 'Literal' and 'Number' not implemented"
360
+ end
361
+ when Rubyang::Xpath::Predicate::FunctionCall
362
+ if Rubyang::Xpath::Parser::DEBUG
363
+ puts
364
+ puts "in FunctionCall"
365
+ puts "name: #{expr.name}"
366
+ puts "args: #{expr.args}"
367
+ puts
368
+ end
369
+ name = expr.name
370
+ case name
371
+ when Rubyang::Xpath::Predicate::FunctionCall::CURRENT
372
+ Rubyang::Xpath::LocationSteps.new
373
+ else
374
+ raise "FunctionCall: #{name} not implemented"
375
+ end
376
+ else
377
+ raise "Unrecognized predicate: #{predicate}"
378
+ end
379
+ end
380
+ end
381
+
382
+ class InteriorNode < Node
383
+ def to_xml pretty: false
384
+ doc = REXML::Document.new
385
+ self.to_xml_recursive doc
386
+ if pretty
387
+ pretty_formatter = REXML::Formatters::Pretty.new( 2 )
388
+ pretty_formatter.compact = true
389
+ output = ''
390
+ pretty_formatter.write( doc, output )
391
+ output
392
+ else
393
+ doc.to_s
394
+ end
395
+ end
396
+ def to_json pretty: false
397
+ hash = Hash.new
398
+ self.to_json_recursive hash
399
+ if pretty
400
+ JSON.pretty_generate( hash )
401
+ else
402
+ JSON.generate( hash )
403
+ end
404
+ end
405
+ def to_xml_recursive _doc, current_namespace=''
406
+ doc = _doc.add_element( @schema.model.arg )
407
+ unless @schema.namespace == current_namespace
408
+ current_namespace = @schema.namespace
409
+ doc.add_namespace current_namespace
410
+ end
411
+ @children.each{ |c|
412
+ c.to_xml_recursive doc, current_namespace
413
+ }
414
+ end
415
+ def to_json_recursive( _hash )
416
+ hash = Hash.new
417
+ _hash[@schema.model.arg] = hash
418
+ @children.each{ |c|
419
+ c.to_json_recursive hash
420
+ }
421
+ end
422
+ def find_child_schema schema, arg
423
+ schema.children.map{ |c|
424
+ case c
425
+ when Rubyang::Database::SchemaTree::Choice
426
+ find_child_schema c, arg
427
+ when Rubyang::Database::SchemaTree::Case
428
+ find_child_schema c, arg
429
+ else
430
+ if c.model.arg == arg
431
+ c
432
+ else
433
+ nil
434
+ end
435
+ end
436
+ }.find{ |c| c }
437
+ end
438
+ def delete_same_choice_other_case schema, arg, children
439
+ child_schema = nil
440
+ schema.children.each{ |c|
441
+ case c
442
+ when Rubyang::Database::SchemaTree::Choice
443
+ child_schema = delete_same_choice_other_case c, arg, children
444
+ when Rubyang::Database::SchemaTree::Case
445
+ child_schema = delete_same_choice_other_case c, arg, children
446
+ if Rubyang::Database::SchemaTree::Choice === schema
447
+ other_schema_children = schema.children.select{ |c2| c2 != c }
448
+ children.delete_if{ |c2|
449
+ other_schema_children.find{ |sc|
450
+ find_child_schema sc, c2.schema.model.arg or sc.model.arg == c2.schema.model.arg
451
+ }
452
+ }
453
+ end
454
+ else
455
+ if c.model.arg == arg
456
+ child_schema = c
457
+ if Rubyang::Database::SchemaTree::Choice === schema
458
+ other_schema_children = schema.children.select{ |c2| c2 != c }
459
+ children.delete_if{ |c2|
460
+ other_schema_children.find{ |sc|
461
+ find_child_schema sc, c2.schema.model.arg or sc.model.arg == c2.schema.model.arg
462
+ }
463
+ }
464
+ end
465
+ else
466
+ nil
467
+ end
468
+ end
469
+ }
470
+ child_schema
471
+ end
472
+ def edit arg
473
+ child_schema = find_child_schema @schema, arg
474
+ delete_same_choice_other_case @schema, arg, @children
475
+ child_node = @children.find{ |c| c.schema == child_schema }
476
+ unless child_node
477
+ case child_schema.model
478
+ when Rubyang::Model::Container
479
+ child_node = Container.new( self, @schema_tree, child_schema )
480
+ when Rubyang::Model::Leaf
481
+ child_node = Leaf.new( self, @schema_tree, child_schema )
482
+ when Rubyang::Model::List
483
+ child_node = List.new( self, @schema_tree, child_schema )
484
+ when Rubyang::Model::LeafList
485
+ child_node = LeafList.new( self, @schema_tree, child_schema )
486
+ else
487
+ raise ArgumentError, "#{arg} NOT match"
488
+ end
489
+ @children.push child_node
490
+ end
491
+ child_node
492
+ end
493
+ def edit_xpath arg
494
+ xpath = Rubyang::Xpath::Parser.parse arg
495
+ elements = self.evaluate_xpath( xpath )
496
+ case elements.size
497
+ when 0
498
+ raise "no such xpath: #{arg}"
499
+ when 1
500
+ elements.first
501
+ else
502
+ raise "too many match to xpath: #{arg}"
503
+ end
504
+ end
505
+ end
506
+
507
+ class LeafNode < Node
508
+ end
509
+
510
+ class ListNode < Node
511
+ end
512
+
513
+ class Root < InteriorNode
514
+ def commit
515
+ backup = self.to_xml
516
+ @parent.history.push backup
517
+ end
518
+ def revert
519
+ backup = @parent.history.pop
520
+ if backup
521
+ self.load_override_xml backup
522
+ else
523
+ self.load_override_xml self.new.to_xml
524
+ end
525
+ end
526
+ def to_xml_recursive _doc, current_namespace=''
527
+ doc = _doc.add_element( 'config' )
528
+ current_namespace = @schema_tree.root.namespace
529
+ doc.add_namespace( current_namespace )
530
+ @children.each{ |c|
531
+ c.to_xml_recursive doc, current_namespace
532
+ }
533
+ end
534
+ def to_json_recursive _hash
535
+ hash = Hash.new
536
+ _hash['config'] = hash
537
+ @children.each{ |c|
538
+ c.to_json_recursive hash
539
+ }
540
+ end
541
+ def load_xml xml_str
542
+ doc_xml = REXML::Document.new( xml_str ).root
543
+ self.load_merge_xml_recursive doc_xml
544
+ end
545
+ def load_merge_xml xml_str
546
+ self.load_xml xml_str
547
+ end
548
+ def load_override_xml xml_str
549
+ @children.clear
550
+ self.load_xml xml_str
551
+ end
552
+ def load_merge_json json_str
553
+ xml_str = json_to_xml( json_str )
554
+ self.load_merge_xml xml_str
555
+ end
556
+ def load_override_json json_str
557
+ xml_str = json_to_xml( json_str )
558
+ self.load_override_xml xml_str
559
+ end
560
+ end
561
+
562
+ class Container < InteriorNode
563
+ end
564
+
565
+ class Leaf < LeafNode
566
+ attr_accessor :value
567
+ def set arg
568
+ case @schema.type
569
+ when SchemaTree::LeafrefType
570
+ elements = self.evaluate_xpath( @schema.type.path )
571
+ values = elements.inject([]){ |vs, v| vs + [v.value] }
572
+ unless values.include? arg
573
+ raise ArgumentError, "#{arg} is not valid for #{@schema.type.inspect}"
574
+ end
575
+ else
576
+ unless @schema.type.valid? arg
577
+ raise ArgumentError, "#{arg} is not valid for #{@schema.type.inspect}"
578
+ end
579
+ end
580
+ self.value = arg
581
+ end
582
+ def has_value?
583
+ if @value
584
+ true
585
+ else
586
+ false
587
+ end
588
+ end
589
+ def to_xml_recursive _doc, current_namespace
590
+ doc = _doc.add_element( @schema.model.arg )
591
+ unless @schema.namespace == current_namespace
592
+ current_namespace = @schema.namespace
593
+ doc.add_namespace current_namespace
594
+ end
595
+ doc.add_text( @value )
596
+ end
597
+ def to_json_recursive _hash
598
+ hash = _hash
599
+ hash[@schema.model.arg] = @value
600
+ end
601
+ end
602
+
603
+ class List < ListNode
604
+ def edit *args
605
+ child_node = @children.find{ |c| c.key_values == args }
606
+ unless child_node
607
+ begin
608
+ child_node = ListElement.new( self, @schema_tree, @schema, args )
609
+ rescue
610
+ raise ArgumentError, "#{args} NOT match"
611
+ end
612
+ @children.push child_node
613
+ end
614
+ child_node
615
+ end
616
+ def to_xml_recursive _doc, current_namespace
617
+ doc = _doc
618
+ @children.each{ |c|
619
+ c.to_xml_recursive doc, current_namespace
620
+ }
621
+ end
622
+ def to_json_recursive _hash
623
+ array = Array.new
624
+ _hash[@schema.model.arg] = array
625
+ @children.each{ |c|
626
+ c.to_json_recursive array
627
+ }
628
+ end
629
+ def load_merge_xml_recursive doc_xml
630
+ return if doc_xml.elements.size == 0
631
+ key_args = @schema.keys.map{ |k| doc_xml.elements[k].text }
632
+ child = edit( *key_args )
633
+ elements = REXML::Document.new('<tmp />')
634
+ doc_xml.each_element{ |e|
635
+ next if @schema.keys.include? e.name
636
+ elements.root.add_element e
637
+ }
638
+ child.load_merge_xml_recursive elements.root
639
+ end
640
+ end
641
+
642
+ class ListElement < InteriorNode
643
+ def initialize parent, schema_tree, schema, key_values
644
+ @parent = parent
645
+ @schema_tree = schema_tree
646
+ @schema = schema
647
+ @children = []
648
+ @key_values = key_values
649
+ @schema.keys.zip( key_values ).each{ |key, value|
650
+ self.edit( key, true ).set( value )
651
+ }
652
+ end
653
+ def key_values
654
+ @key_values
655
+ end
656
+ def edit arg, in_initialize=false
657
+ unless in_initialize
658
+ if @schema.model.substmt( 'key' ).find{ |s| s.arg == arg }
659
+ raise "#{arg} is key"
660
+ end
661
+ end
662
+ super arg
663
+ end
664
+ def to_json_recursive _array
665
+ hash = Hash.new
666
+ _array.push hash
667
+ @children.each{ |c|
668
+ c.to_json_recursive hash
669
+ }
670
+ end
671
+ end
672
+
673
+ class LeafList < InteriorNode
674
+ def set arg
675
+ child_node = @children.find{ |c| c.value == arg }
676
+ unless child_node
677
+ begin
678
+ child_node = LeafListElement.new( self, @schema_tree, @schema, arg )
679
+ rescue
680
+ raise ArgumentError
681
+ end
682
+ @children.push child_node
683
+ end
684
+ child_node
685
+ end
686
+ def to_xml_recursive _doc, current_namespace
687
+ doc = _doc
688
+ @children.each{ |c|
689
+ c.to_xml_recursive doc, current_namespace
690
+ }
691
+ end
692
+ end
693
+
694
+ class LeafListElement < LeafNode
695
+ attr_accessor :value
696
+ def initialize parent, schema_tree, schema, value
697
+ @parent = parent
698
+ @schema_tree = schema_tree
699
+ @schema = schema
700
+ @value = value
701
+ end
702
+ def to_xml_recursive _doc, current_namespace
703
+ doc = _doc.add_element( @schema.model.arg )
704
+ unless @schema.namespace == current_namespace
705
+ current_namespace = @schema.namespace
706
+ doc.add_namespace current_namespace
707
+ end
708
+ doc.add_text( @value )
709
+ end
710
+ end
711
+
712
+ def initialize schema_tree
713
+ @root = Root.new( self, schema_tree, schema_tree.root )
714
+ @history = Array.new
715
+ end
716
+ def history
717
+ @history
718
+ end
719
+ def root
720
+ @root
721
+ end
722
+ end
723
+ end
724
+ end
725
+