source: TOOLS/MOSAIX/update_xml.py @ 6169

Last change on this file since 6169 was 6093, checked in by omamce, 2 years ago

MOSAIX

  • Change update_xml syntax
  • Merge nco commands
  • Add some comments and metadata
  • Property svn:keywords set to Date Revision HeadURL Author Id
File size: 7.8 KB
Line 
1#!/usr/bin/env python
2### ===========================================================================
3###
4### Modifies or add an element in an XML file
5###
6### ===========================================================================
7##
8##  Warning, to install, configure, run, use any of Olivier Marti's
9##  software or to read the associated documentation you'll need at least
10##  one (1) brain in a reasonably working order. Lack of this implement
11##  will void any warranties (either express or implied).
12##  O. Marti assumes no responsability for errors, omissions,
13##  data loss, or any other consequences caused directly or indirectly by
14##  the usage of his software by incorrectly or partially configured
15##  personal.
16##
17## SVN information
18__Author__   = "$Author$"
19__Date__     = "$Date$"
20__Revision__ = "$Revision$"
21__Id__       = "$Id$"
22__HeadURL    = "$HeadURL$"
23
24# python update_xml.py -i ~/Unix/TOOLS/MOSAIX/iodef_atm_to_oce.xml -o essai.xml -n 'context[@id="interpol_read"]/file_definition/file[@id="file_src"]/field[@id="mask_src"]' -k name=Bidon
25# python update_xml.py -i ~/Unix/TOOLS/MOSAIX/iodef_atm_to_oce.xml -d -o essai.xml -n 'context[@id="interpol_run"]/file_definition/file[@id="dia"]/variable[@name="title"]' -t "SRC mask interpolated to DST"
26# python update_xml.py -i ~/Unix/TOOLS/MOSAIX/iodef_atm_to_oce.xml -o essai.xml -c InFile.txt
27
28# Tested with python/2.7.12 and python/3.6.4
29#
30import xml.etree.ElementTree
31import argparse, sys, textwrap, shlex
32   
33# Check version of Python
34Version = sys.version_info
35if Version < (2,7,0) :
36  sys.stderr.write ( "You need python 2.7 or later to run this script\n" )
37  sys.stderr.write ( "Present version is: " + str(Version[0]) + "." + str(Version[1]) + "." + str(Version[2]) + "\n" )
38  sys.exit (1)
39
40## ============================================================================
41## Needed functions
42
43def simplify_string_list (list_str) :
44    '''Concatenate some elements of the list of strings when needed'''
45    zlist = list_str.copy () ; list_new = []
46    while ( len (zlist) > 0 ) :
47        arg = zlist.pop (0)   
48        if arg[0] == '"' :
49            for arg2 in zlist.copy () :
50                arg = arg + " " + arg2
51                zlist.pop (0)
52                if arg2[-1] == '"' : break
53        arg = arg.strip('"').strip("'")
54        list_new.append (arg)
55    return list_new
56 
57def UpdateNode (iodef, Node, Text=None, Key=None) :
58    '''Update an xml node'''
59    # Remove whitespaces at both ends
60    Node = Node.rstrip().lstrip()
61
62    ## Find node
63    nodeList = iodef.findall (Node)
64
65    ## Check that one and only one node is found
66    if len (nodeList) == 0 :
67        print ( "Error : node not found" )
68        print ( "Node  : ", Node )
69        sys.exit (1)
70   
71    if len (nodeList) > 1 :
72        print ( "Error : " + len (nodeList)+" occurences of node found in file" )
73        print ( "Node  : ", Node )
74        sys.exit (2)
75
76    ## Update element
77    elem = nodeList[0]
78
79    if Text != None :
80        if Verbose : print ( 'Node:', Node, ' -- Text:', Text  )
81        if Debug :
82            print ( 'Attributes of node: ' + str (elem.attrib) )
83            print ( 'Text              : ' + str (elem.text)   )
84        elem.text = Text
85
86    if Key != None :
87     
88        # Check the syntax
89        if not '=' in Key :
90            print ( 'Key syntax error. Correct syntax is -k Key=Value' )
91            sys.exit (-1)
92        else :
93            KeyName, Value = Key.split ('=')
94            if Verbose : print ( 'Node:', Node, ' -- Key:', Key )
95            # To do : check that KeyName exist (it is added if not : do we want that ?)
96            if Debug :
97                print ( 'Attributes of node: ' + str (elem.attrib) )
98            elem.attrib.update ( { KeyName:Value } )
99
100    return iodef
101
102## ============================================================================
103## Main code
104
105# Creating a parser to read the command line arguments
106# The first step in using the argparse is creating an ArgumentParser object:
107parser = argparse.ArgumentParser (description = """
108Examples with the modification on the command line :
109     python %(prog)s -i iodef.xml -n 'context[@id="interpol_run"]/file_definition/file[@id="file_src"]/field[@id="mask_source"]' -k name -v maskutil_T
110     python %(prog)s -i iodef.xml -n 'context[@id="interpol_run"]/file_definition/file[@id="dia"]/variable[@name="dest_grid"]'   -t dstDomainType
111
112Usage with a command file :
113     python %(prog)s -i iodef.xml -c commands.txt
114   
115Syntax in the command file : removes the quote around the node description :
116-n context[@id="interpol_run"]/file_definition/file[@id="dia"]/variable[@name="dest_grid"]   -t dstDomainType
117
118   """ + "SVN : " + __Revision__, formatter_class=argparse.RawDescriptionHelpFormatter, epilog='-------- This is the end of the help message --------')
119
120# Adding arguments
121group1 = parser.add_mutually_exclusive_group (required=False)
122
123parser.add_argument ( '-i', '--input'  , help="XML input file"          , default='iodef.xml', type=str, metavar='<input_file>'  )
124parser.add_argument ( '-o', '--output' , help="XML output file"         , default=None       , type=str, metavar='<output_file>' )
125parser.add_argument ( '-n', '--node'   , help="XML node in Xpath syntax", default=None, type=str, metavar='<xml_node>')
126group1.add_argument ( '-k', '--key'    , help="XML key to update and new value (-k <name>=<value>)", default=None, type=str, metavar='<xml_key>' )
127group1.add_argument ( '-t', '--text'   , help="Will replace the 'text' part of the Xpath by <text>", default=None, type=str, metavar='<text>' )
128parser.add_argument ( '-d', '--debug'  , help="Extensive debug prints", action="store_true", default=False )
129parser.add_argument ( '-v', '--verbose', help="Some verbosity"        , action="store_true", default=False )
130parser.add_argument ( '-c', '--commandfile', help="file with list of command", default=None, type=str )
131
132# Parse command line
133myargs  = parser.parse_args ()
134Verbose = myargs.verbose
135Debug   = myargs.debug
136
137if Debug : print ( "Command line arguments : ", myargs )
138
139FileCommand = myargs.commandfile
140FileIn      = myargs.input
141FileOut     = myargs.output
142Node        = myargs.node
143Key         = myargs.key
144Text        = myargs.text
145   
146if FileCommand != None : 
147    if ( Node != None or Key != None or Text != None ) :
148        print ('Error : when a command file is specified, options -k|--key, -n|--node are unused' )
149        exit (-2)
150   
151if FileOut == None : FileOut = FileIn
152   
153## Get XML tree from input file
154iodef = xml.etree.ElementTree.parse ( FileIn )
155
156if FileCommand == None :
157    ## Only one node to modify
158    iodef = UpdateNode (iodef, Node, Key, Text)
159
160else :
161    ## Read a list of modification commands in a command file
162    fic = open (FileCommand, 'r')
163    lignes = fic.readlines()
164
165    for nn, ligne in enumerate (lignes) :
166        ligne = ligne.strip ().split ('#')[0] # Remove leading and trailing blanks, and trailing comments
167        if Debug : print (nn+1, ':', type (ligne) , ':', len (ligne) , ':', ligne, ':')
168        if ligne == '' or ligne == None or len(ligne) == 0 or ligne[0] == '#' :
169            if Debug : print ('Skips blank or comment line')
170        else : 
171            list_args = shlex.split (ligne)
172       
173            if Debug :
174                print ( '{:3d} : '.format(nn+1), end='')
175                print ( list_args )
176            # Parse args line
177            myargs_ligne = parser.parse_args (list_args)
178
179            Node     = myargs_ligne.node
180            Key      = myargs_ligne.key
181            Text     = myargs_ligne.text
182
183            UpdateNode (iodef, Node, Text, Key)
184   
185## Writes XML tree to file
186iodef.write ( FileOut )
187
188## This is the end
189if Debug : print ('This is the end')
190#sys.exit (0)
191   
192### ===========================================================================
193###
194###                               That's all folk's !!!
195###
196### ===========================================================================
197
Note: See TracBrowser for help on using the repository browser.