Next / Previous / Contents / TCC Help System / NM Tech homepage

4.4. main(): The main program

The purpose of the script is to extract all the element and attribute names from the input schema, and write a Python module containing assignment statements that define a symbolic name for each unique name. For example, if the schema has an element named “player” that has an attribute “first-name”, we'll want to generate two Python assignments from those names:

PLAYER_N = 'player'
FIRST_NAME_A = 'first-name'

The obvious data structure for accumulating these names is a Python dictionary; we'll call it nameTable. We'll use the Python name (e.g., FIRST_NAME_A) as the key, and the XML name (e.g., first-name) as the value, in each dictionary entry.

The same attribute name may occur in more than one element. In that case, we'll want to avoid writing duplicate declarations. Because dictionary key values must be unique, we can just throw each name we find into the dictionary: at the end will be no duplications.

Here is the overall program flow:

  1. Process the command line arguments, and figure out whether the output is going to a file or to standard output.

    We'll define a small class named Args to encapsulate the processing and representation of the command line arguments. See Section 4.11, “class Args: Command line argument object”.

  2. The et.parse() function reads the RNG schema document and gives it to us as an et.ElementTree.

  3. We create nameTable as an empty dictionary, then walk the document tree recursively looking for element and attribute names. Each name we find is stored into nameTable.

  4. Finally, each key-value pair in nameTable is written to the output as a Python assignment statement.

The code follows. First, we process the command line arguments; see Section 4.11, “class Args: Command line argument object”.

# - - - - -   m a i n

def main():
    """Main program
    #-- 1
    # [ if sys.argv contains valid command line arguments ->
    #     args  :=  an Args instance representing those arguments
    #   else ->
    #     sys.stderr  +:=  error message(s)
    #     stop execution ]
    args = Args()

This step takes care of reading the input file and building the nameTable dictionary. See Section 4.5, “processInput(): Read the schema”.

    #-- 2
    # [ args is an Args object ->
    #     if args.inFileName names a readable file containing a
    #     valid RNG schema ->
    #       nameTable  :=  a dictionary whose keys are the Python
    #           manifest constant names for the element and
    #           attribute names in that schema (using args.prefix
    #           as a prefix), and each corresponding value is the
    #           XML name
    #     else ->
    #       sys.stderr  +:=  error message(s)
    #       stop execution ]
    nameTable = processInput(args)

All that remains is to write the output file; see Section 4.9, “writeOutput(): Generate the Python file”.

    #-- 3
    # [ args is an Args object ->
    #     if args.outFileName is None ->
    #       outFile  :=  sys.stdout
    #     else if args.outFileName names a writeable file ->
    #       outFile  :=  that file opened new for writing
    #     else ->
    #       sys.stderr  +:=  error message(s)
    #       stop execution ]
    if  args.outFileName is None:
        outFile = sys.stdout
            outFile = open(args.outFileName, "w")
        except (IOError, OSError) as x:
            fatal("Can't open output file '{0}': {1}".format(
                  args.outFileName,  str(x)))
    #-- 4
    # [ (outFile is a writeable file) and
    #   (nameTable is a dictionary whose keys are Python names
    #   and whose values are XML names ->
    #     outFile  :=  Python statements of the form 'n = v'
    #         for n in the set of keys of nameTable and each v
    #         is the corresponding nameTable value ]
    writeOutput(args, outFile, nameTable)