def create_xml(self, add_as_part = True, originator = None, reuse = True): """Creates a genetic boundary feature organisational xml node from this genetic boundary feature object.""" if reuse and self.try_reuse(): return self.root # check for reusable (equivalent) object # create node with citation block gbf = super().create_xml(add_as_part = False, originator = originator) assert self.kind in self.valid_kinds kind_node = rqet.SubElement(gbf, ns['resqml2'] + 'GeneticBoundaryKind') kind_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'GeneticBoundaryKind') kind_node.text = self.kind if self.absolute_age is not None: date_time, year_offset = self.absolute_age age_node = rqet.SubElement(gbf, ns['resqml2'] + 'AbsoluteAge') age_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Timestamp') age_node.text = rqet.null_xml_text dt_node = rqet.SubElement(age_node, ns['resqml2'] + 'DateTime') dt_node.set(ns['xsi'] + 'type', ns['xsd'] + 'dateTime') dt_node.text = str(date_time) if year_offset is not None: yo_node = rqet.SubElement(age_node, ns['resqml2'] + 'YearOffset') yo_node.set(ns['xsi'] + 'type', ns['xsd'] + 'long') yo_node.text = str(year_offset) if add_as_part: self.model.add_part('obj_GeneticBoundaryFeature', self.uuid, gbf) return gbf
def _create_doc_props(model, add_as_part=True, root=None, originator=None): """Creates a document properties stub node and optionally adds as child of root and/or to parts forest.""" dp = rqet.Element(ns['cp'] + 'coreProperties') dp.text = rqet.null_xml_text created = rqet.SubElement(dp, ns['dcterms'] + 'created') created.set(ns['xsi'] + 'type', ns['dcterms'] + 'W3CDTF') # not sure of namespace here created.text = time.now() if originator is None: try: originator = str(os.getlogin()) except Exception: originator = 'unknown' creator = rqet.SubElement(dp, ns['dc'] + 'creator') creator.text = originator ver = rqet.SubElement(dp, ns['cp'] + 'version') ver.text = '1.0' if root is not None: root.append(dp) if add_as_part: model.add_part('docProps', None, dp) if model.rels_present: (_, rel_tree) = model.rels_forest['_rels/.rels'] core_rel = rqet.SubElement(rel_tree.getroot(), ns['rels'] + 'Relationship') core_rel.set('Id', 'CoreProperties') core_rel.set('Type', ns_url['rels_md'] + 'core-properties') core_rel.set('Target', 'docProps/core.xml') return dp
def create_xml(self, genetic_boundary_feature_root = None, add_as_part = True, add_relationships = True, originator = None, title_suffix = None, reuse = True): """Create a organisational xml node from a geobody boundary interpretation object.""" if not self.title: self.title = self.genetic_boundary_feature.feature_name if title_suffix: self.title += ' ' + title_suffix if reuse and self.try_reuse(): return self.root gbi = super().create_xml(add_as_part = False, originator = originator) if self.genetic_boundary_feature is not None: gbf_root = self.genetic_boundary_feature.root if gbf_root is not None: if genetic_boundary_feature_root is None: genetic_boundary_feature_root = gbf_root else: assert gbf_root is genetic_boundary_feature_root, 'genetic boundary feature mismatch' else: if genetic_boundary_feature_root is None: genetic_boundary_feature_root = self.feature_root assert genetic_boundary_feature_root is not None self.genetic_boundary_feature = GeneticBoundaryFeature(self.model, uuid = genetic_boundary_feature_root.attrib['uuid']) self.feature_root = genetic_boundary_feature_root assert self.domain in self.valid_domains, 'illegal domain value for geobody boundary interpretation' dom_node = rqet.SubElement(gbi, ns['resqml2'] + 'Domain') dom_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Domain') dom_node.text = self.domain create_xml_has_occurred_during(self.model, gbi, self.has_occurred_during) if self.boundary_relation_list is not None: for boundary_relation in self.boundary_relation_list: assert boundary_relation in self.valid_boundary_relations br_node = rqet.SubElement(gbi, ns['resqml2'] + 'BoundaryRelation') br_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'BoundaryRelation') br_node.text = str(boundary_relation) self.model.create_ref_node('InterpretedFeature', self.model.title_for_root(genetic_boundary_feature_root), genetic_boundary_feature_root.attrib['uuid'], content_type = 'obj_GeneticBoundaryFeature', root = gbi) if add_as_part: self.model.add_part('obj_GeobodyBoundaryInterpretation', self.uuid, gbi) if add_relationships: self.model.create_reciprocal_relationship(gbi, 'destinationObject', genetic_boundary_feature_root, 'sourceObject') return gbi
def create_xml(self, wellbore_feature_root=None, add_as_part=True, add_relationships=True, originator=None, title_suffix=None, reuse=True): """Creates a wellbore interpretation organisational xml node from a wellbore interpretation object.""" # note: related wellbore feature node should be created first and referenced here if not self.title: self.title = self.wellbore_feature.feature_name if title_suffix: self.title += ' ' + title_suffix if reuse and self.try_reuse(): return self.root wi = super().create_xml(add_as_part=False, originator=originator) if self.wellbore_feature is not None: wbf_root = self.wellbore_feature.root if wbf_root is not None: if wellbore_feature_root is None: wellbore_feature_root = wbf_root else: assert wbf_root is wellbore_feature_root, 'wellbore feature mismatch' if self.is_drilled is None: self.is_drilled = False id_node = rqet.SubElement(wi, ns['resqml2'] + 'IsDrilled') id_node.set(ns['xsi'] + 'type', ns['xsd'] + 'boolean') id_node.text = str(self.is_drilled).lower() assert self.domain in self.valid_domains, 'illegal domain value for wellbore interpretation' domain_node = rqet.SubElement(wi, ns['resqml2'] + 'Domain') domain_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Domain') domain_node.text = str(self.domain).lower() self.model.create_ref_node( 'InterpretedFeature', self.model.title_for_root(wellbore_feature_root), wellbore_feature_root.attrib['uuid'], content_type='obj_WellboreFeature', root=wi) if add_as_part: self.model.add_part('obj_WellboreInterpretation', self.uuid, wi) if add_relationships: self.model.create_reciprocal_relationship( wi, 'destinationObject', wellbore_feature_root, 'sourceObject') return wi
def _create_xml_facet_node(facet_type, facet, p_node): if facet_type is not None and facet is not None: facet_node = rqet.SubElement(p_node, ns['resqml2'] + 'Facet') facet_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'PropertyKindFacet') facet_node.text = rqet.null_xml_text facet_type_node = rqet.SubElement(facet_node, ns['resqml2'] + 'Facet') facet_type_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Facet') facet_type_node.text = facet_type facet_value_node = rqet.SubElement(facet_node, ns['resqml2'] + 'Value') facet_value_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') facet_value_node.text = facet
def create_xml(self, add_as_part=True, add_relationships=True, originator=None, reuse=True): """Creates a stratigraphic unit interpretation xml tree. arguments: add_as_part (bool, default True): if True, the interpretation is added to the parent model as a high level part add_relationships (bool, default True): if True and add_as_part is True, a relationship is created with the referenced stratigraphic unit feature originator (str, optional): if present, is used as the originator field of the citation block reuse (bool, default True): if True, the parent model is inspected for any equivalent interpretation and, if found, the uuid of this interpretation is set to that of the equivalent part returns: lxml.etree._Element: the root node of the newly created xml tree for the interpretation """ if reuse and self.try_reuse(): return self.root sui = super().create_xml(add_as_part=add_as_part, add_relationships=add_relationships, originator=originator, reuse=False) assert sui is not None if self.deposition_mode is not None: assert self.deposition_mode in valid_deposition_modes, \ f'invalid deposition mode {self.deposition_mode} for stratigraphic unit interpretation' dm_node = rqet.SubElement(sui, ns['resqml2'] + 'DepositionMode') dm_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'DepositionMode') dm_node.text = self.deposition_mode if self.min_thickness is not None or self.max_thickness is not None: assert self.thickness_uom in wam.valid_uoms(quantity='length') if self.min_thickness is not None: min_thick_node = rqet.SubElement(sui, ns['resqml2'] + 'MinThickness') min_thick_node.set(ns['xsi'] + 'type', ns['eml'] + 'LengthMeasure') min_thick_node.set('uom', self.thickness_uom) # todo: check this min_thick_node.text = str(self.min_thickness) if self.max_thickness is not None: max_thick_node = rqet.SubElement(sui, ns['resqml2'] + 'MaxThickness') max_thick_node.set(ns['xsi'] + 'type', ns['eml'] + 'LengthMeasure') max_thick_node.set('uom', self.thickness_uom) max_thick_node.text = str(self.max_thickness) return sui
def _create_solitary_point3d(flavour, root, xyz): """Creates a subelement to root for a solitary point in 3D space.""" # todo: check namespaces p3d = rqet.SubElement(root, ns['resqml2'] + flavour) p3d.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3d') p3d.text = rqet.null_xml_text for axis in range(3): coord_node = rqet.SubElement( p3d, ns['resqml2'] + 'Coordinate' + str(axis + 1)) coord_node.set(ns['xsi'] + 'type', ns['xsd'] + 'double') coord_node.text = str(xyz[axis]) return p3d
def __create_xml_refandz(self, p_node, ext_uuid): assert ext_uuid is not None assert self.ref_uuid is not None p_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dZValueArray') sg_node = rqet.SubElement(p_node, ns['resqml2'] + 'SupportingGeometry') sg_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dFromRepresentationLatticeArray') sg_node.text = '\n' niosr_node = rqet.SubElement( sg_node, ns['resqml2'] + 'NodeIndicesOnSupportingRepresentation') niosr_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'IntegerLatticeArray') niosr_node.text = '\n' sv_node = rqet.SubElement(niosr_node, ns['resqml2'] + 'StartValue') sv_node.set(ns['xsi'] + 'type', ns['xsd'] + 'integer') sv_node.text = '0' # no other possibility cater for at present for j_or_i in range(2): # 0 = J, 1 = I o_node = rqet.SubElement(niosr_node, ns['resqml2'] + 'Offset') o_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'IntegerConstantArray' ) # no other possibility cater for at present o_node.text = '\n' ov_node = rqet.SubElement(o_node, ns['resqml2'] + 'Value') ov_node.set(ns['xsi'] + 'type', ns['xsd'] + 'integer') ov_node.text = '1' # no other possibility cater for at present oc_node = rqet.SubElement(o_node, ns['resqml2'] + 'Count') oc_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') if j_or_i: oc_node.text = str(self.ni - 1) else: oc_node.text = str(self.nj - 1) ref_root = self.model.root_for_uuid(self.ref_uuid) self.model.create_ref_node('SupportingRepresentation', rqet.find_nested_tags_text( ref_root, ['Citation', 'Title']), self.ref_uuid, content_type='Grid2dRepresentation', root=sg_node) zv_node = rqet.SubElement(p_node, ns['resqml2'] + 'ZValues') zv_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') zv_node.text = '\n' v_node = rqet.SubElement(zv_node, ns['resqml2'] + 'Values') v_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset') v_node.text = '\n' self.model.create_hdf5_dataset_ref(ext_uuid, self.uuid, 'zvalues', root=v_node)
def _create_xml_property_min_max(collection, property_array, const_value, discrete, add_min_max, p_node, min_value, max_value): if add_min_max: # todo: use active cell mask on numpy min and max operations; exclude null values on discrete min max min_value, max_value = pcga._get_property_array_min_max_value( collection, property_array, const_value, discrete, min_value, max_value) if min_value is not None: min_node = rqet.SubElement(p_node, ns['resqml2'] + 'MinimumValue') min_node.set(ns['xsi'] + 'type', ns['xsd'] + collection.xsd_type) min_node.text = str(min_value) if max_value is not None: max_node = rqet.SubElement(p_node, ns['resqml2'] + 'MaximumValue') max_node.set(ns['xsi'] + 'type', ns['xsd'] + collection.xsd_type) max_node.text = str(max_value)
def __add_sub_elements_to_root_node(self, wbm_node): """Appends sub-elements to the WellboreMarkerFrame object's root node.""" nodeCount = rqet.SubElement(wbm_node, ns['resqml2'] + 'NodeCount') nodeCount.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') nodeCount.text = str(self.node_count) nodeMd = rqet.SubElement(wbm_node, ns['resqml2'] + 'NodeMd') nodeMd.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') nodeMd.text = rqet.null_xml_text md_values_node = rqet.SubElement(nodeMd, ns['resqml2'] + 'Values') md_values_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Hdf5Dataset') md_values_node.text = rqet.null_xml_text return nodeCount, nodeMd, md_values_node
def _create_hdf5_ext(model, add_as_part=True, root=None, title='Hdf Proxy', originator=None, file_name=None, uuid=None): """Creates an hdf5 external node and optionally adds as child of root and/or to parts forest.""" ext = _new_obj_node('EpcExternalPartReference', name_space='eml') assert ext is not None if uuid is not None: # preserve ext uuid if supplied ext.set('uuid', str(uuid)) _create_citation(root=ext, title=title, originator=originator) mime_type = rqet.SubElement(ext, ns['eml'] + 'MimeType') mime_type.set(ns['xsi'] + 'type', ns['xsd'] + 'string') mime_type.text = 'application/x-hdf5' if root is not None: root.append(ext) if add_as_part: ext_uuid = bu.uuid_from_string(ext.attrib['uuid']) model.add_part('obj_EpcExternalPartReference', ext_uuid, ext) if not file_name: file_name = model.h5_file_name(override='full', file_must_exist=False) elif os.sep not in file_name: file_name = os.path.join(model.epc_directory, file_name) assert file_name log.debug(f'creating ext part for hdf5 file: {file_name}') model.h5_dict[ext_uuid.bytes] = file_name if model.main_h5_uuid is None: model.main_h5_uuid = ext_uuid if model.rels_present and file_name: (uuid, rel_tree) = model.rels_forest[rqet.rels_part_name_for_part( rqet.part_name_for_object('obj_EpcExternalPartReference', ext_uuid))] assert (bu.matching_uuids(uuid, ext_uuid)) rel_node = rqet.SubElement(rel_tree.getroot(), ns['rels'] + 'Relationship') rel_node.set('Id', 'Hdf5File') rel_node.set('Type', ns_url['rels_ext'] + 'externalResource') rel_node.set('Target', file_name) rel_node.set('TargetMode', 'External') return ext
def __add_sub_elements_to_root_node(self, ds_node): """Appends sub-elements to the DeviationSurvey object's root node.""" if_node = rqet.SubElement(ds_node, ns['resqml2'] + 'IsFinal') if_node.set(ns['xsi'] + 'type', ns['xsd'] + 'boolean') if_node.text = str(self.is_final).lower() sc_node = rqet.SubElement(ds_node, ns['resqml2'] + 'StationCount') sc_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') sc_node.text = str(self.station_count) md_uom = rqet.SubElement(ds_node, ns['resqml2'] + 'MdUom') md_uom.set(ns['xsi'] + 'type', ns['eml'] + 'LengthUom') md_uom.text = bwam.rq_length_unit(self.md_uom) angle_uom = rqet.SubElement(ds_node, ns['resqml2'] + 'AngleUom') angle_uom.set(ns['xsi'] + 'type', ns['eml'] + 'PlaneAngleUom') if self.angles_in_degrees: angle_uom.text = 'dega' else: angle_uom.text = 'rad' mds = rqet.SubElement(ds_node, ns['resqml2'] + 'Mds') mds.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') mds.text = rqet.null_xml_text mds_values_node = rqet.SubElement(mds, ns['resqml2'] + 'Values') mds_values_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Hdf5Dataset') mds_values_node.text = rqet.null_xml_text azimuths = rqet.SubElement(ds_node, ns['resqml2'] + 'Azimuths') azimuths.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') azimuths.text = rqet.null_xml_text azimuths_values_node = rqet.SubElement(azimuths, ns['resqml2'] + 'Values') azimuths_values_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Hdf5Dataset') azimuths_values_node.text = rqet.null_xml_text inclinations = rqet.SubElement(ds_node, ns['resqml2'] + 'Inclinations') inclinations.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') inclinations.text = rqet.null_xml_text inclinations_values_node = rqet.SubElement(inclinations, ns['resqml2'] + 'Values') inclinations_values_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Hdf5Dataset') inclinations_values_node.text = rqet.null_xml_text return mds_values_node, azimuths_values_node, inclinations_values_node
def _create_ref_node(flavour, title, uuid, content_type=None, root=None): """Create a reference node, optionally add to root.""" assert uuid is not None if flavour.startswith('obj_'): flavour = flavour[4:] if not content_type: content_type = 'obj_' + flavour else: if content_type[0].isupper(): content_type = 'obj_' + content_type prefix = ns['eml'] if flavour == 'HdfProxy' else ns['resqml2'] ref_node = rqet.Element(prefix + flavour) ref_node.set(ns['xsi'] + 'type', ns['eml'] + 'DataObjectReference') ref_node.text = rqet.null_xml_text ct_node = rqet.SubElement(ref_node, ns['eml'] + 'ContentType') ct_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') if 'EpcExternalPartReference' in content_type: ct_node.text = 'application/x-eml+xml;version=2.0;type=' + content_type else: ct_node.text = 'application/x-resqml+xml;version=2.0;type=' + content_type if not title: title = '(title unavailable)' title_node = rqet.SubElement(ref_node, ns['eml'] + 'Title') title_node.set(ns['xsi'] + 'type', ns['eml'] + 'DescriptionString') title_node.text = title uuid_node = rqet.SubElement(ref_node, ns['eml'] + 'UUID') uuid_node.set(ns['xsi'] + 'type', ns['eml'] + 'UuidString') uuid_node.text = str(uuid) if use_version_string: version_str = rqet.SubElement( ref_node, ns['eml'] + 'VersionString') # I'm guessing what this is version_str.set(ns['xsi'] + 'type', ns['eml'] + 'NameString') version_str.text = bu.version_string(uuid) if root is not None: root.append(ref_node) return ref_node
def __create_wbt_node_geometry_sub_elements(self, wbt_node): """ Append sub-elements to the Trajectory object's root node that are related to well geometry.""" geom = rqet.SubElement(wbt_node, ns['resqml2'] + 'Geometry') geom.set(ns['xsi'] + 'type', ns['resqml2'] + 'ParametricLineGeometry') geom.text = '\n' # note: resqml standard allows trajectory to be in different crs to md datum # however, this module often uses the md datum crs, if the trajectory has been imported kc_node = rqet.SubElement(geom, ns['resqml2'] + 'KnotCount') kc_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') kc_node.text = str(self.knot_count) lki_node = rqet.SubElement(geom, ns['resqml2'] + 'LineKindIndex') lki_node.set(ns['xsi'] + 'type', ns['xsd'] + 'integer') lki_node.text = str(self.line_kind_index) cpp_node = rqet.SubElement(geom, ns['resqml2'] + 'ControlPointParameters') cpp_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') cpp_node.text = rqet.null_xml_text cpp_values_node = rqet.SubElement(cpp_node, ns['resqml2'] + 'Values') cpp_values_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset') cpp_values_node.text = rqet.null_xml_text cp_node = rqet.SubElement(geom, ns['resqml2'] + 'ControlPoints') cp_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dHdf5Array') cp_node.text = rqet.null_xml_text cp_coords_node = rqet.SubElement(cp_node, ns['resqml2'] + 'Coordinates') cp_coords_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset') cp_coords_node.text = rqet.null_xml_text if self.tangent_vectors is not None: tv_node = rqet.SubElement(geom, ns['resqml2'] + 'TangentVectors') tv_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dHdf5Array') tv_node.text = rqet.null_xml_text tv_coords_node = rqet.SubElement(tv_node, ns['resqml2'] + 'Coordinates') tv_coords_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset') tv_coords_node.text = rqet.null_xml_text else: tv_node = None tv_coords_node = None return geom, kc_node, lki_node, cpp_node, cpp_values_node, cp_node, cp_coords_node, tv_node, tv_coords_node
def create_xml(self, parent_node, title='wellbore marker'): """Creates the xml tree for this wellbore marker. arguments: parent_node (xml node): the root node of the WellboreMarkerFrame object to which the newly created node will be appended title (string, optional): the citation title of the newly created node note: if not None, self.title will be used instead of "wellbore marker" returns: the newly created xml node """ assert self.uuid is not None wbm_node = self.model.new_obj_node('WellboreMarker', is_top_lvl_obj=False) wbm_node.set('uuid', str(self.uuid)) # Citation block if self.title is not None: title = self.title citation = self.model.create_citation(root=wbm_node, title=title, originator=self.originator) # Add sub-elements to root node for k, v in WellboreMarker.boundary_feature_dict.items(): if self.marker_type in v: boundary_kind = k break wbm_gb_node = rqet.SubElement(wbm_node, ns['resqml2'] + boundary_kind) # wbm_gb_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') wbm_gb_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'GeologicBoundaryKind') wbm_gb_node.text = str(self.marker_type) if self.interpretation_uuid is not None: interp_content_type = 'obj_' + self.marker_type.capitalize( ) + 'Interpretation' interp_root = self.model.root_for_uuid( uuid=self.interpretation_uuid) self.model.create_ref_node( flavour='Interpretation', title=rqet.find_tag(rqet.find_tag(interp_root, 'Citation'), 'Title').text, uuid=self.interpretation_uuid, content_type=interp_content_type, root=wbm_node) # Extra metadata if hasattr(self, 'extra_metadata') and self.extra_metadata: rqet.create_metadata_xml(node=wbm_node, extra_metadata=self.extra_metadata) if parent_node is not None: parent_node.append(wbm_node) return wbm_node
def _create_xml_add_basics_to_p_node(collection, p_node, title, originator, extra_metadata, source, count, indexable_element): collection.model.create_citation(root=p_node, title=title, originator=originator) rqet.create_metadata_xml(node=p_node, extra_metadata=extra_metadata) if source is not None and len(source) > 0: collection.model.create_source(source=source, root=p_node) count_node = rqet.SubElement(p_node, ns['resqml2'] + 'Count') count_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') count_node.text = str(count) ie_node = rqet.SubElement(p_node, ns['resqml2'] + 'IndexableElement') ie_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'IndexableElements') ie_node.text = indexable_element
def create_xml(self, add_as_part = True, title = None, originator = None, reuse = True): """Create a RESQML time series xml node from a TimeSeries or GeologicTimeSeries object, optionally add as part. arguments: add_as_part (boolean, default True): if True, the newly created xml node is added as a part in the model title (string): used as the citation Title text for the new time series node originator (string, optional): the name of the human being who created the time series object; default is to use the login name returns: the newly created time series xml node :meta common: """ if reuse and self.try_reuse(): return self.root # check for reusable (equivalent) object if self.extra_metadata is None: self.extra_metadata = {} self.extra_metadata['timeframe'] = self.timeframe ts_node = super().create_xml(add_as_part = False, title = title, originator = originator) for index in range(self.number_of_timestamps()): time_node = rqet.SubElement(ts_node, ns['resqml2'] + 'Time') time_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Timestamp') time_node.text = rqet.null_xml_text dt_node = rqet.SubElement(time_node, ns['resqml2'] + 'DateTime') dt_node.set(ns['xsi'] + 'type', ns['xsd'] + 'dateTime') if self.timeframe == 'geologic': assert isinstance(self.timestamps[index], int) dt_node.text = '0000-01-01T00:00:00Z' yo_node = rqet.SubElement(time_node, ns['resqml2'] + 'YearOffset') yo_node.set(ns['xsi'] + 'type', ns['xsd'] + 'long') yo_node.text = str(self.timestamps[index]) else: dt_node.text = self.timestamp(index) if add_as_part: self.model.add_part('obj_TimeSeries', self.uuid, ts_node) return ts_node
def _create_source(source, root=None): """Create an extra meta data node holding information on the source of the data, optionally add to root.""" emd_node = rqet.Element(ns['resqml2'] + 'ExtraMetadata') emd_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'NameValuePair') emd_node.text = rqet.null_xml_text name_node = rqet.SubElement(emd_node, ns['resqml2'] + 'Name') name_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') name_node.text = 'source' value_node = rqet.SubElement(emd_node, ns['resqml2'] + 'Value') value_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') value_node.text = source if root is not None: root.append(emd_node) return emd_node
def __create_wbt_node_non_geometry_sub_elements(self, wbt_node): """ Append sub-elements to the Trajectory object's root node that are unrelated to well geometry.""" start_node = rqet.SubElement(wbt_node, ns['resqml2'] + 'StartMd') start_node.set(ns['xsi'] + 'type', ns['xsd'] + 'double') start_node.text = str(self.start_md) finish_node = rqet.SubElement(wbt_node, ns['resqml2'] + 'FinishMd') finish_node.set(ns['xsi'] + 'type', ns['xsd'] + 'double') finish_node.text = str(self.finish_md) md_uom = rqet.SubElement(wbt_node, ns['resqml2'] + 'MdUom') md_uom.set(ns['xsi'] + 'type', ns['eml'] + 'LengthUom') md_uom.text = bwam.rq_length_unit(self.md_uom) if self.md_domain: domain_node = rqet.SubElement(wbt_node, ns['resqml2'] + 'MdDomain') domain_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'MdDomain') domain_node.text = self.md_domain
def __create_xml_regandz(self, p_node, ext_uuid): assert ext_uuid is not None p_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dZValueArray') sg_node = rqet.SubElement(p_node, ns['resqml2'] + 'SupportingGeometry') sg_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dLatticeArray') sg_node.text = '\n' assert self.regular_origin is not None and self.regular_dxyz_dij is not None self.model.create_solitary_point3d( 'Origin', sg_node, self.regular_origin) # todo: check xml namespace for j_or_i in range( 2 ): # 0 = J, 1 = I; ie. J axis info first in xml, followed by I axis dxyz = self.regular_dxyz_dij[1 - j_or_i].copy() log.debug('dxyz: ' + str(dxyz)) d_value = vec.dot_product(dxyz, dxyz) assert d_value > 0.0 d_value = maths.sqrt(d_value) dxyz /= d_value o_node = rqet.SubElement(sg_node, ns['resqml2'] + 'Offset') o_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Point3dOffset') o_node.text = '\n' self.model.create_solitary_point3d('Offset', o_node, dxyz) space_node = rqet.SubElement(o_node, ns['resqml2'] + 'Spacing') space_node.set( ns['xsi'] + 'type', ns['resqml2'] + 'DoubleConstantArray') # nothing else catered for just now space_node.text = '\n' ov_node = rqet.SubElement(space_node, ns['resqml2'] + 'Value') ov_node.set(ns['xsi'] + 'type', ns['xsd'] + 'double') ov_node.text = str(d_value) oc_node = rqet.SubElement(space_node, ns['resqml2'] + 'Count') oc_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger') if j_or_i: oc_node.text = str(self.ni - 1) else: oc_node.text = str(self.nj - 1) zv_node = rqet.SubElement(p_node, ns['resqml2'] + 'ZValues') zv_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'DoubleHdf5Array') zv_node.text = '\n' v_node = rqet.SubElement(zv_node, ns['resqml2'] + 'Values') v_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset') v_node.text = '\n' self.model.create_hdf5_dataset_ref(ext_uuid, self.uuid, 'zvalues', root=v_node)
def _create_rels_part(model): """Adds a relationships reference node as a new part in the model's parts forest.""" rels = rqet.SubElement(model.main_root, ns['content_types'] + 'Default') rels.set('Extension', 'rels') rels.set('ContentType', 'application/vnd.openxmlformats-package.relationships+xml') model.rels_present = True model.set_modified() return rels
def _uom_node(root, uom): """Add a generic unit of measure sub element to root.""" assert root is not None and uom is not None and len(uom) # todo: could assert that uom is a valid unit of measure node = rqet.SubElement(root, ns['resqml2'] + 'UOM') node.set(ns['xsi'] + 'type', ns['resqml2'] + 'ResqmlUom') node.text = uom return node
def create_xml(self, title=None, originator=None, add_as_part=True, reuse=True): """Creates an xml node for the string table lookup. arguments: title (string, optional): if present, overrides the object's title attribute to be used as citation title originator (string, optional): if present, used as the citation creator (otherwise login name is used) add_as_part (boolean, default True): if True, the property set is added to the model as a part :meta common: """ if title: self.title = title if reuse and self.try_reuse(): return self.root # check for reusable (equivalent) object sl_node = super().create_xml(add_as_part=False, originator=originator) for k, v in self.str_dict.items(): pair_node = rqet.SubElement(sl_node, ns['resqml2'] + 'Value') pair_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'StringLookup') pair_node.text = rqet.null_xml_text key_node = rqet.SubElement(pair_node, ns['resqml2'] + 'Key') key_node.set(ns['xsi'] + 'type', ns['xsd'] + 'integer') key_node.text = str(k) value_node = rqet.SubElement(pair_node, ns['resqml2'] + 'Value') value_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') value_node.text = str(v) if add_as_part: self.model.add_part('obj_StringTableLookup', self.uuid, sl_node) return sl_node
def _create_citation(root=None, title='', originator=None): """Creates a citation xml node and optionally appends as a child of root.""" if not title: title = '(no title)' citation = rqet.Element(ns['eml'] + 'Citation') citation.set(ns['xsi'] + 'type', ns['eml'] + 'Citation') citation.text = rqet.null_xml_text title_node = rqet.SubElement(citation, ns['eml'] + 'Title') title_node.set(ns['xsi'] + 'type', ns['eml'] + 'DescriptionString') title_node.text = str(title) originator_node = rqet.SubElement(citation, ns['eml'] + 'Originator') if originator is None: try: originator = str(getpass.getuser()) except Exception: originator = 'unknown' originator_node.set(ns['xsi'] + 'type', ns['eml'] + 'NameString') originator_node.text = originator creation_node = rqet.SubElement(citation, ns['eml'] + 'Creation') creation_node.set(ns['xsi'] + 'type', ns['xsd'] + 'dateTime') creation_node.text = time.now() format_node = rqet.SubElement(citation, ns['eml'] + 'Format') format_node.set(ns['xsi'] + 'type', ns['eml'] + 'DescriptionString') if rqet.pretend_to_be_fesapi: format_node.text = '[F2I-CONSULTING:fesapi]' else: format_node.text = citation_format # todo: add optional description field if root is not None: root.append(citation) return citation
def create_xml(self, add_as_part=True, originator=None, reuse=True): """Create xml for this bespoke property kind.""" if reuse and self.try_reuse(): return self.root # check for reusable (equivalent) object pk = super().create_xml(add_as_part=False, originator=originator) ns_node = rqet.SubElement(pk, ns['resqml2'] + 'NamingSystem') ns_node.set(ns['xsi'] + 'type', ns['xsd'] + 'anyURI') ns_node.text = str(self.naming_system) ia_node = rqet.SubElement(pk, ns['resqml2'] + 'IsAbstract') ia_node.set(ns['xsi'] + 'type', ns['xsd'] + 'boolean') ia_node.text = str(self.is_abstract).lower() # note: schema definition requires this field, even for discrete property kinds uom = self.example_uom if uom is None: uom = 'Euc' ru_node = rqet.SubElement(pk, ns['resqml2'] + 'RepresentativeUom') ru_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'ResqmlUom') ru_node.text = str(uom) ppk_node = rqet.SubElement(pk, ns['resqml2'] + 'ParentPropertyKind') ppk_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'StandardPropertyKind') ppk_node.text = rqet.null_xml_text ppk_kind_node = rqet.SubElement(ppk_node, ns['resqml2'] + 'Kind') ppk_kind_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'ResqmlPropertyKind') ppk_kind_node.text = str(self.parent_kind) if add_as_part: self.model.add_part('obj_PropertyKind', self.uuid, pk) # no relationships at present, if local parent property kinds were to be supported then a rel. is needed there return pk
def create_xml(self, organization_feature_root = None, add_as_part = True, add_relationships = True, originator = None, title_suffix = None, reuse = True): """Creates an earth model interpretation organisational xml node from an earth model interpretation object.""" # note: related organization feature node should be created first and referenced here if not self.title: self.title = self.organization_feature.feature_name if title_suffix: self.title += ' ' + title_suffix if reuse and self.try_reuse(): return self.root emi = super().create_xml(add_as_part = False, originator = originator) if self.organization_feature is not None: of_root = self.organization_feature.root if of_root is not None: if organization_feature_root is None: organization_feature_root = of_root else: assert of_root is organization_feature_root, 'organization feature mismatch' assert organization_feature_root is not None, 'interpreted feature not established for model interpretation' assert self.domain in self.valid_domains, 'illegal domain value for earth model interpretation' dom_node = rqet.SubElement(emi, ns['resqml2'] + 'Domain') dom_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Domain') dom_node.text = self.domain self.model.create_ref_node('InterpretedFeature', self.model.title_for_root(organization_feature_root), organization_feature_root.attrib['uuid'], content_type = 'obj_OrganizationFeature', root = emi) create_xml_has_occurred_during(self.model, emi, self.has_occurred_during) if add_as_part: self.model.add_part('obj_EarthModelInterpretation', self.uuid, emi) if add_relationships: self.model.create_reciprocal_relationship(emi, 'destinationObject', organization_feature_root, 'sourceObject') return emi
def create_xml_has_occurred_during(model, parent_node, hod_pair, tag = 'HasOccuredDuring'): """Creates XML sub-tree 'HasOccuredDuring' node""" if hod_pair is None: return base_chrono_uuid, top_chrono_uuid = hod_pair if base_chrono_uuid is None or top_chrono_uuid is None: return hod_node = rqet.SubElement(parent_node, tag) hod_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'TimeInterval') hod_node.text = rqet.null_xml_text chrono_base_root = model.root_for_uuid(base_chrono_uuid) chrono_top_root = model.root_for_uuid(top_chrono_uuid) model.create_ref_node('ChronoBottom', model.title_for_root(chrono_base_root), base_chrono_uuid, root = hod_node) model.create_ref_node('ChronoTop', model.title_for_root(chrono_top_root), top_chrono_uuid, root = hod_node)
def _create_xml_property_kind(collection, p_node, find_local_property_kinds, property_kind, uom, discrete, property_kind_uuid): p_kind_node = rqet.SubElement(p_node, ns['resqml2'] + 'PropertyKind') p_kind_node.text = rqet.null_xml_text if find_local_property_kinds and property_kind not in supported_property_kind_list: property_kind_uuid = pcga._get_property_kind_uuid( collection, property_kind_uuid, property_kind, uom, discrete) if property_kind_uuid is None: p_kind_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'StandardPropertyKind') # todo: local prop kind ref kind_node = rqet.SubElement(p_kind_node, ns['resqml2'] + 'Kind') kind_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'ResqmlPropertyKind') kind_node.text = property_kind else: p_kind_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'LocalPropertyKind') # todo: local prop kind ref collection.model.create_ref_node('LocalPropertyKind', property_kind, property_kind_uuid, content_type='obj_PropertyKind', root=p_kind_node)
def create_xml(self, add_as_part=True, add_relationships=True, title=None, originator=None): """Creates xml for a measured depth datum element; crs node must already exist; optionally adds as part. arguments: add_as_part (boolean, default True): if True, the newly created xml node is added as a part in the model add_relationships (boolean, default True): if True, a relationship xml part is created relating the new md datum part to the crs title (string): used as the citation Title text for the new md datum node originator (string, optional): the name of the human being who created the md datum part; default is to use the login name returns: the newly created measured depth datum xml node """ md_reference = self.md_reference.lower() assert md_reference in valid_md_reference_list, 'invalid measured depth reference: ' + md_reference if title: self.title = title if not self.title: self.title = 'measured depth datum' crs_uuid = self.crs_uuid assert crs_uuid is not None datum = super().create_xml(add_as_part=False, originator=originator) self.model.create_solitary_point3d('Location', datum, self.location) md_ref = rqet.SubElement(datum, ns['resqml2'] + 'MdReference') md_ref.set(ns['xsi'] + 'type', ns['resqml2'] + 'MdReference') md_ref.text = md_reference self.model.create_crs_reference(crs_uuid=crs_uuid, root=datum) if add_as_part: self.model.add_part('obj_MdDatum', self.uuid, datum) if add_relationships: crs_root = self.model.root_for_uuid(self.crs_uuid) self.model.create_reciprocal_relationship( datum, 'destinationObject', crs_root, 'sourceObject') return datum
def create_xml(self, add_as_part=True, add_relationships=True, originator=None, reuse=True): """Creates a rock fluid unit feature organisational xml node from this rock fluid unit feature object.""" assert self.feature_name and self.phase and self.top_boundary_feature and self.base_boundary_feature if self.phase not in self.valid_phases: raise ValueError(f"Phase '{self.phase}' not recognized") if reuse and self.try_reuse(): return self.root # check for reusable (equivalent) object # create node with citation block rfuf = super().create_xml(add_as_part=False, originator=originator) phase_node = rqet.SubElement(rfuf, ns['resqml2'] + 'Phase') phase_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'Phase') phase_node.text = self.phase top_boundary_root = self.top_boundary_feature.root assert top_boundary_root is not None self.model.create_ref_node( 'FluidBoundaryTop', self.model.title_for_root(top_boundary_root), top_boundary_root.attrib['uuid'], content_type='obj_BoundaryFeature', root=rfuf) base_boundary_root = self.base_boundary_feature.root assert base_boundary_root is not None self.model.create_ref_node( 'FluidBoundaryBottom', self.model.title_for_root(base_boundary_root), base_boundary_root.attrib['uuid'], content_type='obj_BoundaryFeature', root=rfuf) if add_as_part: self.model.add_part('obj_RockFluidUnitFeature', self.uuid, rfuf) if add_relationships: self.model.create_reciprocal_relationship( rfuf, 'destinationObject', top_boundary_root, 'sourceObject') self.model.create_reciprocal_relationship( rfuf, 'destinationObject', base_boundary_root, 'sourceObject') return rfuf