Import a STIX or CybOX xml  from file <filepath> or a string passed as ``xml_content``

         You can furhter provide:

         - a list of InfoObjects as markings with which all generated Information Objects
            will be associated (e.g., in order to provide provenance function)
         - a default identifier namespace URI.

         The kwargs are not read -- they are present to allow the use of the
         DingoImportCommand class for easy definition of commandline import commands
         (the class passes all command line arguments to the xml_import function, so
         without the **kwargs parameter, an error would occur.

def xml_import(self,
                   filepath="",
                   xml_content=None,
                   markings=None,
                   identifier_ns_uri=None,
                   **kwargs):
        """
         Import a STIX or CybOX xml  from file <filepath> or a string passed as ``xml_content``

         You can furhter provide:

         - a list of InfoObjects as markings with which all generated Information Objects
            will be associated (e.g., in order to provide provenance function)
         - a default identifier namespace URI.

         The kwargs are not read -- they are present to allow the use of the
         DingoImportCommand class for easy definition of commandline import commands
         (the class passes all command line arguments to the xml_import function, so
         without the **kwargs parameter, an error would occur.
         """

        # Clear internal state such that same object can be reused for
        # multiple imports.


        if 'default_timestamp' in kwargs and kwargs['default_timestamp']:

            if isinstance(kwargs['default_timestamp'],basestring):
                naive = parse_datetime(kwargs['default_timestamp'])
            else:
                naive = kwargs['default_timestamp']
            if not timezone.is_aware(naive):
                aware = timezone.make_aware(naive,timezone.utc)
            else:
                aware = naive
            self.default_timestamp = aware


        self.namespace_dict = {None: DINGOS_NAMESPACE_URI}

        self.default_identifier_ns_uri = None

        self.default_identifier_ns_uri = identifier_ns_uri

        if not markings:
            markings = []





        # Use the generic XML import customized for STIX/CybOX import
        # to turn XML into DingoObjDicts

        import_result = MantisImporter.xml_import(xml_fname=filepath,
                                                  xml_content=xml_content,
                                                  ns_mapping=self.namespace_dict,
                                                  embedded_predicate=self.stix_embedding_pred,
                                                  id_and_revision_extractor=self.id_and_revision_extractor)





        # The MANTIS/DINGOS xml importer returns then the following structure::
        #
        #
        #    {'id_and_rev_info': Id and revision info of top-level element of the form
        #        {'id': ... , 'timestamp': ...}
        #    'elt_name': Element name of top-level element
        #    'dict_repr': Dictionary representation of XML, minus the embedded objects -- for
        #                 those, an 'idref' reference has been generated
        #    'embedded_objects': List of embedded objects, as dictionary
        #                       {"id_and_revision_info": id and revision info of extracted object,
        #                        "elt_name": Element name,
        #                        "dict_repr" :  dictionary representation of XML of embedded object
        #                       }
        #    'unprocessed' : List of unprocessed embedded objects (as libxml2 Node object)
        #                    (e.g. for handover to other importer
        #    'file_content': Content of imported file (or, if content was passed instead of a file name,
        #                                                                                         the original content)}


        # Extract information from import result

        top_level_id_and_rev_info = import_result['id_and_rev_info']
        top_level_elt_name = import_result['elt_name']
        top_level_elt_dict = import_result['dict_repr']
        file_content = import_result['file_content']
        embedded_objects = import_result['embedded_objects']
        unprocessed_list = import_result['unprocessed']


        if not 'id' in top_level_id_and_rev_info or not top_level_id_and_rev_info['id']:
            if self.default_identifier_ns_uri:
                # Top-level element had no identifier. If a default namespace has been provided,
                # then an identifier is generated
                top_level_id_and_rev_info['id_ns'] = self.default_identifier_ns_uri
                top_level_id_and_rev_info['id_uid'] = hashlib.md5(file_content).hexdigest()
                logger.info("Top level element had no identifier: "
                            "identifier %s has been generated " % top_level_id_and_rev_info['id_uid'])

            else:
                logger.warning("Top level element had no identifier. "
                    "No identifier was generated, because no default namespace had been provided "
                    "(you can provide a namespace with the '-n' commandline parameter")

        # We now have the top-level object, the list of embedded objects,
        # and possibly a list of hitherto unprocessed XML nodes.
        # As we shall see below, we have configured the DINGOS
        # XML  importer such that it extracts marking structures
        # as separate objects and tags them with a label
        # 'import_first'. So, what we need to do is to go through
        # the embedded objects and collect all markings (along with
        # information, in which STIX_Package each marking was defined).
        # This allows us to first create all marking objects and
        # then mark the subsequently created objects with the
        # appropriate markings.
        # Note, that currently,
        # - we only extract and treat markings defined in the header of STIX_Package
        # - we do not care about the XPATH-expression and treat every marking as if
        #   it was defined for the whole STIX-Package

        marking_dict = {}

        # We use queues rather than lists, since we have no need
        # to access elements somewhere in the list, but rather
        # always pop from the end

        import_first_queue = deque()

        pending_queue = deque()

        # The top-level object is certainly no marking, so we
        # put it on the pending queue

        pending_queue.append((top_level_id_and_rev_info, top_level_elt_name, top_level_elt_dict))

        while embedded_objects:
            # We go through the embedded objects and look for the 'import_first' label
            embedded_object = embedded_objects.pop()
            id_and_rev_info = embedded_object['id_and_rev_info']
            elt_name = embedded_object['elt_name']
            elt_dict = embedded_object['dict_repr']
            if 'import_first' in id_and_rev_info:
                import_first_queue.append((id_and_rev_info, elt_name, elt_dict))
            else:
                pending_queue.append((id_and_rev_info, elt_name, elt_dict))


        while import_first_queue:
            # We go through the import_first queue, import all markings,
            # and collect information about the STIX_Package in which the marking
            # was defined in the marking_dict (some organizations use a format
            # in which several STIX Packages are bundled into a single XML file).

            (id_and_rev_info, elt_name, elt_dict) = import_first_queue.pop()


            (info_obj, existed) = self.iobject_import(id_and_rev_info,
                                                      elt_name,
                                                      elt_dict)

            # id_and_rev_info can carries additional information other than the identifier
            # and timestamp that has been extracted: the MANTIS XML importer carries
            # along information inherited from ancestor objects: this allows us
            # to propagate information down to children, grandchildren etc. As we
            # see below, we use this mechanism to propagate information about
            # the STIX_Package in which an object was defined.

            if id_and_rev_info['inherited']['embedding_STIX_Package'] in marking_dict:
                marking_dict[id_and_rev_info['inherited']['embedding_STIX_Package']].append(info_obj)
            else:
                marking_dict[id_and_rev_info['inherited']['embedding_STIX_Package']] = [info_obj]


        while pending_queue:
            # Now we start the import of the remaining embedded objects (plus the top-level object)

            (id_and_rev_info, elt_name, elt_dict) = pending_queue.pop()

            if 'embedding_STIX_Package' in id_and_rev_info:
                embedding_STIX_Package = id_and_rev_info['embedding_STIX_Package']
            else:
                embedding_STIX_Package = id_and_rev_info.get('inherited',{}).get('embedding_STIX_Package')

            logger.debug("%s embedded in %s" % (id_and_rev_info['id'], embedding_STIX_Package))


            if elt_name in ['Kill_Chain','Kill_Chain_Phase']:
                # We chose not to attach markings to Kill_Chain information
                object_markings = []
            else:
                # We mark the object with markings passed to the xml_import command
                # and markings defined in the STIX_Package in which the object was defined.

                object_markings = markings + marking_dict.get(embedding_STIX_Package,[])

            self.iobject_import(id_and_rev_info,
                                elt_name,
                                elt_dict,
                                markings=object_markings)

        # As we shall see below, we have configured the xml_importer such that
        # it recognizes OpenIOC structures embedded as test mechanism and
        # leaves them unprocessed. These unprocessed elements we now hand
        # over to the MANTIS OpenIOC importer.

        for unprocessed_elt in unprocessed_list:
            (id_and_rev_info,typeinfo,xml_node) = unprocessed_elt
            processor_class = self.processors.get(id_and_rev_info['defer_processing']['processor'],None)


            if 'embedding_STIX_Package' in id_and_rev_info:
                embedding_STIX_Package = id_and_rev_info['embedding_STIX_Package']
            else:
                embedding_STIX_Package = id_and_rev_info.get('inherited',{}).get('embedding_STIX_Package')

            logger.debug("%s embedded in %s" % (id_and_rev_info['id'], embedding_STIX_Package))

            object_markings = markings + marking_dict.get(embedding_STIX_Package,[])

            if processor_class:

                processor = processor_class(namespace_dict=self.namespace_dict)

                processor.xml_import(self,
                                     xml_content=xml_node,
                                     markings=object_markings,
                                     identifier_ns_uri=self.namespace_dict[id_and_rev_info['id'].split(':')[0]],
                                     initialize_importer=False
                )
            else:
                logger.error("Did not find a processor for %s" % id_and_rev_info['defer_processing']['processor'])