source: TOOLS/MOSAIX/update_xml.py @ 6446

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

O.M. : Evolution on MOSAIX

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