source: TOOLS/MOSAIX/update_xml.py @ 6764

Last change on this file since 6764 was 6666, checked in by omamce, 7 months ago

O.M. : MOSAIX

Improved code with pylint analysis

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