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