rubyang 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +27 -0
- data/.coveralls.yml +1 -0
- data/.eslintignore +1 -0
- data/.eslintrc +213 -0
- data/.gitignore +41 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/lib/rubyang.rb +10 -0
- data/lib/rubyang/cli.rb +120 -0
- data/lib/rubyang/cli/parser.rb +74 -0
- data/lib/rubyang/database.rb +29 -0
- data/lib/rubyang/database/data_tree.rb +725 -0
- data/lib/rubyang/database/helper.rb +44 -0
- data/lib/rubyang/database/schema_tree.rb +1060 -0
- data/lib/rubyang/model.rb +917 -0
- data/lib/rubyang/model/parser.rb +183 -0
- data/lib/rubyang/model/parser/parser.tab.rb +3661 -0
- data/lib/rubyang/model/parser/parser.y +1454 -0
- data/lib/rubyang/restapi.rb +4 -0
- data/lib/rubyang/restapi/httpd.rb +62 -0
- data/lib/rubyang/version.rb +3 -0
- data/lib/rubyang/webui.rb +11 -0
- data/lib/rubyang/webui/app.rb +74 -0
- data/lib/rubyang/webui/make_json_schema.rb +63 -0
- data/lib/rubyang/webui/public/js/webui.js +326 -0
- data/lib/rubyang/webui/views/index.erb +48 -0
- data/lib/rubyang/webui/views/layout.erb +82 -0
- data/lib/rubyang/xpath.rb +224 -0
- data/lib/rubyang/xpath/parser.rb +146 -0
- data/lib/rubyang/xpath/parser/parser.tab.rb +2273 -0
- data/lib/rubyang/xpath/parser/parser.y +1083 -0
- data/rubyang.gemspec +38 -0
- metadata +180 -0
@@ -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
|
+
|