Ejemplo n.º 1
0
 def nsmap(self):
     """
     Return the source's nsmap
     :return: dict - The source's nsmap
     """
     nsmap = HDict(json.loads(self.namespaces))
     return nsmap
Ejemplo n.º 2
0
 def cim_version(self):
     """
     Return the source's cim_version
     :return: str - The source's cim version
     """
     nsmap = HDict(json.loads(self.namespaces))
     return _get_cimrdf_version(nsmap["cim"])
Ejemplo n.º 3
0
def get_nsmap(sources: frozenset):
    """
    Return the merged namespace map for a list of data sources
    :param sources: frozenset of DataSource objects (so its hashable)
    :return: dict, merged nsmap of all DataSource objects
    """
    nsmaps = [source.nsmap for source in sources]
    nsmaps = {k: v for d in nsmaps for k, v in d.items()}
    return HDict(nsmaps)
Ejemplo n.º 4
0
def dummy_nsmap():
    from cimpyorm.auxiliary import HDict
    nsmap = HDict({
        'cim': 'http://iec.ch/TC57/2013/CIM-schema-cim16#',
        'entsoe': 'http://entsoe.eu/CIM/SchemaExtension/3/1#',
        'md': 'http://iec.ch/TC57/61970-552/ModelDescription/1#',
        'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
    })
    return nsmap
Ejemplo n.º 5
0
def merge_sources(sources):
    d_ = defaultdict(dict)
    from lxml.etree import XPath
    xp = {
        "id": XPath("@rdf:ID", namespaces=get_nsmap(sources)),
        "about": XPath("@rdf:about", namespaces=get_nsmap(sources))
    }
    for source in sources:
        for element in source.tree.getroot():
            try:
                uuid = determine_uuid(element, xp)
                classname = shorten_namespace(element.tag,
                                              HDict(get_nsmap(sources)))
                if classname not in d_ or uuid not in d_[classname].keys():
                    d_[classname][uuid] = element
                else:
                    [d_[classname][uuid].append(sub) for sub in element]  # pylint: disable=expression-not-assigned
            except ValueError:
                log.warning(f"Skipped element during merge: {element}.")
    return d_
Ejemplo n.º 6
0
 def _init_parser(self):
     SchemaElement.nsmap = HDict(self.root.nsmap)
     for c in self.Element_classes.values():
         c._generateXPathMap()
Ejemplo n.º 7
0
def merge_sources(sources, model_schema=None):
    """
    Merge different sources of CIM datasets (usually the different profiles, but could also be
    multiple instances of the same profile when multiple datasets are merged via boundary datasets)

    :param sources: SourceInfo objects of the source files.
    :param model_schema: The schema used to deserialize the dataset.

    :return: A dictionary of the objects found in the dataset, keyed by classname and object uuid.
    """
    uuid2name = dict()
    uuid2data = dict()

    classname_list = defaultdict(set)

    from cimpyorm.auxiliary import XPath
    xp = {
        "id": XPath("@rdf:ID", namespaces=get_nsmap(sources)),
        "about": XPath("@rdf:about", namespaces=get_nsmap(sources))
    }
    for source in sources:
        for element in source.tree.getroot():
            try:
                uuid = determine_uuid(element, xp)
                classname = shorten_namespace(element.tag,
                                              HDict(get_nsmap(sources)))

                # Set the classname only when UUID is attribute
                try:
                    uuid = xp["id"](element)[0]
                    if uuid in uuid2name and uuid2name[uuid] != classname:
                        # If multiple objects of different class share the same uuid, raise an Error
                        raise ReferenceError(
                            f"uuid {uuid}={classname} already defined as {uuid2name[uuid]}"
                        )

                    uuid2name[uuid] = classname
                except IndexError:
                    pass

                classname_list[uuid] |= {classname}

                if uuid not in uuid2data:
                    uuid2data[uuid] = element
                else:
                    [uuid2data[uuid].append(sub) for sub in element]  # pylint: disable=expression-not-assigned
            except ValueError:
                log.warning(f"Skipped element during merge: {element}.")

    # print warning in case uuid references use different classnames
    for uuid, name_set in classname_list.items():
        if len(name_set) > 1:
            log.warning(
                f"Ambiguous classnames for {uuid} of type {uuid2name.get(uuid, None)} = {name_set}"
            )

    # check that the class is the most specific one in the list
    if model_schema is not None:
        schema_classes = model_schema.get_classes()
        for uuid, classname in uuid2name.items():
            try:
                cls = schema_classes[classname]
            except KeyError:
                log.info(
                    f"Class {classname} is not included in schema. Objects of this class are not deserialized."
                )
            else:
                try:
                    if not all(
                            issubclass(cls, schema_classes[_cname])
                            for _cname in classname_list[uuid]):
                        raise ValueError(
                            f"Class {classname} is not most specific of {classname_list[uuid]}."
                        )
                except KeyError as ex:
                    raise ReferenceError(
                        f"Malformed schema. Class-hierarchy-element is missing: {ex}."
                    )

    # transform the data into output structure
    d_ = defaultdict(dict)
    for uuid, classname in uuid2name.items():
        d_[classname][uuid] = uuid2data[uuid]

    return d_
Ejemplo n.º 8
0
 def _init_parser(self, nsmap):
     ElementMixin.nsmap = HDict(nsmap)  # Set the nsmap on the Baseclass.
     for c in self.Element_classes.values():
         c._generateXPathMap()