def new_exhib(): newelt = ET.Element('Exhibition') subelt = ET.SubElement(newelt, 'ExhibitionName') subelt.text = exhibition.ExhibitionName if catalog_num is not None: subelt = ET.SubElement(newelt, 'CatalogueNumber') subelt.text = str(catalog_num) subelt = ET.SubElement(newelt, 'Place') subelt.text = exhibition.Place dateelt = ET.SubElement(newelt, 'Date') subelt = ET.SubElement(dateelt, 'DateBegin') subelt.text = modesdate(exhibition.DateBegin) subelt = ET.SubElement(dateelt, 'DateEnd') subelt.text = modesdate(exhibition.DateEnd) return exhibition.DateBegin, newelt
def main(): inf = open(sys.argv[1]) outf = open(sys.argv[2], 'w') reader = csv.reader(inf) writer = csv.writer(outf) row = next(reader) row.append('modesdate') row.append('isodate') # writer.writerow(row) for row in reader: indate = row[1] d, status, nfields = parsedate(indate) print(row, d, status) if d: if WRITEALL or not status: outs = modesdate(d, nfields) iso = d.isoformat() row.append(outs) row.append(iso) newrow = [row[0], outs] writer.writerow(newrow) elif WRITEALL: if indate and indate != 'unknown': print(f'Cannot parse {row}') outs = 'unknown' iso = '' if indate and indate != 'unknown': print(f'{row}') row.append(outs) row.append(iso) writer.writerow(row)
def one_object(objelt: ET.Element, idnum: str) -> bool: """ :param objelt: the Object :param idnum: the ObjectIdentity/Number text (for trace) :return: True if an object is updated """ references = objelt.findall('./References/Reference') updated = False for reference in references: refdate = reference.find('./Date') if refdate is None: continue refdatetext: str = refdate.text if refdatetext is None or len(refdatetext) == 0: continue try: newdate, partcount, datetype = datefrombritishdate(refdatetext) except ValueError: continue if datetype == MODESTYPE: # if it's already a Modes format date continue mdate = modesdate(newdate, partcount) refdate.text = mdate updated = True trace(2, '{}: {} -> {}', idnum, refdatetext, mdate) return updated
def expand_value(text): match text.lower(): case '{{clear}}': return '' case '{{today}}': return modesdate(date.today()) case _: return text
def one_object(obj): db = obj.find( './ObjectLocation[@elementtype="current location"]/Date/DateBegin') if db is not None and db.text is not None: isodate = None try: isodate = dt.strptime(db.text, '%Y-%m-%d') except ValueError: pass if isodate: db.text = nd.modesdate(isodate)
def one_exhibition(exhib_elt): """ Handle an existing exhibition :param exhib_elt: an Exhibition element (under Object) :return: 0 if it is an empty template 1 if the input element's ExhibitionName is different from the one we are inserting 2 (also update the values) if the ExhibitionName values match It is possible to have duplicate exhibition names but exhibitions are guaranteed to have unique name+place+begindate. So if we are replacing the name, make sure that we are updating the correct exhibition by checking the complete keys. """ exhibname = exhib_elt.find('ExhibitionName') if exhibname is None: return 0 # This is an empty Exhibition template # Updating the exhibition name is a special case since it's used as # a key. The old name is in the XML file and is to be replaced. We # could skip this step as the full key compare will work anyhow, but # this gets us out of here quickly in most cases. if exhibname.text not in (_oldname, exhibition.ExhibitionName): return 1 # not a match so just keep this element as is # The exhibition names match but if they are duplicated elsewhere in # the list, we must look deeper. exhibkey = _oldname if _oldname else exhibition.ExhibitionName + ':' exhibkey += _oldplace if _oldplace else exhibition.Place + ':' exhibkey += _olddate if _olddate else ( exhibition.DateBegin.isoformat()[:10]) xmlkey = exhibname.text xmlplace = '' xmldate = '' subelts = list(exhib_elt) for subelt in subelts: tag = subelt.tag if tag == "Place": xmlplace = subelt.text elif tag == "Date": dates = list(subelt) for dateelt in dates: if dateelt.tag == 'DateBegin': xmldate = dateelt.text break xmlkey += ':' + xmlplace + ':' + xmldate # And finally, confirm that it's really the one we want to update. trace(3, '{}: exhibkey={}\nxmlkey={}', idnum, exhibkey, xmlkey) if exhibkey != xmlkey: return 1 # The names match so update the values for subelt in subelts: tag = subelt.tag if tag == "ExhibitionName": subelt.text = exhibition.ExhibitionName elif tag == "CatalogueNumber": subelt.text = str(catalog_num) elif tag == "Place": subelt.text = exhibition.Place elif tag == "Date": dates = list(subelt) for dateelt in dates: if dateelt.tag == 'DateBegin': dateelt.text = modesdate(exhibition.DateBegin) elif dateelt.tag == 'DateEnd': dateelt.text = modesdate(exhibition.DateEnd) else: trace( 1, 'ID {}: Unknown subelt in {} Exhibition element: {},' ' element not updated.', subelt.text, display_id, tag) return 2
def add_arguments(parser, command): global is_update, is_diff, is_select, is_validate # Needed for Sphinx if called_from_sphinx: is_update = command == 'update' is_diff = command == 'diff' is_select = command == 'select' is_validate = command == 'validate' parser.add_argument('-i', '--infile', required=True, help=''' The XML file saved from Modes.''') if is_update or is_select: parser.add_argument('-o', '--outfile', required=True, help=''' The output XML file.''') if is_diff or is_update or is_select: parser.add_argument('-a', '--all', action='store_true', help=''' Write all objects and, if -w is selected, issue a warning if an object is not in the detail CSV file. The default is to only write updated objects. In either case warn if an object in the CSV file is not in the input XML file.''') if is_update or is_diff: parser.add_argument('--col_acc', type=int, default=0, help=''' The zero-based column containing the accession number of the object to be updated. The default is column zero. ''') parser.add_argument('--col_loc', type=int, default=1, help=nd.sphinxify( ''' The zero-based column containing the new location of the object to be updated. The default is column 1. See the --location option which sets the location for all objects in which case this option is ignored.''', called_from_sphinx)) if is_update or is_diff: parser.add_argument('-c', '--current', action='store_true', help=''' Update the current location and change the old current location to a previous location. See the descrption of "n" and "p". ''') if is_update: parser.add_argument('-d', '--date', default=nd.modesdate(date.today()), help=''' When updating the current location, use this date as the DateEnd value for the previous location we're making and the DateBegin value for the new current location we're making. The default is today's date in Modes format (d.m.yyyy). ''') parser.add_argument('--datebegin', help=''' Use this string as the date to store in the new previous ObjectLocation date. The format must be in Modes format (d.m.yyyy). ''') parser.add_argument('--dateend', default=nd.modesdate(date.today()), help=''' Use this string as the date to store in the new previous ObjectLocation date. The format must be in Modes format (d.m.yyyy). ''') parser.add_argument('--encoding', default='utf-8', help=''' Set the input encoding. Default is utf-8. Output is always utf-8. ''') if is_update: parser.add_argument('-f', '--force', action='store_true', help=''' Write the object to the output file even if it hasn't been updated. This only applies to objects whose ID appears in the CSV file. -a implies -f. ''') parser.add_argument('--heading', help=nd.sphinxify( ''' The first row of the map file contains a column title which must match the parameter (case insensitive) in the column designated for the location. If a --location argument is specified, the first row is skipped and the value, which nevertheless must be specified, is ignored. ''', called_from_sphinx)) if is_update or is_diff: parser.add_argument('-j', '--object', help=nd.sphinxify( ''' Specify a single object to be processed. If specified, do not specify the CSV file containing object numbers and locations (--mapfile). You must also specify --location. ''', called_from_sphinx)) parser.add_argument('-l', '--location', help=''' Set the location for all of the objects in the CSV file. In this case the CSV file only needs a single column containing the accession number. ''') if is_diff or is_select or is_update: parser.add_argument('-m', '--mapfile', help=nd.sphinxify( ''' The CSV file mapping the object number to its new location. By default, the accession number is in the first column (column 0) but this can be changed by the --col_acc option. The new location is by default in the second column (column 1) but can be changed by the --col_loc option. This argument is ignored if --object is specified. ''', called_from_sphinx)) if is_update or is_diff: parser.add_argument('-n', '--normal', action='store_true', help=''' Update the normal location. See the description for "p" and "c".''') if is_diff: parser.add_argument('--old', action='store_true', help=''' The column selected is the "old" location, the one we are moving the object from. Warn if the value in the CSV file does not match the value in the XML file. The default is to warn if the value in the CSV file does match the value in the XML file which is not expected as the purpose is to update that value. ''') if is_update: parser.add_argument('--patch', action='store_true', help=''' Update the specified location in place without creating history. This is always the behavior for normal locations but not for current or previous. ''') parser.add_argument('-p', '--previous', action='store_true', help=nd.sphinxify( ''' Add a previous location. This location's start and end dates must not overlap with an existing current or previous location's date(s). If "p" is selected, do not select "n" or "c". If "p" is specified, you must specify --datebegin and --dateend. ''', called_from_sphinx)) parser.add_argument('--reset_current', action='store_true', help=''' Only output the most recent current location element for each object, deleting all previous locations. ''') parser.add_argument('-r', '--reason', default='', help=''' Insert this text as the reason for the move to the new current location. ''') parser.add_argument('-s', '--short', action='store_true', help=''' Only process a single object. For debugging.''') parser.add_argument('-v', '--verbose', type=int, default=1, help=''' Set the verbosity. The default is 1 which prints summary information. ''') if is_diff or is_select or is_update: parser.add_argument('-w', '--warn', action='store_true', help=''' Valid if -a is selected. Warn if an object in the XML file is not in the CSV file. ''')