diff --git a/README b/README index 8a5a8de83ddee93f3e3344a7ecd175ba2e068219..4b904189ae22604cc2d5414527920abb9167c086 100644 --- a/README +++ b/README @@ -65,14 +65,14 @@ More information More information on generateDS.py is in generateDS.html in the distribution or `generateDS -- Generate Data Structures from XML Schema -- -http://www.rexx.com/~dkuhlman/generateDS.html -<http://www.rexx.com/~dkuhlman/generateDS.html>`_. +http://www.davekuhlman.org/generateDS.html +<http://www.davekuhlman.org/generateDS.html>`_. There is also a tutorial. See tutorial/tutorial.html in the distribution or `generateDS -- Introduction and Tutorial -- -http://www.rexx.com/~dkuhlman/generateds_tutorial.html -<http://www.rexx.com/~dkuhlman/generateds_tutorial.html>`_. +http://www.davekuhlman.org/generateds_tutorial.html +<http://www.davekuhlman.org/generateds_tutorial.html>`_. ----------- @@ -150,6 +150,10 @@ Version 2.11b (08/19/2013) code. Thanks to Shahaf Abileah for reporting this and for providing test files to reproduce the problem behavior. - Created unit test for anonymous types. +- Added command line option --fix-type-names. This may be useful if + there are name conflicts in your XML schema, for example, because + the schema refers to two types with the same name but in different + namespaces. Version 2.11a (08/16/2013) - Added ability to use XML catalog to find included/imported @@ -1419,6 +1423,6 @@ The following enhancements and fixes remain to be done: Dave Kuhlman -dkuhlman@rexx.com -http://www.rexx.com/~dkuhlman +dkuhlman@pacbell.net +http://www.davekuhlman.org diff --git a/generateDS.html b/generateDS.html index 726500daf09342a27e4f606cf54d9537c4ce2906..f41c344d72c17b35c3544fe85893beceae3a9a16 100644 --- a/generateDS.html +++ b/generateDS.html @@ -201,10 +201,11 @@ tt.docutils { <tbody valign="top"> <tr><th class="docinfo-name">Author:</th> <td>Dave Kuhlman</td></tr> +<tr><th class="docinfo-name">Contact:</th> +<td><a class="first last reference external" href="mailto:dkuhlman@pacbell.net">dkuhlman@pacbell.net</a></td></tr> <tr><th class="docinfo-name">Address:</th> <td><pre class="address"> -<a class="first reference external" href="mailto:dkuhlman@rexx.com">dkuhlman@rexx.com</a> -<a class="last reference external" href="http://www.rexx.com/~dkuhlman">http://www.rexx.com/~dkuhlman</a> +<a class="first last reference external" href="http://www.davekuhlman.org">http://www.davekuhlman.org</a> </pre> </td></tr> </tbody> @@ -216,7 +217,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.11a</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.11b</td> </tr> </tbody> </table> @@ -225,7 +226,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">August 16, 2013</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">August 21, 2013</td> </tr> </tbody> </table> @@ -434,6 +435,8 @@ to use the Python code and data structures that it generates; and http://pypi.python.org/pypi/generateDS/</a></li> <li><a class="reference external" href="http://sourceforge.net/projects/generateds/">Source Forge -- http://sourceforge.net/projects/generateds/</a></li> +<li><a class="reference external" href="https://bitbucket.org/dkuhlman/generateds">Bitbucket -- +https://bitbucket.org/dkuhlman/generateds</a></li> </ul> </div> <div class="section" id="support-and-more-information"> diff --git a/generateDS.py b/generateDS.py index bfd59cd6e4dad8690dbb3fa1da9d6973ffc5010a..477b598b0e23c182964889a02c8d84ea2d7fbeb8 100755 --- a/generateDS.py +++ b/generateDS.py @@ -86,6 +86,8 @@ Options: create session file in generateds_gui.py. Or, copy and edit sample.session from the distribution. + --fix-type-names="oldname1:newname1;oldname2:newname2;..." + Fix up (replace) complex type names. --version Print version and exit. Usage example: @@ -224,6 +226,7 @@ AnyTypeIdentifier = '__ANY__' ExportWrite = True ExportEtree = False ExportLiteral = True +FixTypeNames = None SchemaToPythonTypeMap = {} @@ -5706,8 +5709,10 @@ def parseAndGenerate( import process_includes outfile = StringIO.StringIO() process_includes.process_include_files( - infile, outfile, inpath=xschemaFileName, - catalogpath=catalogFilename) + infile, outfile, + inpath=xschemaFileName, + catalogpath=catalogFilename, + fixtypenames=FixTypeNames) outfile.seek(0) infile = outfile parser.parse(infile) @@ -5825,7 +5830,8 @@ def main(): Namespacedef, NoDates, NoVersion, \ TEMPLATE_MAIN, TEMPLATE_SUBCLASS_FOOTER, Dirpath, \ ExternalEncoding, MemberSpecs, NoQuestions, \ - ExportWrite, ExportEtree, ExportLiteral + ExportWrite, ExportEtree, ExportLiteral, \ + FixTypeNames outputText = True args = sys.argv[1:] try: @@ -5838,7 +5844,7 @@ def main(): 'user-methods=', 'no-process-includes', 'silence', 'namespacedef=', 'external-encoding=', 'member-specs=', 'no-dates', 'no-versions', - 'no-questions', 'session=', + 'no-questions', 'session=', 'fix-type-names=', 'version', 'export=', ]) except getopt.GetoptError: @@ -5970,6 +5976,8 @@ def main(): ExternalEncoding = option[1] elif option[0] in ('-q', '--no-questions'): NoQuestions = True + elif option[0] == "--fix-type-names": + FixTypeNames = option[1] elif option[0] == '--version': showVersion = True elif option[0] == '--member-specs': diff --git a/generateDS.txt b/generateDS.txt index 42d1ce0a7a85acfb1a496e3a8719bfbb1aa96417..ab8558cb4561f3261ab86d0827c04776d1ab4002 100644 --- a/generateDS.txt +++ b/generateDS.txt @@ -3,8 +3,9 @@ generateDS -- Generate Data Structures from XML Schema ====================================================== :author: Dave Kuhlman -:address: dkuhlman@rexx.com - http://www.rexx.com/~dkuhlman +:contact: dkuhlman@pacbell.net +:address: + http://www.davekuhlman.org .. Do not modify the following version comments. They are used by updateversion.py. @@ -123,6 +124,10 @@ You can find the source distribution here: http://sourceforge.net/projects/generateds/ <http://sourceforge.net/projects/generateds/>`_ +- `Bitbucket -- + https://bitbucket.org/dkuhlman/generateds + <https://bitbucket.org/dkuhlman/generateds>`_ + @@ -137,8 +142,8 @@ https://lists.sourceforge.net/lists/listinfo/generateds-users There is a tutorial in the distribution: ``tutorial/tutorial.html`` and at `generateDS -- Introduction and Tutorial -- -http://www.rexx.com/~dkuhlman/generateds_tutorial.html -<http://www.rexx.com/~dkuhlman/generateds_tutorial.html>`_. +http://www.davekuhlman.org/generateds_tutorial.html +<http://www.davekuhlman.org/generateds_tutorial.html>`_. How to build and install it @@ -286,6 +291,8 @@ Here is the usage message displayed by ``generateDS.py``:: create session file in generateds_gui.py. Or, copy and edit sample.session from the distribution. + --fix-type-names="oldname1:newname1;oldname2:newname2;..." + Fix up (replace) complex type names. --version Print version and exit. Usage example: @@ -507,6 +514,17 @@ session=mysession.session used to override options in the session file. A session file is an XML document, so you can modify it with a text editor. +fix-type-names="oldname1:newname1;oldname2:newname2;..." + Fix up (replace) complex type names. Using this option will + replace the following: (1) the 'name' attribute of a + complexType; (2) the 'type' attribute of each element that + refers to the type; and (3) the 'base' attribute of each + extension that refers to the type. These fixups happen before + information is collected from the schema for code generation. + Therefore, using this option is effectively equivalent to + copying your schema, then editing it with your text editor, then + generating code from the modified schema. + version Print out the current version of generateDS.py and immediately exit. diff --git a/process_includes.py b/process_includes.py index b53243ae4b1bd056e91edfbf3bd496d33b3002e4..4f4ab1d41020e38462f3b972c2de1dc8f8ca3b4c 100755 --- a/process_includes.py +++ b/process_includes.py @@ -53,10 +53,13 @@ def load_catalog(catalogpath): # Functions for external use -def process_include_files(infile, outfile, inpath='', catalogpath=None): +def process_include_files( + infile, outfile, inpath='', catalogpath=None, + fixtypenames=None): load_catalog(catalogpath) options = Values({ 'force': False, + 'fixtypenames': fixtypenames, }) prep_schema_doc(infile, outfile, inpath, options) @@ -230,6 +233,7 @@ def prep_schema_doc(infile, outfile, inpath, options): root2.append(insert_node) process_groups(root2) raise_anon_complextypes(root2) + fix_type_names(root2, options) doc2 = etree.ElementTree(root2) doc2.write(outfile) return doc2 @@ -267,6 +271,81 @@ def process_groups(root): replace_group_defs(def_dict, refs) +def fix_type_names(root, options): + fixnamespec = options.fixtypenames + if fixnamespec: + namespecs = fixnamespec.split(';') + else: + namespecs = [] + for namespec in namespecs: + names = namespec.split(':') + if len(names) == 2: + oldname = names[0] + newname = names[1] + elif len(names) == 1: + oldname = names[0] + newname = '%sxx' % (oldname, ) + else: + continue + # Change the name (name attribute) of the complexType. + pat = './/%s:complexType[@name="%s"]' % ( + root.prefix, oldname) + elements = xpath_find(root, pat) + if len(elements) < 1: + sys.stderr.write( + "\nWarning: fix-type-names can't find complexType '%s'. " + "Exiting.\n\n" % (oldname, )) + sys.exit(1) + if len(elements) < 1: + sys.stderr.write( + "Warning: fix-type-names found more than " + "one complexType '%s'. " + "Changing first." % (oldname, )) + element = elements[0] + element.set('name', newname) + # Change the reference (type attribute) of child elements. + pat = './/%s:element' % (root.prefix, ) + elements = xpath_find(root, pat) + for element in elements: + typename = element.get('type') + if not typename: + continue + names = typename.split(':') + if len(names) == 2: + typename = names[1] + elif len(names) == 1: + typename = names[0] + else: + continue + if typename != oldname: + continue + if not element.getchildren(): + element.set('type', newname) + # Change the extensions ('base' attribute) that refer to the old type. + pat = './/%s:extension' % (root.prefix, ) + elements = xpath_find(root, pat) + for element in elements: + typename = element.get('base') + if not typename: + continue + names = typename.split(':') + if len(names) == 2: + typename = names[1] + elif len(names) == 1: + typename = names[0] + else: + continue + if typename != oldname: + continue + element.set('base', newname) + + +def xpath_find(node, pat): + namespaces = {node.prefix: node.nsmap[node.prefix]} + elements = node.xpath(pat, namespaces=namespaces) + return elements + + def replace_group_defs(def_dict, refs): for ref_node in refs: name = trim_prefix(ref_node.get('ref')) @@ -339,12 +418,16 @@ def raise_anon_complextypes(root): # simpleType, element). def collect_type_names(node): prefix = node.prefix - if prefix: + if prefix is not None and prefix.strip(): pattern = './/%s:complexType|.//%s:simpleType|.//%s:element' % ( prefix, prefix, prefix) + # Must make sure that we have a namespace dictionary that does *not* + # have a key None. + namespaces = {prefix: node.nsmap[prefix]} + elements = node.xpath(pattern, namespaces=namespaces) else: pattern = './/complexType|.//simpleType|.//element' - elements = node.xpath(pattern, namespaces=node.nsmap) + elements = node.xpath(pattern) names = [ el.attrib['name'] for el in elements if 'name' in el.attrib and el.getchildren()