303 lines
8.6 KiB
Ruby
303 lines
8.6 KiB
Ruby
|
#!/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
|