source: TOOLS/MOSAIX/update_xml.py @ 6091

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

O.M: MOSAIX

Replaces multiple calls to python update_xml.py by one call
It uses a liste of command in a file now

  • Property svn:keywords set to Date Revision HeadURL Author Id
File size: 7.9 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 -v 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
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, Key, Value) :
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" )
73        print ( "Node  : ", Node )
74        sys.exit (2)
75
76    ## Update element
77    elem = nodeList[0]
78
79    if Debug :
80        print ( 'Node:', Node, ' -- Key:', Key, ' -- Value:', Value , ' -- Text:', Text  )
81
82    if Text != None :
83        if Debug :
84            print ( 'Attributes of node: ' + str (elem.attrib) )
85            print ( 'Text              : ' + str (elem.text)   )
86        elem.text = Text
87
88    if Key != None :
89        # To do : check that Key exist (it is added if not : do we want that ?)
90        if Debug :
91            print ( 'Attributes of node: ' + str (elem.attrib) )
92        elem.attrib.update ( { Key:Value } )
93
94    return iodef
95
96## ============================================================================
97## Main code
98
99# Creating a parser to read the command line arguments
100# The first step in using the argparse is creating an ArgumentParser object:
101parser = argparse.ArgumentParser (description = """
102Examples with the modification on the command line :
103     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
104     python %(prog)s -i iodef.xml -n 'context[@id="interpol_run"]/file_definition/file[@id="dia"]/variable[@name="dest_grid"]'   -t dstDomainType
105
106Usage with a command file :
107     python %(prog)s -i iodef.xml -c commands.txt
108   
109Syntax in the command file : removes the quote around the node description :
110-n context[@id="interpol_run"]/file_definition/file[@id="dia"]/variable[@name="dest_grid"]   -t dstDomainType
111
112   """ + "SVN : " + __Revision__, formatter_class=argparse.RawDescriptionHelpFormatter, epilog='-------- This is the end of the help message --------')
113
114# Adding arguments
115group1 = parser.add_mutually_exclusive_group (required=False)
116
117parser.add_argument ( '-i', '--input'  , help="XML input file"              , default='iodef.xml', type=str, metavar='<input_file>'  )
118parser.add_argument ( '-o', '--output' , help="XML output file"             , default=None       , type=str, metavar='<output_file>' )
119parser.add_argument ( '-n', '--node'   , help="XML node in Xpath syntax", default=None, type=str, metavar='<xml_node>')
120group1.add_argument ( '-k', '--key'    , help="XML key to update"       , default=None , type=str , metavar='<xml_key>' )
121group1.add_argument ( '-t', '--text'   , help="Will replace the 'text' part of the Xpath by <text>", default=None, type=str, metavar='<text>' )
122parser.add_argument ( '-v', '--value'  , help="New value for xml key  ", default=None, type=str, metavar='<value>' )
123parser.add_argument ( '-d', '--debug'  , action="store_true", default=False )
124parser.add_argument ( '-V', '--verbose', action="store_true", default=False )
125parser.add_argument ( '-c', '--commandfile', help="file with list of command", default=None, type=str )
126
127# Parse command line
128myargs  = parser.parse_args ()
129Verbose = myargs.verbose
130Debug   = myargs.debug
131
132if Debug : print ( "Command line arguments : ", myargs )
133
134FileCommand = myargs.commandfile
135FileIn      = myargs.input
136FileOut     = myargs.output
137Node        = myargs.node
138Key         = myargs.key
139Text        = myargs.text
140Value       = myargs.value
141   
142if FileCommand != None : 
143    if ( Node != None or Key != None or Text != None or Value != None ) :
144        print ('Error : when a command file is specified, options -k|--key, -n|--node and -v|--value a unused' )
145        exit (-2)
146   
147if FileOut == None : FileOut = FileIn
148   
149## Get XML tree from input file
150iodef = xml.etree.ElementTree.parse ( FileIn )
151
152if FileCommand == None :
153    ## Only one node to modify
154   
155    # Error handling not dealed by argparse
156    if Key != None and Value == None :
157        print ( "Error. When -k|--key=<key> is specified, you must specify -v|--value=<xml_value>" )
158        sys.exit (-1)
159
160    iodef = UpdateNode ( iodef, Node, Text, Key, Value)
161
162else :
163    ## Read a list of modification commands in a command file
164    fic = open (FileCommand, 'r')
165    lignes = fic.readlines()
166
167    for nn, ligne in enumerate (lignes) :
168
169        ligne = ligne.strip()
170        if ligne    == ''  : break # Skips blank lines
171        if ligne[0] == '#' : break # Skips comment lines
172
173        ligne = ligne.split('#')[0] # Remove trailing comments
174       
175        list_args = ligne.split()
176        list_args = simplify_string_list ( list_args )
177       
178        if Debug :
179            print ( '{:3d} : '.format(nn+1), end='')
180            print ( list_args )
181        myargs_ligne = parser.parse_args ( list_args )
182
183        Node     = myargs_ligne.node
184        Key      = myargs_ligne.key
185        Text     = myargs_ligne.text
186        Value    = myargs_ligne.value
187       
188        if Key != None and Value == None :
189            print ( "Error. When -k|--key=<key> is specified, you must specify -v|--value=<xml_value>" )
190            sys.exit (-1)
191        UpdateNode ( iodef, Node, Text, Key, Value)
192   
193## Writes XML tree to file
194iodef.write ( FileOut )
195
196## This is the end
197sys.exit (0)
198   
199### ===========================================================================
200###
201###                               That's all folk's !!!
202###
203### ===========================================================================
204
Note: See TracBrowser for help on using the repository browser.