diff --git a/.gitignore b/.gitignore
index 08e5eba3e..fe7c191e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ build
build_*
*.*.sw?
.vscode
+__pycache__
diff --git a/sdf/1.10/CMakeLists.txt b/sdf/1.10/CMakeLists.txt
index 531202e38..55a906f71 100644
--- a/sdf/1.10/CMakeLists.txt
+++ b/sdf/1.10/CMakeLists.txt
@@ -73,8 +73,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/sdf/1.5/CMakeLists.txt b/sdf/1.5/CMakeLists.txt
index be630c5c4..68ceba50f 100644
--- a/sdf/1.5/CMakeLists.txt
+++ b/sdf/1.5/CMakeLists.txt
@@ -67,8 +67,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Pyhton3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/sdf/1.6/CMakeLists.txt b/sdf/1.6/CMakeLists.txt
index 0ed72231d..ed41bf3b1 100644
--- a/sdf/1.6/CMakeLists.txt
+++ b/sdf/1.6/CMakeLists.txt
@@ -71,8 +71,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/sdf/1.7/CMakeLists.txt b/sdf/1.7/CMakeLists.txt
index ce971c310..51e6fe9af 100644
--- a/sdf/1.7/CMakeLists.txt
+++ b/sdf/1.7/CMakeLists.txt
@@ -72,8 +72,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/sdf/1.8/CMakeLists.txt b/sdf/1.8/CMakeLists.txt
index 162b2941a..ed7f874df 100644
--- a/sdf/1.8/CMakeLists.txt
+++ b/sdf/1.8/CMakeLists.txt
@@ -74,8 +74,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/sdf/1.9/CMakeLists.txt b/sdf/1.9/CMakeLists.txt
index 28ae14907..193f82c23 100644
--- a/sdf/1.9/CMakeLists.txt
+++ b/sdf/1.9/CMakeLists.txt
@@ -74,8 +74,8 @@ foreach(FIL ${sdfs})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.xsd"
- COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/tools/xmlschema.rb
- ARGS -s ${CMAKE_CURRENT_SOURCE_DIR} -i ${ABS_FIL} -o ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xmlschema.py
+ ARGS --sdf-dir ${CMAKE_CURRENT_SOURCE_DIR} --input-file ${ABS_FIL} --output-dir ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${ABS_FIL}
COMMENT "Running xml schema compiler on ${FIL}"
VERBATIM)
diff --git a/tools/xmlschema.py b/tools/xmlschema.py
new file mode 100755
index 000000000..b3518f9ec
--- /dev/null
+++ b/tools/xmlschema.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python3
+# Copyright 2023 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Conversion script for SDF definitions to XML XSD files
+"""
+
+from xml.etree import ElementTree
+
+import os
+
+from typing import List, Dict, Tuple, Optional
+
+
+# Mapping between "type" values found in SDF files to the corresponding
+# XSD standard datatypes as defined by https://www.w3.org/TR/xmlschema11-2/
+SDF_TYPES_TO_XSD_STD_TYPES = {
+ "bool": "boolean",
+ "char": "char",
+ "int": "int",
+ "double": "double",
+ "float": "float",
+ "string": "string",
+ "unsigned int": "unsignedInt",
+ "unsigned long": "unsignedLong",
+}
+
+# Mapping between "required" values found in SDF files to the corresponding
+# minOccurs and maxOccurs found in XSD
+SDF_REQUIRED_TO_MIN_MAX_OCCURS: Dict[str, Tuple[str, str]] = {
+ "0": ("0", "1"), # Required: 0, (minOccurs: 0, maxOccurs: 1)
+ "1": ("1", "1"), # Required: 1, (minOccurs: 1, maxOccurs: 1)
+ "+": ("1", "unbounded"), # Required: +, (minOccurs: 1, maxOccurs: inf)
+ "*": ("0", "unbounded"), # Required: *, (minOccurs: 0, maxOccurs: inf)
+ "-1": ("0", "unbounded"), # Required: -1, (minOccurs: 0, maxOccurs: inf)
+}
+
+
+def indent_lines(lines: List[str], indent: int) -> List[str]:
+ """
+ Indent a list of xml lines group of lines by a number (indent) of spaces
+
+ """
+ return [" " * indent + line for line in lines]
+
+
+def get_attribute(element: ElementTree.Element, attrib: str) -> Optional[str]:
+ """
+ Retrieve XML attribute from an element
+ """
+ return element.attrib[attrib] if attrib in element.attrib else None
+
+
+def is_std_type(sdf_type: str) -> bool:
+ """
+ Check if sdf_type is a known XSD standard type.
+ Return true if the sdf_type is in the set of known types, false otherwise.
+ """
+ return sdf_type in SDF_TYPES_TO_XSD_STD_TYPES
+
+
+def xsd_type_string(sdf_type: str) -> Optional[str]:
+ """
+ Check if xsd_type is a known XSD standard type.
+ If it is, return 'xsd:' + type, None otherwise.
+ """
+ if is_std_type(sdf_type):
+ xsd_type = SDF_TYPES_TO_XSD_STD_TYPES[sdf_type]
+ return "xsd:" + xsd_type
+ return None
+
+
+def print_documentation(element: ElementTree.Element) -> List[str]:
+ """
+ Print the documentation associated with an element
+ """
+ lines = []
+ description = element.find("description")
+ if (
+ description is not None
+ and description.text is not None
+ and len(description.text)
+ ):
+ lines.append("")
+ lines.append(" ")
+ lines.append(f" ")
+ lines.append(" ")
+ lines.append("")
+ return lines
+
+
+def print_include(element: ElementTree.Element) -> List[str]:
+ """
+ Print include tag information
+ """
+ lines = []
+ filename = get_attribute(element, "filename")
+ if filename is not None:
+ loc = "http://sdformat.org/schemas/"
+ loc += filename.replace(".sdf", ".xsd")
+ lines.append(f"")
+ return lines
+
+
+def print_include_ref(element: ElementTree.Element, sdf_root_dir: str) -> List[str]:
+ """
+ Print include tag reference information
+ """
+ lines = []
+ filename = get_attribute(element, "filename")
+ if filename is not None:
+ sdf_path = os.path.join(sdf_root_dir, filename)
+ if not os.path.exists(sdf_path):
+ raise RuntimeError(f"Attempted to include non-existent file: {sdf_path}")
+
+ include_tree = ElementTree.parse(sdf_path)
+ root = include_tree.getroot()
+ include_element_name = root.attrib["name"]
+ lines.append(f"")
+ return lines
+
+
+def print_plugin_element(element: ElementTree.Element) -> List[str]:
+ """
+ Separate handling of the 'plugin' element
+ """
+ lines = []
+ # Short circuit for plugin.sdf copy_data element
+ if "copy_data" in element.attrib:
+ lines.append("")
+ lines.append(
+ " "
+ )
+ lines.append("")
+ return lines
+
+
+def print_element(element: ElementTree.Element) -> List[str]:
+ """
+ Print a child element of the sdf definition
+ """
+ lines = []
+
+ elem_name = get_attribute(element, "name")
+ elem_type = get_attribute(element, "type")
+ elem_reqd = get_attribute(element, "required")
+
+ if elem_type and is_std_type(elem_type):
+ elem_type = xsd_type_string(elem_type)
+
+ if not elem_reqd:
+ raise RuntimeError("Cannot process element missing 'required' attribute")
+
+ min_occurs, max_occurs = SDF_REQUIRED_TO_MIN_MAX_OCCURS[elem_reqd]
+ lines.append(f"")
+
+ if elem_type is None:
+ lines.append(f"")
+ lines.extend(indent_lines(print_documentation(element), 2))
+ lines.append(" ")
+ lines.append(" ")
+
+ for child_element in element.findall("element"):
+ lines.extend(indent_lines(print_element(child_element), 6))
+
+ lines.append(" ")
+
+ for attribute in element.findall("attribute"):
+ lines.extend(indent_lines(print_attribute(attribute), 4))
+
+ lines.append(" ")
+ else:
+ lines.append(f"")
+ lines.extend(indent_lines(print_documentation(element), 2))
+
+ lines.append("")
+ lines.append("")
+ return lines
+
+
+def print_attribute(element: ElementTree.Element) -> List[str]:
+ """
+ Print an attribute of the sdf definition
+ """
+ lines = []
+
+ elem_name = get_attribute(element, "name")
+ elem_type = get_attribute(element, "type")
+ elem_reqd = get_attribute(element, "required")
+ elem_default = get_attribute(element, "default")
+
+ if elem_type and is_std_type(elem_type):
+ elem_type = xsd_type_string(elem_type)
+
+ use = ""
+ default = ""
+
+ if elem_reqd == "1":
+ use = "use='required'"
+ elif elem_reqd == "0":
+ use = "use='optional'"
+ if elem_default is not None:
+ default = f"default='{elem_default}'"
+
+ lines.append(
+ f""
+ )
+ lines.extend(indent_lines(print_documentation(element), 2))
+ lines.append("")
+ return lines
+
+
+def print_xsd(element: ElementTree.Element, sdf_root_dir: str) -> List[str]:
+ """
+ Print xsd for top level SDF element
+ """
+ lines = []
+
+ elem_name = get_attribute(element, "name")
+ elem_type = get_attribute(element, "type")
+
+ elements = element.findall("element")
+ attributes = element.findall("attribute")
+ includes = element.findall("include")
+
+ lines.extend(print_documentation(element))
+ lines.append(
+ ""
+ )
+
+ # Reference any includes in the SDF file
+ for include in includes:
+ lines.extend(print_include(include))
+
+ if len(elements) or len(attributes) or len(includes):
+ lines.append(f"")
+ lines.append(" ")
+
+ if elem_name != "plugin" and (len(elements) or len(includes)):
+ lines.append(" ")
+
+ for child_element in elements:
+ if "copy_data" in child_element.attrib:
+ element_lines = print_plugin_element(child_element)
+ lines.extend(indent_lines(element_lines, 4))
+ else:
+ element_lines = print_element(child_element)
+ lines.extend(indent_lines(element_lines, 6))
+
+ for include_element in includes:
+ element_lines = print_include_ref(include_element, sdf_root_dir)
+ lines.extend(indent_lines(element_lines, 6))
+
+ if elem_name != "plugin" and (len(elements) or len(includes)):
+ lines.append(" ")
+
+ for attribute_element in attributes:
+ lines.extend(indent_lines(print_attribute(attribute_element), 4))
+
+ lines.append(" ")
+ lines.append("")
+ else:
+ if elem_type and is_std_type(elem_type):
+ elem_type = f' type={xsd_type_string(elem_type)}'
+ else:
+ elem_type = ""
+
+ lines.append(f"")
+ return lines
+
+
+def process(input_file_sdf: str, sdf_dir: str) -> List[str]:
+ """
+ Produce an XSD file from an input SDF file
+ """
+ lines = []
+ tree = ElementTree.parse(input_file_sdf)
+ root = tree.getroot()
+ lines.append("")
+ lines.append("")
+ lines.extend(indent_lines(print_xsd(root, sdf_dir), 2))
+ lines.append("")
+ return lines
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser("xmlschema.py")
+ parser.add_argument("--input-file")
+ parser.add_argument("--sdf-dir")
+ parser.add_argument("--output-dir")
+ args = parser.parse_args()
+
+ input_file = os.path.abspath(args.input_file)
+ output_lines = process(input_file, args.sdf_dir)
+ fname = os.path.splitext(os.path.basename(args.input_file))[0]
+ os.makedirs(args.output_dir, exist_ok=True)
+
+ output_file = os.path.join(args.output_dir, f"{fname}.xsd")
+
+ with open(output_file, "w", encoding="utf8") as f:
+ f.write("\n".join(output_lines))
+ f.write("\n")
diff --git a/tools/xmlschema.rb b/tools/xmlschema.rb
deleted file mode 100755
index cadfa59fb..000000000
--- a/tools/xmlschema.rb
+++ /dev/null
@@ -1,302 +0,0 @@
-#!/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\n", _spaces-2, "")
- _file.printf("%*s\n", _spaces, "")
- _file.printf("%*s\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\n",
- _spaces, "", minOccurs, maxOccurs)
-
- # Print the complex type with a name
- if type.nil? || type == ""
-
- _file.printf("%*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\n", _spaces+2, "")
-
- _file.printf("%*s\n", _spaces+4, "")
-
- _elem.get_elements("element").each do |elem|
- printElem(_file, _spaces+6, elem)
- end
- _file.printf("%*s\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\n", _spaces+2, "")
- else
- _file.printf("%*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\n", _spaces, "")
- _file.printf("%*s\n", _spaces, "")
-
-end
-
-#################################################
-def printDocumentation(_file, _spaces, _doc)
- _file.printf("%*s\n", _spaces, "")
-
- _spaces += 2
- _file.printf("%*s\n", _spaces, "")
-
- _spaces += 2
- _file.printf("%*s\n",_spaces, "", _doc);
- _spaces -= 2
-
- _file.printf("%*s\n", _spaces, "")
- _spaces -= 2
-
- _file.printf("%*s\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\n", _spaces, "", incElemName)
-end
-
-#################################################
-def printInclude(_file, _spaces, _attr)
- loc = "http://sdformat.org/schemas/"
- loc += _attr.attributes['filename'].sub("\.sdf","\.xsd")
- _file.printf("%*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\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\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\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\n", _spaces, "",
- _elem.attributes["name"])
- _file.printf("%*s\n", _spaces+2, "")
-
- if _elem.attributes['name'] != "plugin" &&
- (_elem.get_elements("element").size > 0 ||
- _elem.get_elements("include").size > 0)
- _file.printf("%*s\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\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\n", _spaces+2, "")
- _file.printf("%*s\n", _spaces, "")
- else
- type = _elem.attributes["type"]
-
- if isStdType(type)
- type = "xsd:" + type
- end
-
- if !type.nil?
- type = "type='" + type + "'"
- end
-
- _file.printf("%*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.exist?(infile)
- puts "Input file[#{infile}] does not exist\n"
- exit
-end
-
-if $path.nil?
- puts "Missing option -s."
- exit
-elsif !Dir.exist?($path)
- puts "SDF source dir[#{$path}] does not exist\n"
- exit
-end
-
-if outdir.nil?
- puts "Missing output directory, option -o."
- exit
-elsif !Dir.exist?(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("\n")
- file.print("\n")
-
- printXSD(file, spaces, elem)
-
- file.print("\n")
- file.close()
-end