rubyang 0.1.0

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