def _component(reader, elem): try: # May be a reference return Reference(elem) except NotReference: pass # Object class: {,Measure,Time}Dimension or DataAttribute cls = class_for_tag(elem.tag) args = dict( concept_identity=reader.pop_resolved_ref("ConceptIdentity"), local_representation=reader.pop_single(model.Representation), ) try: args["order"] = int(elem.attrib["position"]) except KeyError: pass # DataAttribute only ar = reader.pop_all(model.AttributeRelationship) if len(ar): assert len(ar) == 1 args["related_to"] = ar[0] return reader.identifiable(cls, elem, **args)
def _item(reader, elem): try: # <str:DataProvider> may be a reference, e.g. in <str:ConstraintAttachment> return Reference(elem) except NotReference: pass cls = class_for_tag(elem.tag) item = reader.nameable(cls, elem) # Hierarchy is stored in two ways # (1) XML sub-elements of the parent. These have already been parsed. for e in elem: if e.tag == elem.tag: # Found 1 child XML element with same tag → claim 1 child object item.append_child(reader.pop_single(cls)) # (2) through <str:Parent> parent = reader.pop_resolved_ref("Parent") if parent: parent.append_child(item) # Agency only try: item.contact = reader.pop_all(model.Contact) except ValueError: # NB this is a ValueError from pydantic, rather than AttributeError from Python pass reader.unstash() return item
def _ref(reader, elem): cls_hint = None if "Parent" in elem.tag: # Use the *grand*-parent of the <Ref> or <URN> for a class hint cls_hint = class_for_tag(elem.getparent().tag) reader.push(QName(elem).localname, Reference(elem, cls_hint))
def _message(reader, elem): """Start of a Message.""" # <mes:Structure> within <mes:Header> of a data message is handled by # _header_structure() below. if getattr(elem.getparent(), "tag", None) == qname("mes", "Header"): return ss_without_dsd = False # With 'dsd' argument, the message should be structure-specific if ( "StructureSpecific" in elem.tag and reader.get_single(model.DataStructureDefinition) is None ): log.warning(f"sdmxml.Reader got no dsd=… argument for {QName(elem).localname}") ss_without_dsd = True # The following seems to only confuse users. # Thus it is commented out post v1.1.0 # elif "StructureSpecific" not in elem.tag and reader.get_single( # model.DataStructureDefinition # log.warning("Ambiguous: dsd=… argument for non–structure-specific message") # Store values for other methods reader.push("SS without DSD", ss_without_dsd) if "Data" in elem.tag: reader.push("DataSetClass", model.get_class(f"{QName(elem).localname}Set")) # Instantiate the message object cls = class_for_tag(elem.tag) return cls()
def _key(reader, elem): cls = class_for_tag(elem.tag) kv = {e.attrib["id"]: e.attrib["value"] for e in elem.iterchildren()} dsd = reader.get_single("DataSet").structured_by return dsd.make_key(cls, kv, extend=True)
def _itemscheme(reader, elem): cls = class_for_tag(elem.tag) # Iterate over all Item objects *and* their children iter_all = chain(*[iter(item) for item in reader.pop_all(cls._Item)]) # Set of objects already added to `items` seen = dict() # Flatten the list, with each item appearing only once items = [seen.setdefault(i, i) for i in iter_all if i not in seen] return reader.maintainable(cls, elem, items=items)
def _cl(reader, elem): try: # <str:Group> may be a reference return Reference(elem, cls_hint=model.GroupDimensionDescriptor) except NotReference: pass # Retrieve the DSD dsd = reader.peek(model.DataStructureDefinition) assert dsd is not None # Retrieve the components args = dict(components=reader.pop_all(model.Component)) # Determine the class localname = QName(elem).localname if localname == "Group": cls = model.GroupDimensionDescriptor # Replace components with references args["components"] = [ dsd.dimensions.get(ref.target_id) for ref in reader.pop_all("DimensionReference") ] else: # SDMX-ML spec for, e.g. DimensionList: "The id attribute is # provided in this case for completeness. However, its value is # fixed to 'DimensionDescriptor'." cls = class_for_tag(elem.tag) args["id"] = elem.attrib.get("id", cls.__name__) cl = reader.identifiable(cls, elem, **args) try: # DimensionDescriptor only cl.assign_order() except AttributeError: pass # Assign to the DSD eagerly (instead of in _dsd_end()) for reference by next # ComponentList e.g. so that AttributeRelationship can reference the # DimensionDescriptor attr = { model.DimensionDescriptor: "dimensions", model.AttributeDescriptor: "attributes", model.MeasureDescriptor: "measures", model.GroupDimensionDescriptor: "group_dimensions", }.get(cl.__class__) if attr == "group_dimensions": getattr(dsd, attr)[cl.id] = cl else: setattr(dsd, attr, cl)
def _header_org(reader, elem): reader.push(elem, reader.nameable(class_for_tag(elem.tag), elem))
def __init__(self, elem, cls_hint=None): parent_tag = elem.tag try: # Use the first child elem = elem[0] except IndexError: raise NotReference # Extract information from the XML element if elem.tag == "Ref": # Element attributes give target_id, id, and version target_id = elem.attrib["id"] agency_id = elem.attrib.get("agencyID", None) id = elem.attrib.get("maintainableParentID", target_id) version = elem.attrib.get( "maintainableParentVersion", None ) or elem.attrib.get("version", None) # Attributes of the element itself, if any args = (elem.attrib.get("class", None), elem.attrib.get("package", None)) elif elem.tag == "URN": match = pandasdmx.urn.match(elem.text) # If the URN doesn't specify an item ID, it is probably a reference to a # MaintainableArtefact, so target_id and id are the same target_id = match["item_id"] or match["id"] agency_id = match["agency"] id = match["id"] version = match["version"] args = (match["class"], match["package"]) else: raise NotReference # Find the target class target_cls = model.get_class(*args) if target_cls is None: # Try the parent tag name target_cls = class_for_tag(parent_tag) if cls_hint and (target_cls is None or issubclass(cls_hint, target_cls)): # Hinted class is more specific than target_cls, or failed to find a target # class above target_cls = cls_hint self.maintainable = issubclass(target_cls, model.MaintainableArtefact) if self.maintainable: # MaintainableArtefact is the same as the target cls, id = target_cls, target_id else: # Get the class for the parent MaintainableArtefact cls = model.parent_class(target_cls) # Store self.cls = cls self.agency = model.Agency(id=agency_id) if agency_id else _NO_AGENCY self.id = id self.version = version self.target_cls = target_cls self.target_id = target_id