#***************************************************************************** # inventory.py # # XML I/O for Inventory (new schema) # # (c) 2006 Andres Heinloo, GFZ Potsdam # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. For more information, see http://www.gnu.org/ #***************************************************************************** from __future__ import (absolute_import, division, print_function, unicode_literals) import seiscomp.legacy.db.xmlio.xmlwrap as _xmlwrap from seiscomp.legacy.db import DBError try: from xml.etree import cElementTree as ET # Python 2.5? except ImportError: import cElementTree as ET _root_tag = "{http://geofon.gfz-potsdam.de/ns/Inventory/1.0/}inventory" class _UsedSensor(object): def __init__(self): self.calibration = set() def reg_calibration(self, id): self.calibration.add(id) class _UsedDatalogger(object): def __init__(self): self.decimation = set() self.calibration = set() def reg_decimation(self, sampleRateNumerator, sampleRateDenominator): self.decimation.add((sampleRateNumerator, sampleRateDenominator)) def reg_calibration(self, id): self.calibration.add(id) class _UsedAuxilliaryDevice(object): def __init__(self): self.source = set() def reg_source(self, id): self.source.add(id) class _UsedInstruments(object): def __init__(self): self.sensor = {} self.datalogger = {} self.auxDevice = {} def reg_sensor(self, name): try: return self.sensor[name] except KeyError: obj = _UsedSensor() self.sensor[name] = obj return obj def reg_datalogger(self, name): try: return self.datalogger[name] except KeyError: obj = _UsedDatalogger() self.datalogger[name] = obj return obj def reg_auxDevice(self, name): try: return self.auxDevice[name] except KeyError: obj = _UsedAuxilliaryDevice() self.auxDevice[name] = obj return obj class _UsedFilters(object): def __init__(self): self.filters = set() def reg_filter(self, name): self.filters.add(name) #***************************************************************************** # XML IN (instruments) #***************************************************************************** def _responseFIR_in(xresponseFIR, inventory): if xresponseFIR.action == "delete": try: inventory.remove_responseFIR(xresponseFIR.name) except KeyError: pass return try: responseFIR = inventory.responseFIR[xresponseFIR.name] if responseFIR.publicID != xresponseFIR.publicID: inventory.remove_responseFIR(xresponseFIR.name) raise KeyError except KeyError: responseFIR = inventory.insert_responseFIR(xresponseFIR.name, publicID=xresponseFIR.publicID) xresponseFIR.publicID = responseFIR.publicID xresponseFIR._copy_to(responseFIR) def _responseIIR_in(xresponseIIR, inventory): if xresponseIIR.action == "delete": try: inventory.remove_responseIIR(xresponseIIR.name) except KeyError: pass return try: responseIIR = inventory.responseIIR[xresponseIIR.name] if responseIIR.publicID != xresponseIIR.publicID: inventory.remove_responseIIR(xresponseIIR.name) raise KeyError except KeyError: responseIIR = inventory.insert_responseIIR(xresponseIIR.name, publicID=xresponseIIR.publicID) xresponseIIR.publicID = responseIIR.publicID xresponseIIR._copy_to(responseIIR) def _responsePAZ_in(xresponsePAZ, inventory): if xresponsePAZ.action == "delete": try: inventory.remove_responsePAZ(xresponsePAZ.name) except KeyError: pass return try: responsePAZ = inventory.responsePAZ[xresponsePAZ.name] if responsePAZ.publicID != xresponsePAZ.publicID: inventory.remove_responsePAZ(xresponsePAZ.name) raise KeyError except KeyError: responsePAZ = inventory.insert_responsePAZ(xresponsePAZ.name, publicID=xresponsePAZ.publicID) xresponsePAZ.publicID = responsePAZ.publicID xresponsePAZ._copy_to(responsePAZ) def _responsePolynomial_in(xresponsePolynomial, inventory): if xresponsePolynomial.action == "delete": try: inventory.remove_responsePolynomial(xresponsePolynomial.name) except KeyError: pass return try: responsePolynomial = inventory.responsePolynomial[xresponsePolynomial.name] if responsePolynomial.publicID != xresponsePolynomial.publicID: inventory.remove_responsePolynomial(xresponsePolynomial.name) raise KeyError except KeyError: responsePolynomial = inventory.insert_responsePolynomial(xresponsePolynomial.name, publicID=xresponsePolynomial.publicID) xresponsePolynomial.publicID = responsePolynomial.publicID xresponsePolynomial._copy_to(responsePolynomial) def _responseFAP_in(xresponseFAP, inventory): if xresponseFAP.action == "delete": try: inventory.remove_responseFAP(xresponseFAP.name) except KeyError: pass return try: responseFAP = inventory.responseFAP[xresponseFAP.name] if responseFAP.publicID != xresponseFAP.publicID: inventory.remove_responseFAP(xresponseFAP.name) raise KeyError except KeyError: responseFAP = inventory.insert_responseFAP(xresponseFAP.name, publicID=xresponseFAP.publicID) xresponseFAP.publicID = responseFAP.publicID xresponseFAP._copy_to(responseFAP) def _decimation_in(xdecim, device): if xdecim.action == "delete": try: device.remove_decimation(xdecim.sampleRateNumerator, xdecim.sampleRateDenominator) except KeyError: pass return try: decim = device.decimation[xdecim.sampleRateNumerator][xdecim.sampleRateDenominator] except KeyError: decim = device.insert_decimation(xdecim.sampleRateNumerator, xdecim.sampleRateDenominator) xdecim._copy_to(decim) def _calibration_in(xcalib, device): if xcalib.action == "delete": try: device.remove_calibration(xcalib.serialNumber, xcalib.channel, xcalib.start) except KeyError: pass return try: calib = device.calibration[xcalib.serialNumber][xcalib.channel][xcalib.start] except KeyError: calib = device.insert_calibration(xcalib.serialNumber, xcalib.channel, xcalib.start) xcalib._copy_to(calib) def _datalogger_in(xlogger, inventory): if xlogger.action == "delete": try: inventory.remove_datalogger(xlogger.name) except KeyError: pass return try: logger = inventory.datalogger[xlogger.name] if logger.publicID != xlogger.publicID: inventory.remove_datalogger(xlogger.name) raise KeyError except KeyError: logger = inventory.insert_datalogger(xlogger.name, publicID=xlogger.publicID) xlogger.publicID = logger.publicID xlogger._copy_to(logger) for xdecim in xlogger.decimation: _decimation_in(xdecim, logger) for xcalib in xlogger.calibration: _calibration_in(xcalib, logger) def _sensor_in(xsensor, inventory): if xsensor.action == "delete": try: inventory.remove_sensor(xsensor.name) except KeyError: pass return try: sensor = inventory.sensor[xsensor.name] if sensor.publicID != xsensor.publicID: inventory.remove_sensor(xsensor.name) raise KeyError except KeyError: sensor = inventory.insert_sensor(xsensor.name, publicID=xsensor.publicID) xsensor.publicID = sensor.publicID xsensor._copy_to(sensor) for xcalib in xsensor.calibration: _calibration_in(xcalib, sensor) def _aux_source_in(xaux_source, auxDevice): if xaux_source.action == "delete": try: auxDevice.remove_auxSource(xaux_source.name) except KeyError: pass return try: aux_source = auxDevice.aux_source[xaux_source.name] except KeyError: aux_source = auxDevice.insert_auxSource(xaux_source.name) xaux_source._copy_to(aux_source) def _auxDevice_in(xauxDevice, inventory): if xauxDevice.action == "delete": try: inventory.remove_auxDevice(xauxDevice.name) except KeyError: pass return try: auxDevice = inventory.auxDevice[xauxDevice.name] if auxDevice.publicID != xauxDevice.publicID: inventory.remove_auxDevice(xauxDevice.name) raise KeyError except KeyError: auxDevice = inventory.insert_auxDevice(xauxDevice.name, publicID=xauxDevice.publicID) xauxDevice.publicID = auxDevice.publicID xauxDevice._copy_to(auxDevice) for xaux_source in xauxDevice.source: _aux_source_in(xaux_source, auxDevice) #***************************************************************************** # XML IN (stations) #***************************************************************************** def _Comment_in(xcom, elem): if xcom.action == "delete": try: elem.remove_comment(xcom.id) except KeyError: pass return try: com = elem.comment[xcom.id] except KeyError: com = elem.insert_comment(xcom.id) xcom._copy_to(com) def _AuxStream_in(xaux, sl): if xaux.action == "delete": try: sl.remove_auxStream(xaux.code, xaux.start) except KeyError: pass return try: aux = sl.auxStream[xaux.code][xaux.start] except KeyError: aux = sl.insert_auxStream(xaux.code, xaux.start) xaux._copy_to(aux) def _Stream_in(xstrm, sl): if xstrm.action == "delete": try: sl.remove_Stream(xstrm.code, xstrm.start) except KeyError: pass return try: strm = sl.stream[xstrm.code][xstrm.start] if strm.publicID != xstrm.publicID: sl.remove_stream(xstrm.code, xstrm.start) raise KeyError except KeyError: strm = sl.insert_stream(xstrm.code, xstrm.start, publicID=xstrm.publicID) xstrm.publicID = strm.publicID xstrm._copy_to(strm) for xcom in xstrm.comment: _Comment_in(xcom, strm) def _SensorLocation_in(xsl, sta): if xsl.action == "delete": try: sta.remove_sensorLocation(xsl.code, xsl.start) except KeyError: pass return try: sl = sta.sensorLocation[xsl.code][xsl.start] if sl.publicID != xsl.publicID: sta.remove_sensorLocation(xsl.code, xsl.start) raise KeyError except KeyError: sl = sta.insert_sensorLocation(xsl.code, xsl.start, publicID=xsl.publicID) xsl.publicID = sl.publicID xsl._copy_to(sl) for xStream in xsl.stream: _Stream_in(xStream, sl) for xAuxStream in xsl.auxStream: _AuxStream_in(xAuxStream, sl) for xcom in xsl.comment: _Comment_in(xcom, sl) def _Station_in(xsta, net): if xsta.action == "delete": try: net.remove_station(xsta.code, xsta.start) except KeyError: pass return try: sta = net.station[xsta.code][xsta.start] if sta.publicID != xsta.publicID: net.remove_station(xsta.code, xsta.start) raise KeyError except KeyError: sta = net.insert_station(xsta.code, xsta.start, publicID=xsta.publicID) xsta.publicID = sta.publicID xsta._copy_to(sta) for xsensorLocation in xsta.sensorLocation: _SensorLocation_in(xsensorLocation, sta) for xcom in xsta.comment: _Comment_in(xcom, sta) def _Network_in(xnet, inventory): if xnet.action == "delete": try: inventory.remove_network(xnet.code, xnet.start) except KeyError: pass return try: net = inventory.network[xnet.code][xnet.start] if net.publicID != xnet.publicID: inventory.remove_network(xnet.code, xnet.start) raise KeyError except KeyError: net = inventory.insert_network(xnet.code, xnet.start, publicID=xnet.publicID) xnet.publicID = net.publicID xnet._copy_to(net) for xsta in xnet.station: _Station_in(xsta, net) for xcom in xnet.comment: _Comment_in(xcom, net) def _StationReference_in(xsref, gr): if xsref.action == "delete": try: inventory.remove_stationReference(xsref.stationID) except KeyError: pass return try: sref = gr.stationReference[xsref.stationID] except KeyError: sref = gr.insert_stationReference(xsref.stationID) xsref._copy_to(sref) def _StationGroup_in(xgr, inventory): if xgr.action == "delete": try: inventory.remove_stationGroup(xgr.code) except KeyError: pass return try: gr = inventory.stationGroup[xgr.code] if gr.publicID != xgr.publicID: inventory.remove_stationGroup(xgr.code) raise KeyError except KeyError: gr = inventory.insert_stationGroup(xgr.code, publicID=xgr.publicID) xgr.publicID = gr.publicID xgr._copy_to(gr) for xsref in xgr.stationReference: _StationReference_in(xsref, gr) #***************************************************************************** # XML IN (doc) #***************************************************************************** def _xmldoc_in(xinventory, inventory): for xresponseFIR in xinventory.responseFIR: _responseFIR_in(xresponseFIR, inventory) for xresponseIIR in xinventory.responseIIR: _responseIIR_in(xresponseIIR, inventory) for xresponsePAZ in xinventory.responsePAZ: _responsePAZ_in(xresponsePAZ, inventory) for xresponsePolynomial in xinventory.responsePolynomial: _responsePolynomial_in(xresponsePolynomial, inventory) for xresponseFAP in xinventory.responseFAP: _responseFAP_in(xresponseFAP, inventory) for xsensor in xinventory.sensor: _sensor_in(xsensor, inventory) for xlogger in xinventory.datalogger: _datalogger_in(xlogger, inventory) for xauxDevice in xinventory.auxDevice: _auxDevice_in(xauxDevice, inventory) for xnet in xinventory.network: _Network_in(xnet, inventory) for xgr in xinventory.stationGroup: _StationGroup_in(xgr, inventory) #***************************************************************************** # XML OUT (instruments) #***************************************************************************** def _responseFIR_out(xinventory, responseFIR, modified_after): if modified_after is None or responseFIR.last_modified >= modified_after: xresponseFIR = xinventory._new_responseFIR() xresponseFIR._copy_from(responseFIR) xinventory._append_child(xresponseFIR) return True return False def _responseIIR_out(xinventory, responseIIR, modified_after): if modified_after is None or responseIIR.last_modified >= modified_after: xresponseIIR = xinventory._new_responseIIR() xresponseIIR._copy_from(responseIIR) xinventory._append_child(xresponseIIR) return True return False def _responsePAZ_out(xinventory, responsePAZ, modified_after): if modified_after is None or responsePAZ.last_modified >= modified_after: xresponsePAZ = xinventory._new_responsePAZ() xresponsePAZ._copy_from(responsePAZ) xinventory._append_child(xresponsePAZ) return True return False def _responsePolynomial_out(xinventory, responsePolynomial, modified_after): if modified_after is None or responsePolynomial.last_modified >= modified_after: xresponsePolynomial = xinventory._new_responsePolynomial() xresponsePolynomial._copy_from(responsePolynomial) xinventory._append_child(xresponsePolynomial) return True return False def _responseFAP_out(xinventory, responseFAP, modified_after): if modified_after is None or responseFAP.last_modified >= modified_after: xresponseFAP = xinventory._new_responseFAP() xresponseFAP._copy_from(responseFAP) xinventory._append_child(xresponseFAP) return True return False def _decimation_out(xdevice, decim, modified_after, filters): if filters is not None: for f in str(decim.digitalFilterChain).split(): filters.reg_filter(f) for f in str(decim.analogueFilterChain).split(): filters.reg_filter(f) if modified_after is None or decim.last_modified >= modified_after: xdecim = xdevice._new_decimation() xdecim._copy_from(decim) xdevice._append_child(xdecim) return True return False def _gain_out(xcalib, gain, modified_after): if modified_after is None or gain.last_modified >= modified_after: xgain = xcalib._new_gain() xgain._copy_from(gain) xcalib._append_child(xgain) return True return False def _dataloggerCalibration_out(xdevice, calib, modified_after): xcalib = xdevice._new_calibration() if modified_after is None or calib.last_modified >= modified_after: xcalib._copy_from(calib) retval = True else: xcalib.serialNumber = calib.serialNumber retval = False if retval: xdevice._append_child(xcalib) return retval def _sensorCalibration_out(xdevice, calib, modified_after): xcalib = xdevice._new_calibration() if modified_after is None or calib.last_modified >= modified_after: xcalib._copy_from(calib) retval = True else: xcalib.serialNumber = calib.serialNumber retval = False if retval: xdevice._append_child(xcalib) return retval def _datalogger_out(xinventory, logger, modified_after, used, filters): xlogger = xinventory._new_datalogger() if modified_after is None or logger.last_modified >= modified_after: xlogger._copy_from(logger) retval = True else: xlogger.publicID = logger.publicID retval = False for i in logger.decimation.values(): for j in i.values(): if used is None or \ (j.sampleRateNumerator, j.sampleRateDenominator) in used.decimation: retval |= _decimation_out(xlogger, j, modified_after, filters) for c in [t for sn in logger.calibration.values()\ for ch in sn.values()\ for t in ch.values()]: if used is None or c.serialNumber in used.calibration: retval |= _dataloggerCalibration_out(xlogger, c, modified_after) if retval: xinventory._append_child(xlogger) return retval def _sensor_out(xinventory, sensor, modified_after, used, filters): xsensor = xinventory._new_sensor() if filters is not None and sensor.response != "": filters.reg_filter(sensor.response) if modified_after is None or sensor.last_modified >= modified_after: xsensor._copy_from(sensor) retval = True else: xsensor.publicID = sensor.publicID retval = False for c in [t for sn in sensor.calibration.values()\ for ch in sn.values()\ for t in ch.values()]: if used is None or c.serialNumber in used.calibration: retval |= _sensorCalibration_out(xsensor, c, modified_after) if retval: xinventory._append_child(xsensor) return retval def _aux_source_out(xauxDevice, aux_source, modified_after): if modified_after is None or aux_source.last_modified >= modified_after: xaux_source = xauxDevice._new_source() xaux_source._copy_from(aux_source) xauxDevice._append_child(xaux_source) return True return False def _auxDevice_out(xinventory, auxDevice, modified_after, used): xauxDevice = xinventory._new_auxDevice() if modified_after is None or auxDevice.last_modified >= modified_after: xauxDevice._copy_from(auxDevice) retval = True else: xauxDevice.publicID = auxDevice.publicID retval = False for i in auxDevice.source.values(): if used is None or i.name in used.source: retval |= _aux_source_out(xauxDevice, i, modified_after) if retval: xinventory._append_child(xauxDevice) return retval #***************************************************************************** # XML OUT (stations) #***************************************************************************** def _Comment_out(xelem, com, modified_after, used_instr): if modified_after is None or com.last_modified >= modified_after: xcom = xelem._new_comment() xcom._copy_from(com) xelem._append_child(xcom) return True return False def _Stream_out(xsl, strm, modified_after, used_instr): if used_instr is not None: used_sensor = used_instr.reg_sensor(strm.sensor) if strm.sensorSerialNumber != "": used_sensor.reg_calibration(strm.sensorSerialNumber) used_logger = used_instr.reg_datalogger(strm.datalogger) used_logger.reg_decimation(strm.sampleRateNumerator, strm.sampleRateDenominator) if strm.dataloggerSerialNumber != "": used_logger.reg_calibration(strm.dataloggerSerialNumber) if modified_after is None or strm.last_modified >= modified_after: xstrm = xsl._new_stream() xstrm._copy_from(strm) retval = True else: xstrm.code = strm.code xstrm.start = strm.start retval = False for i in strm.comment.values(): retval |= _Comment_out(xstrm, i, modified_after, used_instr) if retval: xsl._append_child(xstrm) return retval def _AuxStream_out(xsl, aux, modified_after, used_instr): if used_instr is not None: used_auxDevice = used_instr.reg_auxDevice(aux.device) used_auxDevice.reg_source(aux.source) if modified_after is None or aux.last_modified >= modified_after: xaux = xsl._new_auxStream() xaux._copy_from(aux) xsl._append_child(xaux) return True return False def _SensorLocation_out(xsta, sl, modified_after, used_instr): xsl = xsta._new_sensorLocation() if modified_after is None or sl.last_modified >= modified_after: xsl._copy_from(sl) retval = True else: xsl.code = sl.code xsl.start = sl.start retval = False for i in sl.stream.values(): for j in i.values(): retval |= _Stream_out(xsl, j, modified_after, used_instr) for i in sl.auxStream.values(): for j in i.values(): retval |= _AuxStream_out(xsl, j, modified_after, used_instr) for i in sl.comment.values(): retval |= _Comment_out(xsl, i, modified_after, used_instr) if retval: xsta._append_child(xsl) return retval def _Station_out(xnet, sta, modified_after, used_instr): xsta = xnet._new_station() if modified_after is None or sta.last_modified >= modified_after: xsta._copy_from(sta) retval = True else: xsta.code = sta.code xsta.start = sta.start retval = False for i in sta.sensorLocation.values(): for j in i.values(): retval |= _SensorLocation_out(xsta, j, modified_after, used_instr) for i in sta.comment.values(): retval |= _Comment_out(xsta, i, modified_after, used_instr) if retval: xnet._append_child(xsta) return retval def _Network_out(xinventory, net, modified_after, used_instr): xnet = xinventory._new_network() if modified_after is None or net.last_modified >= modified_after: xnet._copy_from(net) retval = True else: xnet.code = net.code xnet.start = net.start retval = False for i in net.station.values(): for j in i.values(): retval |= _Station_out(xnet, j, modified_after, used_instr) for i in net.comment.values(): retval |= _Comment_out(xnet, i, modified_after, used_instr) if retval: xinventory._append_child(xnet) return retval def _StationReference_out(xgr, sref, modified_after, used_instr): xsref = xgr._new_stationReference() xsref._copy_from(sref) xgr._append_child(xsref) return True def _StationGroup_out(xinventory, gr, modified_after, used_instr): if modified_after is None or gr.last_modified >= modified_after: xgr = xinventory._new_stationGroup() xgr._copy_from(gr) xinventory._append_child(xgr) for i in gr.stationReference.values(): _StationReference_out(xgr, i, modified_after, used_instr) return True return False #***************************************************************************** # XML OUT (doc) #***************************************************************************** def _xmldoc_out(xinventory, inventory, instr, modified_after): if instr == 0: for i in inventory.network.values(): for j in i.values(): _Network_out(xinventory, j, modified_after, None) for i in inventory.stationGroup.values(): _StationGroup_out(xinventory, i, modified_after, None) elif instr == 1: used_instr = _UsedInstruments() used_filters = _UsedFilters() for i in inventory.network.values(): for j in i.values(): _Network_out(xinventory, j, modified_after, used_instr) for i in inventory.stationGroup.values(): _StationGroup_out(xinventory, i, modified_after, None) for i in inventory.datalogger.values(): used_logger = used_instr.datalogger.get(i.publicID) if used_logger is not None: _datalogger_out(xinventory, i, modified_after, used_logger, used_filters) for i in inventory.sensor.values(): used_sensor = used_instr.sensor.get(i.publicID) if used_sensor is not None: _sensor_out(xinventory, i, modified_after, used_sensor, used_filters) for i in inventory.auxDevice.values(): used_auxDevice = used_instr.auxDevice.get(i.publicID) if used_auxDevice is not None: _auxDevice_out(xinventory, i, modified_after, used_auxDevice) for i in inventory.responseFIR.values(): if i.publicID in used_filters.filters: _responseFIR_out(xinventory, i, modified_after) for i in inventory.responseIIR.values(): if i.publicID in used_filters.filters: _responseIIR_out(xinventory, i, modified_after) for i in inventory.responsePAZ.values(): if i.publicID in used_filters.filters: _responsePAZ_out(xinventory, i, modified_after) for i in inventory.responsePolynomial.values(): if i.publicID in used_filters.filters: _responsePolynomial_out(xinventory, i, modified_after) for i in inventory.responseFAP.values(): if i.publicID in used_filters.filters: _responseFAP_out(xinventory, i, modified_after) elif instr == 2: for i in inventory.network.values(): for j in i.values(): _Network_out(xinventory, j, modified_after, None) for i in inventory.stationGroup.values(): _StationGroup_out(xinventory, i, modified_after, None) for i in inventory.datalogger.values(): _datalogger_out(xinventory, i, modified_after, None, None) for i in inventory.sensor.values(): _sensor_out(xinventory, i, modified_after, None, None) for i in inventory.auxDevice.values(): _auxDevice_out(xinventory, i, modified_after, used_auxDevice) for i in inventory.responseFIR.values(): _responseFIR_out(xinventory, i, modified_after) for i in inventory.responseIIR.values(): _responseIIR_out(xinventory, i, modified_after) for i in inventory.responsePAZ.values(): _responsePAZ_out(xinventory, i, modified_after) for i in inventory.responsePolynomial.values(): _responsePolynomial_out(xinventory, i, modified_after) for i in inventory.responseFAP.values(): _responseFAP_out(xinventory, i, modified_after) #***************************************************************************** # Incremental Parser #***************************************************************************** class _IncrementalParser(object): def __init__(self, inventory): self.__inventory = inventory self.__p = ET.XMLTreeBuilder() def feed(self, s): self.__p.feed(s) def close(self): root = self.__p.close() if root.tag != _root_tag: raise DBError("unrecognized root element: " + root.tag) xinventory = _xmlwrap.xml_Inventory(root) _xmldoc_in(xinventory, self.__inventory) #***************************************************************************** # Public functions #***************************************************************************** def make_parser(inventory): return _IncrementalParser(inventory) def xml_in(inventory, src): doc = ET.parse(src) root = doc.getroot() if root.tag != _root_tag: raise DBError("unrecognized root element: " + root.tag) xinventory = _xmlwrap.xml_Inventory(root) _xmldoc_in(xinventory, inventory) def _indent(elem, level=0): s = 1*"\t" # indent char i = "\n" + level*s if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + s for e in elem: _indent(e, level+1) if not e.tail or not e.tail.strip(): e.tail = i + s if not e.tail or not e.tail.strip(): e.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def xml_out(inventory, dest, instr=0, modified_after=None, stylesheet=None, indent=True): xinventory = _xmlwrap.xml_Inventory() _xmldoc_out(xinventory, inventory, instr, modified_after) if isinstance(dest, str): fd = open(dest, "wb") elif hasattr(dest, "write"): fd = dest else: raise TypeError("invalid file object") try: filename = fd.name except AttributeError: filename = '' fd.write(b'\n') if stylesheet is not None: fd.write(b'\n' % \ (stylesheet,)) if indent is True: _indent(xinventory._element) ET.ElementTree(xinventory._element).write(fd, encoding="utf-8") if isinstance(dest, str): fd.close()