-
Notifications
You must be signed in to change notification settings - Fork 93
/
xmlschema.rb
executable file
·302 lines (244 loc) · 8.61 KB
/
xmlschema.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#!/usr/bin/env ruby
require "rexml/document"
require "optparse"
$path = nil
#################################################
# \brief A not very elegant way to convert to schema types
def xsdType(_type)
if _type == "unsigned int"
return "unsignedInt"
elsif _type == "unsigned long"
return "unsignedLog"
elsif _type == "bool"
return "boolean"
else
return _type
end
end
#################################################
def isStdType(_type)
return _type == "string" || _type == "int" || _type == "double" ||
_type == "float" || _type == "bool" || _type == "char" ||
_type == "unsigned int"
end
#################################################
def printElem(_file, _spaces, _elem)
# this currently short-circuits the plugin.sdf copy_data element.
if _elem.attributes["name"].nil?
_file.printf("%*s<xsd:sequence>\n", _spaces-2, "")
_file.printf("%*s<xsd:any minOccurs='0' maxOccurs='unbounded' processContents='lax'/>\n", _spaces, "")
_file.printf("%*s</xsd:sequence>\n", _spaces-2, "")
return
end
type = _elem.attributes["type"]
if isStdType(type)
type = "xsd:" + xsdType(type)
end
minOccurs = '0'
maxOccurs = 'unbounded'
if _elem.attributes["required"] == '0'
minOccurs='0'
maxOccurs='1'
elsif _elem.attributes["required"] == '1'
minOccurs='1'
maxOccurs='1'
elsif _elem.attributes["required"] == '+'
minOccurs='1'
maxOccurs='unbounded'
elsif _elem.attributes["required"] == '*'
minOccurs='0'
maxOccurs='unbounded'
end
_file.printf("%*s<xsd:choice minOccurs='%s' maxOccurs='%s'>\n",
_spaces, "", minOccurs, maxOccurs)
# Print the complex type with a name
if type.nil? || type == ""
_file.printf("%*s<xsd:element name='%s'>\n",
_spaces, "", _elem.attributes["name"])
if !_elem.elements["description"].nil? &&
!_elem.elements["description"].text.nil?
printDocumentation(_file, _spaces+2, _elem.elements["description"].text)
end
_file.printf("%*s<xsd:complexType>\n", _spaces+2, "")
_file.printf("%*s<xsd:choice maxOccurs='unbounded'>\n", _spaces+4, "")
_elem.get_elements("element").each do |elem|
printElem(_file, _spaces+6, elem)
end
_file.printf("%*s</xsd:choice>\n", _spaces+4, "")
# Print the attributes for the complex type
# Attributes must go at the end of the complex type.
_elem.get_elements("attribute").each do |attr|
printAttribute(_file, _spaces+4, attr);
end
_file.printf("%*s</xsd:complexType>\n", _spaces+2, "")
else
_file.printf("%*s<xsd:element name='%s' type='%s'>\n",
_spaces, "", _elem.attributes["name"], type)
if !_elem.elements["description"].nil? &&
!_elem.elements["description"].text.nil?
printDocumentation(_file, _spaces+2, _elem.elements["description"].text)
end
end
_file.printf("%*s</xsd:element>\n", _spaces, "")
_file.printf("%*s</xsd:choice>\n", _spaces, "")
end
#################################################
def printDocumentation(_file, _spaces, _doc)
_file.printf("%*s<xsd:annotation>\n", _spaces, "")
_spaces += 2
_file.printf("%*s<xsd:documentation xml:lang='en'>\n", _spaces, "")
_spaces += 2
_file.printf("%*s<![CDATA[%s]]>\n",_spaces, "", _doc);
_spaces -= 2
_file.printf("%*s</xsd:documentation>\n", _spaces, "")
_spaces -= 2
_file.printf("%*s</xsd:annotation>\n", _spaces, "")
end
#################################################
def printIncludeRef(_file, _spaces, _inc)
path = File.join($path, _inc.attributes["filename"])
doc = REXML::Document.new File.new(path)
incElemName = doc.root.attributes['name']
_file.printf("%*s<xsd:element ref='%s'/>\n", _spaces, "", incElemName)
end
#################################################
def printInclude(_file, _spaces, _attr)
loc = "http://sdformat.org/schemas/"
loc += _attr.attributes['filename'].sub("\.sdf","\.xsd")
_file.printf("%*s<xsd:include schemaLocation='%s'/>\n", _spaces, "", loc)
end
#################################################
def printAttribute(_file, _spaces, _attr)
name = _attr.attributes["name"]
type = _attr.attributes["type"]
use = ""
default = ""
if !_attr.attributes["required"].nil?
if _attr.attributes["required"] == "1"
use = "use='required'"
elsif _attr.attributes["required"] == "0"
use = "use='optional'"
# Default is only valid if use is optional
if !_attr.attributes["default"].nil?
default="default='#{_attr.attributes["default"]}'"
end
end
end
if isStdType(type)
type = "xsd:" + xsdType(type)
end
_file.printf("%*s<xsd:attribute name='%s' type='%s' %s %s>\n", _spaces,
"", name, type, use, default)
if !_attr.elements["description"].nil? &&
!_attr.elements["description"].text.nil?
printDocumentation(_file, _spaces+2, _attr.elements["description"].text)
end
_file.printf("%*s</xsd:attribute>\n", _spaces, "")
end
#################################################
# \brief Print the complete schema for an element into a file.
# \param[in] _file File pointer in which to print the schema.
# \param[in] _spaces Number of spaces to prepend to each line.
# \param[in] _elem The SDF element to convert to an xml schema.
def printXSD(_file, _spaces, _elem)
if !_elem.elements["description"].nil? &&
!_elem.elements["description"].text.nil?
printDocumentation(_file, _spaces, _elem.elements["description"].text)
end
_file.printf("%*s<xsd:include schemaLocation='http://sdformat.org/schemas/types.xsd'/>\n", _spaces, "")
# Print the inclues for the complex type
# The includes must appear first
_elem.get_elements("include").each do |inc|
printInclude(_file, _spaces, inc);
end
if _elem.get_elements("element").size > 0 ||
_elem.get_elements("attribute").size > 0 ||
_elem.get_elements("include").size > 0
# Print the complex type with a name
_file.printf("%*s<xsd:element name='%s'>\n", _spaces, "",
_elem.attributes["name"])
_file.printf("%*s<xsd:complexType>\n", _spaces+2, "")
if _elem.attributes['name'] != "plugin" &&
(_elem.get_elements("element").size > 0 ||
_elem.get_elements("include").size > 0)
_file.printf("%*s<xsd:choice maxOccurs='unbounded'>\n", _spaces+4, "")
end
# Print all the child elements
_elem.get_elements("element").each do |elem|
printElem(_file, _spaces+6, elem);
end
# Print all the included sdf's root elements
_elem.get_elements("include").each do |inc|
printIncludeRef(_file, _spaces+6, inc);
end
if _elem.attributes['name'] != "plugin" &&
(_elem.get_elements("element").size > 0 ||
_elem.get_elements("include").size > 0)
_file.printf("%*s</xsd:choice>\n", _spaces+4, "")
end
# Print the attributes for the complex type
# Attributes must go at the end of the complex type.
_elem.get_elements("attribute").each do |attr|
printAttribute(_file, _spaces+4, attr);
end
# Close the complex type
_file.printf("%*s</xsd:complexType>\n", _spaces+2, "")
_file.printf("%*s</xsd:element>\n", _spaces, "")
else
type = _elem.attributes["type"]
if isStdType(type)
type = "xsd:" + type
end
if !type.nil?
type = "type='" + type + "'"
end
_file.printf("%*s<xsd:element name='%s' %s/>\n", _spaces, "",
_elem.attributes["name"], type)
end
end
infile = nil
outdir = nil
opt_parser = OptionParser.new do |o|
o.on("-i", "--in [path]", String,
"SDF file to compile") {|path| infile = path}
o.on("-o", "--out [path]", String,
"Output directory for source and header files") {|path| outdir = path}
o.on("-s", "--sdf [path]", String,
"Directory containing all the SDF files") {|path| $path = path}
o.on("-h", "--help", "Display this help message") do
puts opt_parser
exit
end
end
opt_parser.parse!
if infile.nil?
puts "Missing option -i."
exit
elsif !File.exists?(infile)
puts "Input file[#{infile}] does not exist\n"
exit
end
if $path.nil?
puts "Missing option -s."
exit
elsif !Dir.exists?($path)
puts "SDF source dir[#{$path}] does not exist\n"
exit
end
if outdir.nil?
puts "Missing output directory, option -o."
exit
elsif !Dir.exists?(outdir)
Dir.mkdir(outdir)
end
doc = REXML::Document.new File.new(infile)
spaces = 2
doc.elements.each_with_index("element") do |elem, i|
out_xsd = infile.split("/").last.sub("\.sdf","\.xsd")
file = File.open(File.join(outdir, out_xsd), "w")
file.print("<?xml version='1.0' encoding='UTF-8'?>\n")
file.print("<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>\n")
printXSD(file, spaces, elem)
file.print("</xsd:schema>\n")
file.close()
end