def WMapToHtml(theMap, propData):
     sys.stderr.write("WMapToHtml len=%d\n" % len(theMap))
     for urlSubj in theMap:
         (subjText, subjEntityGraphClass,
          subjEntityId) = lib_naming.ParseEntityUri(
              lib_util.urllib_unquote(urlSubj))
         WrtAsUtf("<tr>")
         WrtAsUtf("<td valign='top'><a href='%s'>%s</a></td>" %
                  (str(urlSubj), subjText))
         WrtAsUtf("<td>")
         WrtAsUtf("<table>")
         for theProp, urlObj in theMap[urlSubj]:
             WrtAsUtf("<tr>")
             propNam = lib_exports.PropToShortPropNam(theProp)
             WrtAsUtf("<td><i>%s</i></td>" % propNam)
             if lib_kbase.IsLiteral(urlObj):
                 WrtAsUtf("<td>%s</td>" % (str(urlObj)))
             else:
                 (objText, objEntityGraphClass,
                  objEntityId) = lib_naming.ParseEntityUri(
                      lib_util.urllib_unquote(urlObj))
                 WrtAsUtf("<td><a href='%s'>%s</a></td>" %
                          (str(urlObj), objText))
             WrtAsUtf("</tr>")
         WrtAsUtf("</table>")
         WrtAsUtf("</td>")
     WrtAsUtf("</tr>")
Exemple #2
0
 def WMapToHtml(theMap):
     DEBUG("WMapToHtml len=%d", len(theMap))
     for urlSubj in theMap:
         (subjText, subjEntityGraphClass,
          subjEntityId) = lib_naming.ParseEntityUri(
              lib_util.urllib_unquote(urlSubj))
         yield ("<tr>")
         yield ("<td valign='top'><a href='%s'>%s</a></td>" %
                (str(urlSubj), subjText))
         yield ("<td>")
         yield ("<table border=0>")
         for theProp, urlObj in theMap[urlSubj]:
             yield ("<tr>")
             propNam = lib_exports.PropToShortPropNam(theProp)
             yield ("<td><i>%s</i></td>" % propNam)
             if lib_kbase.IsLiteral(urlObj):
                 yield ("<td>%s</td>" % (str(urlObj)))
             else:
                 (objText, objEntityGraphClass,
                  objEntityId) = lib_naming.ParseEntityUri(
                      lib_util.urllib_unquote(urlObj))
                 yield ("<td><a href='%s'>%s</a></td>" %
                        (str(urlObj), objText))
             yield ("</tr>")
         yield ("</table>")
         yield ("</td>")
     yield ("</tr>")
 def w_map_to_html(the_map):
     """This callback receives a RDF property (WBEM or WMI) and a map
     which represents the CIM links associated to the current object. """
     logging.debug("w_map_to_html len=%d", len(the_map))
     for url_subj in the_map:
         unquoted_subj = lib_util.urllib_unquote(url_subj)
         subj_text, subj_entity_graph_class, subj_entity_id = lib_naming.ParseEntityUri(
             unquoted_subj)
         yield "<tr>"
         yield "<td valign='top'><a href='%s'>%s</a></td>" % (str(url_subj),
                                                              subj_text)
         yield "<td>"
         yield "<table border=0>"
         for the_prop, url_obj in the_map[url_subj]:
             yield "<tr>"
             prop_nam = lib_exports.PropToShortPropNam(the_prop)
             yield "<td><i>%s</i></td>" % prop_nam
             if lib_kbase.IsLiteral(url_obj):
                 yield "<td>%s</td>" % str(url_obj)
             else:
                 unquoted_obj = lib_util.urllib_unquote(url_obj)
                 obj_text, obj_entity_graph_class, obj_entity_id = lib_naming.ParseEntityUri(
                     unquoted_obj)
                 yield "<td><a href='%s'>%s</a></td>" % (str(url_obj),
                                                         obj_text)
             yield "</tr>"
         yield "</table>"
         yield "</td>"
     yield "</tr>"
Exemple #4
0
    def make_universal_alias_no_cache(an_object):
        # It is a rdflib.term.URIRef
        # The prefix of the URL which contain the host name,
        # maybe with a port number, maybe with a WBEM prefix, WMI machine, CGI script etc...
        # is simply replaced by the IP address of the machine.
        # The resulting string is the same for all servers running on the same machine.
        an_object_as_str = str(an_object)
        parsed_url = lib_util.survol_urlparse(an_object_as_str)
        # netloc=u'desktop-ni99v8e:8000'
        entity_host = parsed_url.netloc.split(":")[0]

        # FIXME: This is very slow.
        if False:
            try:
                # Might throw: socket.gaierror: [Errno 11004] getaddrinfo failed with "entity_host=desktop-ni99v8e"
                entity_ip_addr = lib_util.GlobalGetHostByName(entity_host)
            except:
                entity_ip_addr = entity_host
        else:
            entity_ip_addr = entity_host

        # RFC4343: Hostname are case-insensitive.
        entity_ip_addr = entity_ip_addr.lower()

        # TODO: Many things are calculated several times.
        lab_text, subj_entity_graphic_class, entity_id = lib_naming.ParseEntityUri(
            an_object_as_str,
            long_display=True,
            force_entity_ip_addr=entity_ip_addr)

        return lab_text
Exemple #5
0
    def MakeUniversalAliasNoCache(anObj):
        # The prefix of the URL which contain the host name,
        # maybe with a port number, maybe with a WBEM prefix, WMI machine,
        # CGI script etc...
        # is simply replaced by the IP address of the machine.
        # The resulting string is the same for all servers
        # running on the same machine.
        parsed_url = lib_util.survol_urlparse(anObject)
        #sys.stderr.write("MakeUniversalAliasNoCache parsed_url=%s\n"%str(parsed_url))
        # netloc=u'desktop-ni99v8e:8000'
        entity_host = parsed_url.netloc.split(":")[0]
        #sys.stderr.write("MakeUniversalAliasNoCache entity_host=%s\n"%str(entity_host))

        # FIXME: This is very slow.
        if False:
            try:
                # Might throw: socket.gaierror: [Errno 11004] getaddrinfo failed with "entity_host=desktop-ni99v8e"
                entity_ip_addr = lib_util.GlobalGetHostByName(entity_host)
            except:
                entity_ip_addr = entity_host
        else:
            entity_ip_addr = entity_host

        # RFC4343: Hostname are case-insensitive.
        entity_ip_addr = entity_ip_addr.lower()

        # TODO: Many things are calculated several times.
        (labText, subjEntityGraphicClass,
         entity_id) = lib_naming.ParseEntityUri(
             anObject, longDisplay=True, force_entity_ip_addr=entity_ip_addr)

        # sys.stderr.write("MakeUniversalAliasNoCache anObject=%s labText=%s\n"%(str(anObject),labText))
        return labText
Exemple #6
0
def external_url_to_title(ext_url):
    """Returns a string for an URL which might be different from "entity.py" etc...
    Depending on where it comes from, "%2F" instead of "/" ... ugly.
    BEWARE: This is completely experimental. See if "Yawn" is actually used."""
    if re.match( ".*/yawn/.*", ext_url) or re.match(".*%2Fyawn%2F.*", ext_url):
        return "Yawn"

    py_nam_mtch = re.match( ".*/([^.]+).py.*", ext_url)
    if py_nam_mtch:
        py_nam = py_nam_mtch.group(1)

        # After all, the script might be entity
        if py_nam == "entity":
            obj_nam, entity_graphic_class, entity_id = lib_naming.ParseEntityUri(ext_url)
            return obj_nam

        try:
            # TODO: See lib_naming.scripts_to_titles
            basNamToTxt = {
                "objtypes_wbem": "Subtypes", # This key is duplicated !!!!
                "file_directory": "Subdir",
                "file_to_mime": "MIME",
                "objtypes_wmi": "WMI tree",
                "objtypes_wbem": "WBEM hier.",
                "class_type_all": "Cross class",
                "dir_to_html": "DIR"
            }
            return basNamToTxt[py_nam]
        except:
            return py_nam.replace("_", " ").capitalize()
    else:
        return "Literal:" + ext_url
Exemple #7
0
    def __init__(self, rdf_node):
        global NodeJsonNumber
        subj_str = str(rdf_node)

        (entity_label, entity_graphic_class,
         entity_id) = lib_naming.ParseEntityUri(subj_str,
                                                longDisplay=False,
                                                force_entity_ip_addr=None)

        self.m_label = entity_label.strip()
        self.m_class = entity_graphic_class

        arrayGraphParams = lib_patterns.TypeToGraphParams(self.m_class)

        # "Graphic_shape","Graphic_colorfill","Graphic_colorbg","Graphic_border","Graphic_is_rounded"
        self.m_color = arrayGraphParams[1]

        # TODO: Display the doc in the module with FromModuleToDoc(importedMod,filDfltText):
        self.m_info_list = [entity_graphic_class]
        self.m_info_dict = dict()
        self.m_index = NodeJsonNumber

        the_survol_url = lib_util.survol_HTMLParser().unescape(rdf_node)
        # Hack, specific to OVH.
        the_survol_url = the_survol_url.replace(
            "primhillcomputers.com:80/survol/survolcgi",
            "primhillcomputers.com:80/cgi-bin/survol/survolcgi")
        self.m_survol_url = the_survol_url
        self.m_survol_universal_alias = NodeToUniversalAlias(rdf_node)

        NodeJsonNumber += 1  # One more node.
Exemple #8
0
    def fields_to_html_vertical(grph, the_fields):
        props = {}
        idx = 0
        # TODO: The sort must put at first, some specific keys.
        # For example, sources_top/nmap_run.py, the port number as an int (Not a string)
        # Also, filenames, case-sensitive or not.
        for key, val in sorted(the_fields):
            # This should come first, but it does not so we prefix with "----". Hack !
            if key == pc.property_information:
                # Completely left-aligned. Col span is 2, approximate ratio.
                val = _str_with_br(val, 2)
                curr_td = "<td align='left' balign='left' colspan='2'>%s</td>" % val
            elif is_flat_property(key) :
                url_txt = lib_naming.ParseEntityUri(val)[0]
                split_txt = _str_with_br(url_txt, 2)
                # The text of the link must be underlined.
                curr_td = '<td href="%s" align="left" colspan="2">%s</td>' % (val, _dot_ul(split_txt))
            else:
                key_qname = lib_kbase.qname(key, grph)
                # This assumes: type(val) == 'rdflib.term.Literal'
                if lib_kbase.IsLiteral(val):
                    curr_td = _format_pair(key_qname, val.value)
                else:
                    curr_td = _format_pair(key_qname, val)

            props[idx] = curr_td
            idx += 1
        return props
Exemple #9
0
    def FieldsToHtmlVertical(grph, the_fields):
        props = {}
        idx = 0
        # TODO: The sort must put at first, some specific keys.
        # For example, sources_top/nmap_run.py, the port number as an int (Not a string)
        # Also, filenames, case-sensitive or not.
        for (key, val) in sorted(the_fields):
            # This should come first, but it does not so we prefix with "----". Hack !
            if key == pc.property_information:
                # Completely left-aligned. Col span is 2, approximate ratio.
                val = lib_exports.StrWithBr(val, 2)
                currTd = "<td align='left' balign='left' colspan='2'>%s</td>" % val
            elif IsFlatProperty(key):
                urlTxt = lib_naming.ParseEntityUri(val)[0]
                splitTxt = lib_exports.StrWithBr(urlTxt, 2)
                # The text of the link must be underlined.
                currTd = '<td href="%s" align="left" colspan="2">%s</td>' % (
                    val, lib_exports.DotUL(splitTxt))
            else:
                key_qname = qname(key, grph)
                # This assumes: type(val) == 'rdflib.term.Literal'
                # sys.stderr.write("FORMAT ELEMENT: %s\n" %(dir(val)))
                if lib_kbase.IsLiteral(val):
                    currTd = FormatPair(key_qname, val.value)
                else:
                    currTd = FormatPair(key_qname, val)

            props[idx] = currTd
            idx += 1
        return props
Exemple #10
0
    def __init__(self, rdf_node):
        global _node_json_number
        subj_str = str(rdf_node)

        entity_label, entity_graphic_class, entity_id = lib_naming.ParseEntityUri(
            subj_str, long_display=False, force_entity_ip_addr=None)

        self.m_label = entity_label.strip()
        self.m_class = entity_graphic_class

        array_graph_params = lib_patterns.TypeToGraphParams(self.m_class)

        # "Graphic_shape","Graphic_colorfill","Graphic_colorbg","Graphic_border","Graphic_is_rounded"
        self.m_color = array_graph_params[1]

        # TODO: Display the doc in the module with FromModuleToDoc(importedMod,filDfltText):
        self.m_info_list = [entity_graphic_class]
        self.m_info_dict = dict()
        self.m_index = _node_json_number

        the_survol_url = lib_util.survol_unescape(rdf_node)
        self.m_survol_url = the_survol_url
        self.m_survol_universal_alias = lib_exports.NodeToUniversalAlias(
            rdf_node)

        _node_json_number += 1  # One more node.
Exemple #11
0
def _script_information_html_iterator(theCgi, gblCgiEnvList):
    """
        This displays general information about this script and the object if there is one.
    """
    logging.debug("_script_information_html_iterator entity_type=%s",
                  theCgi.m_entity_type)

    # This is already called in lib_common, when creating ScriptEnvironment.
    # It does not matter because this is very fast.
    calling_url = lib_util.RequestUri()
    entity_label, entity_graphic_class, entity_id = lib_naming.ParseEntityUri(
        calling_url, long_display=True)
    logging.debug("entity_label=%s entity_graphic_class=%s entity_id=%s",
                  entity_label, entity_graphic_class, entity_id)

    yield '<table border="0">'
    if len(gblCgiEnvList):
        logging.debug("gblCgiEnvList=%s", str(gblCgiEnvList))
        # This step is dedicated to the merging of several scripts.

        yield (
            "<tr align=left><td colspan=2 align=left><h2>Fusion of data from %d scripts</h2></td></tr>"
            % len(gblCgiEnvList))
        for aCgiEnv in gblCgiEnvList:
            page_title_first, page_title_rest = aCgiEnv.m_page_title, aCgiEnv.m_page_subtitle
            yield ("<tr><td><a href='%s'>%s</td><td><i>%s</i></td></tr>" %
                   (aCgiEnv.m_calling_url, page_title_first, page_title_rest))
    else:
        (page_title_first,
         page_title_rest) = theCgi.m_page_title, theCgi.m_page_subtitle
        yield "<tr><td colspan=2><h2>%s</h2></td></tr>" % page_title_first
        if page_title_rest:
            yield "<tr><td colspan=2>%s</td></tr>" % page_title_rest

    yield '</table>'
Exemple #12
0
def ExternalToTitle(extUrl):
    # Depending on where we come from, "%2F" instead of "/" ... ugly.
    # BEWARE: This is completely experimental. See if "Yawn" is actually used.
    if re.match(".*/yawn/.*", extUrl) or re.match(".*%2Fyawn%2F.*", extUrl):
        return "Yawn"

    pyNamMtch = re.match(".*/([^.]+).py.*", extUrl)
    if pyNamMtch:
        pyNam = pyNamMtch.group(1)

        # After all, the script might be entity
        if pyNam == "entity":
            (objNam, entity_graphic_class,
             entity_id) = lib_naming.ParseEntityUri(extUrl)
            return objNam

        try:
            # TODO: See lib_naming.scripts_to_titles
            basNamToTxt = {
                "objtypes_wbem": "Subtypes",  # This key is duplicated !!!!
                "file_directory": "Subdir",
                "file_to_mime": "MIME",
                "objtypes_wmi": "WMI tree",
                "objtypes_wbem": "WBEM hier.",
                "class_type_all": "Cross class",
                "dir_to_html": "DIR"
            }
            return basNamToTxt[pyNam]
        except:
            return pyNam.replace("_", " ").capitalize()
    else:
        # sys.stderr.write("extUrl=%s\n"%extUrl)
        return "Literal:" + extUrl
Exemple #13
0
def _create_objects_list(grph):
    """
        This displays all the objects returned by this scripts.
        Other scripts are not here, so we do not have to eliminate them.
        This is therefore simpler than in the SVG (Graphviz) output,
        where all objects are mixed together.
    """

    # This groups data by subject, then predicate, then object.
    dictClassSubjPropObj = dict()

    # TODO: Group objects by type, then display the count, some info about each type etc...
    for aSubj, aPred, anObj in grph:
        # No point displaying some keys if there is no value.
        if aPred == pc.property_information:
            try:
                if str(anObj) == "":
                    continue
            # 'ascii' codec can't encode character u'\xf3' in position 17: ordinal not in range(128)
            # u'SDK de comprobaci\xf3n de Visual Studio 2012 - esn'
            except UnicodeEncodeError:
                exc = sys.exc_info()[1]
                ERROR("Exception %s", str(exc))
                continue

        subj_str = str(aSubj)
        (subj_title, entity_graphic_class,
         entity_id) = lib_naming.ParseEntityUri(subj_str)

        try:
            dictSubjPropObj = dictClassSubjPropObj[entity_graphic_class]
            try:
                dictPred = dictSubjPropObj[aSubj]
                try:
                    dictPred[aPred].append(anObj)
                except KeyError:
                    # First time this object has this predicate.
                    dictPred[aPred] = [anObj]
            except KeyError:
                # First time we see this object.
                dictSubjPropObj[aSubj] = {aPred: [anObj]}
        except KeyError:
            # First object of this class.
            dictClassSubjPropObj[entity_graphic_class] = {
                aSubj: {
                    aPred: [anObj]
                }
            }
    return dictClassSubjPropObj
Exemple #14
0
def _cim_urls_html_iterator():
    # This callback receives a RDF property (WBEM or WMI) and a map
    # which represents the CIM links associated to the current object.
    def WMapToHtml(theMap):
        DEBUG("WMapToHtml len=%d", len(theMap))
        for urlSubj in theMap:
            (subjText, subjEntityGraphClass,
             subjEntityId) = lib_naming.ParseEntityUri(
                 lib_util.urllib_unquote(urlSubj))
            yield ("<tr>")
            yield ("<td valign='top'><a href='%s'>%s</a></td>" %
                   (str(urlSubj), subjText))
            yield ("<td>")
            yield ("<table border=0>")
            for theProp, urlObj in theMap[urlSubj]:
                yield ("<tr>")
                propNam = lib_exports.PropToShortPropNam(theProp)
                yield ("<td><i>%s</i></td>" % propNam)
                if lib_kbase.IsLiteral(urlObj):
                    yield ("<td>%s</td>" % (str(urlObj)))
                else:
                    (objText, objEntityGraphClass,
                     objEntityId) = lib_naming.ParseEntityUri(
                         lib_util.urllib_unquote(urlObj))
                    yield ("<td><a href='%s'>%s</a></td>" %
                           (str(urlObj), objText))
                yield ("</tr>")
            yield ("</table>")
            yield ("</td>")
        yield ("</tr>")

    callingUrl = lib_util.RequestUri()
    (entity_label, entity_type,
     entity_id) = lib_naming.ParseEntityUri(callingUrl, longDisplay=True)
    host_wbem_wmi = lib_util.currentHostname
    nameSpace = ""

    mapWbem = CIM_ComputerSystem.AddWbemServers(host_wbem_wmi, nameSpace,
                                                entity_type, entity_id)
    for linHtml in WMapToHtml(mapWbem):
        yield linHtml
    mapWmi = CIM_ComputerSystem.AddWmiServers(host_wbem_wmi, nameSpace,
                                              entity_type, entity_id)
    for linHtml in WMapToHtml(mapWmi):
        yield linHtml
    mapSurvol = CIM_ComputerSystem.AddSurvolServers(host_wbem_wmi, nameSpace,
                                                    entity_type, entity_id)
    for linHtml in WMapToHtml(mapSurvol):
        yield linHtml
Exemple #15
0
def _cim_urls_html_iterator():
    def w_map_to_html(the_map):
        """This callback receives a RDF property (WBEM or WMI) and a map
        which represents the CIM links associated to the current object. """
        logging.debug("w_map_to_html len=%d", len(the_map))
        for url_subj in the_map:
            unquoted_subj = lib_util.urllib_unquote(url_subj)
            subj_text, subj_entity_graph_class, subj_entity_id = lib_naming.ParseEntityUri(
                unquoted_subj)
            yield "<tr>"
            yield "<td valign='top'><a href='%s'>%s</a></td>" % (str(url_subj),
                                                                 subj_text)
            yield "<td>"
            yield "<table border=0>"
            for the_prop, url_obj in the_map[url_subj]:
                yield "<tr>"
                prop_nam = lib_exports.PropToShortPropNam(the_prop)
                yield "<td><i>%s</i></td>" % prop_nam
                if lib_kbase.IsLiteral(url_obj):
                    yield "<td>%s</td>" % str(url_obj)
                else:
                    unquoted_obj = lib_util.urllib_unquote(url_obj)
                    obj_text, obj_entity_graph_class, obj_entity_id = lib_naming.ParseEntityUri(
                        unquoted_obj)
                    yield "<td><a href='%s'>%s</a></td>" % (str(url_obj),
                                                            obj_text)
                yield "</tr>"
            yield "</table>"
            yield "</td>"
        yield "</tr>"

    calling_url = lib_util.RequestUri()
    entity_label, entity_type, entity_id = lib_naming.ParseEntityUri(
        calling_url, long_display=True)
    host_wbem_wmi = lib_util.currentHostname
    name_space = ""

    map_wbem = CIM_ComputerSystem.AddWbemServers(host_wbem_wmi, name_space,
                                                 entity_type, entity_id)
    for lin_html in w_map_to_html(map_wbem):
        yield lin_html
    map_wmi = CIM_ComputerSystem.AddWmiServers(host_wbem_wmi, name_space,
                                               entity_type, entity_id)
    for lin_html in w_map_to_html(map_wmi):
        yield lin_html
    map_survol = CIM_ComputerSystem.AddSurvolServers(host_wbem_wmi, name_space,
                                                     entity_type, entity_id)
    for lin_html in w_map_to_html(map_survol):
        yield lin_html
Exemple #16
0
def _get_daemons_data():
    """
    This returns in a dictionary, the list of deamons.
    These daemons can then be displayed in plain HTML or in a Jinja2 template.
    Some control is also provided by the interface of supervisord library, so its link is displayed.
    Some CGI scripts can run in two modes: "web" mode (CGI or WSGI), as usual, but also in daemon mode:
    their daemon process runs endlessly and instead of returning their events to the caller of the CGI script,
    these events are inserted into a RDF triplestore.
    This RDF triplestore is defined as an URL in the credentials: Any type of triplestore
    is allowed as long as it is supported by rdflib persistence API,
    see details here: https://rdflib.readthedocs.io/en/stable/persistence.html .
    Then, when the script is later run in "normal", CGI mode, the events are returned from this triplestore database.
    This allows to accumulate a complete history of events stored as RDF triples.
    
    Each of these daemons is associated with a CGI script and also an object, defined with its class and the values 
    of the attributes listes in the ontology of the class.
    Of course, if this is a top-level script not associated with a class, there are no arguments.
    """

    urls_daemons_dict = lib_daemon.get_running_daemons()
    for daemon_url, daemon_object in urls_daemons_dict.items():
        logging.debug("daemon_url=%s" % daemon_url)

        url_label, entity_type, entity_id = lib_naming.ParseEntityUri(
            daemon_url, long_display=True)
        logging.debug("url_label=%s" % url_label)
        logging.debug("entity_type=%s" % entity_type)
        logging.debug("entity_id=%s" % entity_id)

        daemon_object['url_title'] = url_label

        # Now that we have the class and the key-value pairs of the object related to the script, builds its url.
        # TODO: Simplify this, because it splits the id path to join it afterwards.
        # It might help to reorder properly the key-value pairs.
        entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)
        entity_url = lib_util.EntityUri(entity_type, *entity_ids_arr)
        logging.debug("entity_url=%s" % entity_url)
        daemon_object['object_url'] = entity_url
        entity_label = lib_naming.entity_to_label(entity_type, entity_id,
                                                  lib_util.HostName())
        logging.debug("entity_label=%s" % entity_label)
        daemon_object['object_title'] = entity_label
        daemon_object['triples_number'] = lib_kbase.context_events_count(
            daemon_url)
        daemon_object['start_time'] = datetime.datetime.fromtimestamp(
            daemon_object['start']).strftime("%m/%d/%Y, %H:%M:%S")

    return urls_daemons_dict
Exemple #17
0
    def _define_class_in_ontology(url_node):
        """This takes the class from an Url and defines it in the RDF ontology.
        This returns the class name as a string."""
        entity_label, class_name, entity_id = lib_naming.ParseEntityUri(
            url_node)

        # This could be: ("http://the_host", "http://primhillcomputers.com/survol/____Information", "HTTP url")
        if not class_name:
            return None

        # TODO: Define base classes with rdfs:subClassOf / RDFS.subClassOf
        # "base_class" and "class_description' ???

        # A class name with the WMI namespace might be produced with this kind of URL:
        # "http://www.primhillcomputers.com/survol#root\CIMV2:CIM_Process"
        class_name = class_name.replace("\\", "%5C")
        assert isinstance(class_name, str)

        if class_name not in map_classes:
            if class_name == "":
                raise Exception("No class name for url=%s type=%s" %
                                (str(url_node), str(type(url_node))))

            # Maybe this CIM class is not defined as an RDFS class.
            # This function might also filter duplicate and redundant insertions.
            lib_util.AppendClassSurvolOntology(class_name, map_classes,
                                               map_attributes)

        # The entity_id is a concatenation of CIM property-value paris, and define an unique object.
        # They are different of the triples, but might overlap.
        entity_id_dict = lib_util.SplitMoniker(entity_id)
        for predicate_key in entity_id_dict:
            if predicate_key not in map_attributes:
                # This function might also filter a duplicate and redundant insertion.
                lib_util.append_property_survol_ontology(
                    predicate_key, "CIM key predicate %s" % predicate_key,
                    class_name, None, map_attributes)

            # This value is explicitly added to the node.
            predicate_value = entity_id_dict[predicate_key]
            new_grph.add((url_node, lib_properties.MakeProp(predicate_key),
                          rdflib.Literal(predicate_value)))

        # This adds a triple specifying that this node belongs to this RDFS class.
        lib_kbase.add_node_to_rdfs_class(new_grph, url_node, class_name,
                                         entity_label)

        return class_name
Exemple #18
0
def url_to_instance(instance_url):
    if instance_url.find("entity.py") < 0:
        # So maybe this is not an instance after all.
        return None

    # This parsing that all urls are not scripts but just define an instance
    # and therefore have the form "http://.../entity.py?xid=...",
    agent_url = instance_url_to_agent_url(instance_url)

    (entity_label, entity_graphic_class, entity_id) = lib_naming.ParseEntityUri(instance_url)
    # This extracts the host from the string "Key=Val,Name=xxxxxx,Key=Val"
    # TODO: Some arguments should be decoded from base64.
    # DEBUG("get_instances instanceUrl=%s entity_graphic_class=%s entity_id=%s",instanceUrl,entity_graphic_class,entity_id)

    new_instance = entity_id_to_instance(agent_url, entity_graphic_class, entity_id)
    return new_instance
Exemple #19
0
def _script_information_html_iterator(theCgi, gblCgiEnvList):
    """
        This displays general information about this script and the object if there is one.
    """
    DEBUG("_script_information_html_iterator entity_type=%s",
          theCgi.m_entity_type)

    # This is already called in lib_common, when creating CgiEnv.
    # It does not matter because this is very fast.
    callingUrl = lib_util.RequestUri()
    (entity_label, entity_graphic_class,
     entity_id) = lib_naming.ParseEntityUri(callingUrl, longDisplay=True)
    DEBUG("entity_label=%s entity_graphic_class=%s entity_id=%s", entity_label,
          entity_graphic_class, entity_id)

    # WrtAsUtf('<table class="list_of_merged_scripts">')
    yield ('<table border="0">')
    if len(gblCgiEnvList):
        DEBUG("gblCgiEnvList=%s", str(gblCgiEnvList))
        # This step is dedicated to the merging of several scripts.

        yield (
            "<tr align=left><td colspan=2 align=left><h2>Fusion of data from %d scripts</h2></td></tr>"
            % len(gblCgiEnvList))
        for aCgiEnv in gblCgiEnvList:
            DEBUG("aCgiEnv=%s", str(aCgiEnv))
            DEBUG("aCgiEnv.m_page_title=%s", str(aCgiEnv.m_page_title))
            DEBUG("aCgiEnv.m_calling_url=%s", str(aCgiEnv.m_calling_url))
            #(page_title_first,page_title_rest) = lib_util.SplitTextTitleRest(aCgiEnv.m_page_title)
            page_title_first, page_title_rest = aCgiEnv.m_page_title, aCgiEnv.m_page_subtitle
            yield ("<tr><td><a href='%s'>%s</td><td><i>%s</i></td></tr>" %
                   (aCgiEnv.m_calling_url, page_title_first, page_title_rest))
    else:
        # (page_title_first,page_title_rest) = lib_util.SplitTextTitleRest(theCgi.m_page_title)
        (page_title_first,
         page_title_rest) = theCgi.m_page_title, theCgi.m_page_subtitle
        yield ("<tr><td colspan=2><h2>%s</h2></td></tr>" % (page_title_first))
        if page_title_rest:
            yield ("<tr><td colspan=2>%s</td></tr>" % (page_title_rest))

    yield ('</table>')
Exemple #20
0
def url_to_instance(instance_url):
    """
    This creates an object from an URI.
    Input example: instanceUrl="http://LOCALHOST:80/LocalExecution/entity.py?xid=CIM_Process.Handle=2092"
    """
    if instance_url.find("entity.py") < 0:
        # So maybe this is not an instance after all.
        return None

    # This parsing that all urls are not scripts but just define an instance
    # and therefore have the form "http://.../entity.py?xid=...",
    agent_url = instance_url_to_agent_url(instance_url)

    entity_label, entity_graphic_class, entity_id = lib_naming.ParseEntityUri(
        instance_url)
    # This extracts the host from the string "Key=Val,Name=xxxxxx,Key=Val"
    # TODO: Some arguments should be decoded from base64.

    new_instance = entity_id_to_instance(agent_url, entity_graphic_class,
                                         entity_id)
    return new_instance
Exemple #21
0
    def get_triplestore(self):
        triplestoreA = self.m_srcA.get_triplestore()
        if self.is_cgi_complete():
            triplestoreB = self.m_srcB.get_triplestore()

            return self.m_operatorTripleStore(triplestoreA,triplestoreB)

        else:
            # TODO: Was it ever used ?
            # The class cannot be None because the url is not complete

            objsList = triplestoreA.enumerate_urls()

            # TODO: Not optimal because it processes not only instances urls but also scripts urls.
            for instanceUrl in objsList:
                ( entity_label, entity_graphic_class, entity_id ) = lib_naming.ParseEntityUri(instanceUrl)
                if entity_label == self.m_srcB.m_class:
                    urlDerived = url_to_instance(instanceUrl)
                    triplestoreB = urlDerived.get_triplestore()
                    triplestoreA = self.m_operatorTripleStore(triplestoreA,triplestoreB)
            return TripleStore(triplestoreA)
Exemple #22
0
def WriteAllObjects(grph):
    """
		This displays all the objects returend by this scripts.
		Other scripts are not here, so we do not have to eliminate them.
		This is therefore simpler than in the SVG (Graphviz) output,
		where all objects are mixed together.
	"""

    # This groups data by subject, then predicate, then object.
    dictClassSubjPropObj = dict()

    # TODO: Group objects by type, then display the count, some info about each type etc...
    for aSubj, aPred, anObj in grph:
        # No point displaying some keys if there is no value.
        if aPred == pc.property_information:
            try:
                if str(anObj) == "":
                    continue
            # 'ascii' codec can't encode character u'\xf3' in position 17: ordinal not in range(128)
            # u'SDK de comprobaci\xf3n de Visual Studio 2012 - esn'
            except UnicodeEncodeError:
                exc = sys.exc_info()[1]
                sys.stderr.write("Exception %s\n" % str(exc))
                continue

        subj_str = str(aSubj)
        (subj_title, entity_graphic_class,
         entity_id) = lib_naming.ParseEntityUri(subj_str)

        try:
            dictSubjPropObj = dictClassSubjPropObj[entity_graphic_class]
            try:
                dictPred = dictSubjPropObj[aSubj]
                try:
                    dictPred[aPred].append(anObj)
                except KeyError:
                    # First time this object has this predicate.
                    dictPred[aPred] = [anObj]
            except KeyError:
                # First time we see this object.
                dictSubjPropObj[aSubj] = {aPred: [anObj]}
        except KeyError:
            # First object of this class.
            dictClassSubjPropObj[entity_graphic_class] = {
                aSubj: {
                    aPred: [anObj]
                }
            }

    # Group objects by class.
    # Display list of classes with an indexs and a link to the class.
    # "NO TITLE" is wrong

    # TODO: Create a "difference mode". Periodic display, of only the difference between successive data sets.
    # Ajouter mode "difference": On recalcule periodiquement et on affiche la difference.

    # No need to use natural sort, because these are no filenames or strings containing numbres.
    for entity_graphic_class in sorted(dictClassSubjPropObj):

        urlClass = lib_util.EntityClassUrl(entity_graphic_class)
        urlClass_with_mode = UrlInHtmlMode(urlClass)
        WrtAsUtf("<h3>Class <a href='%s'>%s</a></h3>" %
                 (urlClass_with_mode, entity_graphic_class))
        dictSubjPropObj = dictClassSubjPropObj[entity_graphic_class]

        DispClassObjects(dictSubjPropObj)
def _add_wmi_links(callback_grph_add, parent_node, entity_type, entity_id, gen_obj):

    """
    wmi_associators_list(entity_type, entity_id) = ["ASSOC1", "ASSOC2"]

    This applies only if this class is defined in WMI or WBEM respectively, as Survol classes have no associators.

    # This creates a menu like:
    # "WMI associators" =>

    :param callback_grph_add:
    :param parent_node:
    :param entity_type:
    :param entity_id:
    :return:
    """

    # Get the list of associators names and field names, from the ontology, in WMI or WBEM.
    # It is possible to have both types of accessors, or none.

    # From survol_ontology_attributes.wmi.202104.json
    # CIM_ProcessExecutable.Antecedent
    #                    predicate_type	"ref:CIM_DataFile"
    #                    predicate_domai ["CIM_Process"]
    # CIM_ProcessExecutable.Dependent
    #                    predicate_type	"ref:CIM_Process"
    #                    predicate_domain ["CIM_DataFile"]

    # Get the list of attributes, like "accessor name.field name" which have a predicate type of the given class.
    # See terminology: https://docs.microsoft.com/en-us/windows/win32/wmisdk/associators-of-statement
    # ASSOCIATORS OF {ObjectPath} WHERE
    #     AssocClass = AssocClassName
    #     ClassDefsOnly
    #     RequiredAssocQualifier = QualifierName
    #     RequiredQualifier = QualifierName
    #     ResultClass = ClassName
    #     ResultRole = PropertyName
    #     Role = PropertyName
    # For each of these attributes, create a URL like:
    # associators_wmi.py?xid=<the-xid>&__result_class__=<class name>&__result_role__=<xyz>

    logging.debug("entity_type=%s entity_id=%s", entity_type, entity_id)
    depth_call = 1
    wmi_associators_node = None

    attributes_list = lib_ontology_tools.class_associators("wmi", lib_wmi.extract_specific_ontology_wmi, entity_type)
    for attribute_name in attributes_list:
        logging.debug("attribute_name=%s", attribute_name)
        # It must have the syntax "associator.role"
        assert attribute_name.find(".") > 0
        if wmi_associators_node is None:
            # Add the parent node only if there is at least one associator.
            wmi_associators_node = lib_util.NodeLiteral("WMI associators")
            callback_grph_add((parent_node, pc.property_script, wmi_associators_node), depth_call)

        # The CGI parameter "xid" is normally the only CGI parameter related to data.
        # Extra CGI parameters are used for display mode (RDF, SVG etc...) or for parameters edition,
        # that is, for "technical" things.
        # Here, this is the only place where an extra CGI parameters related to data is used.
        # This is why no function is created in lib_urls for this purpose.
        # This might change if, in the future, all parameters of the instances are passed
        # as plain CGI parameters, like the technical parameters which will be prefixed and suffixed with "__".
        # url_path = gen_obj.create_entity_path("/entity.py", entity_type, entity_id.replace("/", ""))
        url_path = gen_obj.create_entity_path("/entity.py", entity_type, entity_id)
        url_path += "&amp;__associator_attribute__=" + attribute_name
        script_node = lib_util.NodeUrl(url_path)

        associator_name, _, _ = attribute_name.partition(".")
        callback_grph_add((wmi_associators_node, pc.property_script, script_node), depth_call + 1)
        script_label, _, _ = lib_naming.ParseEntityUri(url_path)
        callback_grph_add((script_node, pc.property_information, lib_util.NodeLiteral(script_label)), depth_call + 1)
Exemple #24
0
def Rdf2Dot(grph, logfil, stream, CollapsedProperties):
    fieldsSet = collections.defaultdict(list)

    # This maps RDFLIB nodes to DOT label names.
    dictRdf2Dot = {}

    # This returns the DOT label of a RDFLIB, and creates a new one if necessary.
    def RdfNodeToDotLabel(x):
        try:
            return dictRdf2Dot[x]
        except KeyError:
            nodelabel = "nd_%d" % len(dictRdf2Dot)
            dictRdf2Dot[x] = nodelabel
            return nodelabel

    # The QName is an abbreviation of URI reference with the namespace function for XML.
    # Edge label.
    # Transforms "http://primhillcomputers.com/ontologies/ppid" into "ppid"
    # TODO: Beware, a CGI parameter might be there. CGIPROP
    def qname(x, grph):
        try:
            q = grph.compute_qname(x)
            # q[0] is the shortened namespace "ns"
            # Could return q[0] + ":" + q[2]
            return q[2]
        except:
            return x
        # Nothing really interesting at the moment, just hardcodes.
        return lib_properties.prop_color(prop)

    # The input is any Python object.
    # This returns a simple object which can be transformed into a string.
    # If the input is a container, it returns a HTML table.
    def FormatElementAux(val, depth=0):
        if val is None:
            return ""

        try:
            int(val)
            return val
        except:
            pass

        try:
            float(val)
            return val
        except:
            pass

        if isinstance(val, dict):
            subTable = ""
            # TODO: Consider using six.iteritems.
            for subKey, subVal in val.items():
                subTd = FormatPair(subKey, subVal, depth + 1)
                if subTd:
                    subTable += "<tr>%s</tr>" % subTd
            return "<table border='0'>%s</table>" % subTable

        # Note: Recursive list are not very visible.
        if isinstance(val, (list, tuple)):
            # If this is an empty list or tuple.
            if not val:
                # return "(Empty)"
                # Empty set character in UTF8
                return "{" + "&#x2205;" + "}"
            if depth % 2 == 0:
                subTable = ""
                for subElement in val:
                    subTd = FormatElement(subElement, depth + 1)
                    subTable += "<tr>%s</tr>" % subTd
                return "<table border='0'>%s</table>" % subTable
            else:
                subTable = ""
                for subElement in val:
                    subTd = FormatElement(subElement, depth + 1)
                    subTable += subTd
                return "<table border='0'><tr>%s</tr></table>" % subTable

        try:
            decodVal = json.loads(val)
            return FormatElementAux(decodVal, depth + 1)

        except ValueError:
            # It is a string which cannot be converted to json.
            val = cgi.escape(val)
            return lib_exports.StrWithBr(val)
        except TypeError:
            # "Expected a string or buffer"
            # It is not a string, so it could be a datetime.datetime
            val = cgi.escape(str(val))
            return lib_exports.StrWithBr(val)
        return "FormatElement failure"

    def FormatElement(val, depth=0):
        if lib_kbase.IsLink(val):
            valTitle = "FormatElement " + ExternalToTitle(val)
            valTitleUL = lib_exports.DotUL(valTitle)
            return "<td align='left' balign='left' border='0' href='%s'>%s</td>" % (
                val, valTitleUL)

        resStr = FormatElementAux(val, depth)
        return "<td align='left' balign='left' border='0'>%s</td>" % resStr

    # Prints a key-value pair as two TD tags, to go in an HTML table.
    def FormatPair(key, val, depth=0):
        colFirst = "<td align='left' valign='top' border='0'>%s</td>" % lib_exports.DotBold(
            key)
        colSecond = FormatElement(val, depth + 1)
        return colFirst + colSecond

    # Display in the DOT node the list of its literal properties.
    def FieldsToHtmlVertical(grph, the_fields):
        props = {}
        idx = 0
        # TODO: The sort must put at first, some specific keys.
        # For example, sources_top/nmap_run.py, the port number as an int (Not a string)
        # Also, filenames, case-sensitive or not.
        for (key, val) in sorted(the_fields):
            # This should come first, but it does not so we prefix with "----". Hack !
            if key == pc.property_information:
                # Completely left-aligned. Col span is 2, approximate ratio.
                val = lib_exports.StrWithBr(val, 2)
                currTd = "<td align='left' balign='left' colspan='2'>%s</td>" % val
            elif IsFlatProperty(key):
                urlTxt = lib_naming.ParseEntityUri(val)[0]
                splitTxt = lib_exports.StrWithBr(urlTxt, 2)
                # The text of the link must be underlined.
                currTd = '<td href="%s" align="left" colspan="2">%s</td>' % (
                    val, lib_exports.DotUL(splitTxt))
            else:
                key_qname = qname(key, grph)
                # This assumes: type(val) == 'rdflib.term.Literal'
                # sys.stderr.write("FORMAT ELEMENT: %s\n" %(dir(val)))
                if lib_kbase.IsLiteral(val):
                    currTd = FormatPair(key_qname, val.value)
                else:
                    currTd = FormatPair(key_qname, val)

            props[idx] = currTd
            idx += 1
        return props

    # Ca liste les labels des objects qui apparaissent dans les blocs,
    # et pointent vers le nom du record.
    dictCollapsedObjectLabelsToSubjectLabels = {}

    # This contains, for each node (subject), the related node (object) linked
    # to it with a property to be displayed in tables instead of individual nodes.
    dictPropsCollapsedSubjectsToObjectLists = {}

    for collapsPropObj in CollapsedProperties:
        collapsPropNam = lib_exports.PropToShortPropNam(collapsPropObj)
        dictPropsCollapsedSubjectsToObjectLists[
            collapsPropNam] = collections.defaultdict(list)

    # TODO: (TRANSLATE THIS) Une premiere passe pour batir l'arbre d'une certaine propriete.
    # Si pas un DAG, tant pis, ca fera un lien en plus.
    # ON voulait batir des records, mais les nodes dans un record ne peuvent pas
    # avoir un URL: Donc ca va pas evidemment.
    # HTML-LIKE Labels avec PORT et PORTPOS.
    # CA VA AUSSI SIMPLIFIER L'AFFICHAGE DES TRUCS ENORMES: Modules, Fichiers etc...
    # Et on pourra trier car il y a un ordre.
    # Donc ca doit etre facile d'ajouter des proprietes affichees comme ca.

    logfil.write(TimeStamp() + " Rdf2Dot: First pass\n")

    # New intermediary node created.
    def CollapsedLabel(collapsPropNam, subjNam):
        return "R_" + collapsPropNam + "_" + subjNam

    # Called mainly from entity.py. If S points vers O, transforms "O" => "R_S:O"
    # Accordingly we create an edge: "S" => "R_S"
    def SubjNamFromCollapsed(collapsPropNam, subjNam):
        #sys.stderr.write("ADDING1 subjNam=%s collapsPropNam=%s\n" % (subjNam,collapsPropNam))
        collapsedSubjNam = dictCollapsedObjectLabelsToSubjectLabels[subjNam][
            collapsPropNam]
        #sys.stderr.write("ADDING2 subjNam=%s collapsPropNam=%s\n" % (subjNam,collapsPropNam))
        newSubjNam = CollapsedLabel(collapsPropNam,
                                    collapsedSubjNam) + ":" + subjNam
        #sys.stderr.write("ADDED collapsedSubjNam=%s newSubjNam=%s collapsPropNam=%s\n" % (collapsedSubjNam,newSubjNam,collapsPropNam))
        return newSubjNam

    # This is sorted so the result is deterministic. Very small performance impact.
    # Any order will do as long as the result is always the same.
    sortedGrph = sorted(grph)

    # TODO: Loop only on the "collapsed" properties, the ones whose objects must be displayed
    # in tables, instead of links  - if only they have a single subject. Otherwise it cannot work.
    for subj, prop, obj in sortedGrph:

        # Objects linked with these properties, are listed in a table, instead of distinct nodes in a graph.
        if prop in CollapsedProperties:
            # TODO: We lose the property, unfortunately. Should make a map: subject => prop => object ?
            subjNam = RdfNodeToDotLabel(subj)

            propNam = lib_exports.PropToShortPropNam(prop)
            dictPropsCollapsedSubjectsToObjectLists[propNam][subj].append(obj)

            # Maybe we already entered it: Not a problem.
            objNam = RdfNodeToDotLabel(obj)

            # CollapsedProperties can contain only properties which define a tree,
            # as visibly the "object" nodes can have one ancestor only.
            try:
                # TODO: We should check if a node appears in two tables,
                # associated to two properties and/or two parent node.
                dictCollapsedObjectLabelsToSubjectLabels[objNam][
                    propNam] = subjNam
            except KeyError:
                dictCollapsedObjectLabelsToSubjectLabels[objNam] = dict()
                dictCollapsedObjectLabelsToSubjectLabels[objNam][
                    propNam] = subjNam

    # For getting the node of an object, as it might be in a table.
    def RdfNodeToDotLabelExtended(obj, prop):
        objNam = RdfNodeToDotLabel(obj)

        try:
            dictOfProps = dictCollapsedObjectLabelsToSubjectLabels[objNam]
        except KeyError:
            # sys.stderr.write("RdfNodeToDotLabelExtended propNam=%s objNam=%s\n"%(propNam,objNam) )
            return objNam

        # Let's hope there is only one collapsed property for this node. Otherwise, it means
        # that this node would be displayed in two different tables. It happened...
        if not prop is None:
            propNam = lib_exports.PropToShortPropNam(prop)
            try:
                # Maybe this property is not collapsed.
                subjNam = dictOfProps[propNam]
            except KeyError:
                prop = None

        # Maybe the property is not known, if the node is the subject.
        # Or the property is not collapsed.
        if prop is None:
            # In Python3, keys() is an iterable. No need to create a list.
            #propNam = list(dictOfProps.keys())[0]
            #propNam = dictOfProps.keys()[0]
            for propNam in dictOfProps.keys():
                break
            # First property available.
            subjNam = dictOfProps[propNam]

        newObjNam = CollapsedLabel(propNam, subjNam) + ":" + objNam
        return newObjNam

    # Now we know that we have seen all nodes in a collapsed property.
    for subj, prop, obj in sortedGrph:
        if prop in CollapsedProperties:
            continue

        # Maybe the subject node belongs to a table, but the property is not known.
        subjNam = RdfNodeToDotLabelExtended(subj, None)
        if lib_kbase.IsLink(obj):

            prp_col = lib_properties.prop_color(prop)

            # TODO: GENERALIZE THIS TO ALL COMMUTATIVE PROPERTIES.
            # THAT IS: PROPERTIES WHOSE TRIPLES ARE MERGED WHEN
            # WE HAVE AT THE SAME TIME: (Subj,Prop,Obj) and (Obj,Prop,Subj).
            # WHEN THIS HAPPENS, THE ARROW MUST BE BIDIRECTIONAL.
            # TODO: All commutative relation have bidirectional arrows.
            # At the moment, only one property can be bidirectional.
            if prop == pc.property_socket_end:

                # BEWARE, MAYBE THIS IS A PORT INTO A TABLE. SO IT HAS TO BE PREFIXED BY THE RECORD NAME.
                objNam = RdfNodeToDotLabelExtended(obj, prop)
                if (obj, prop, subj) in grph:
                    if subjNam < objNam:
                        stream.write(
                            pattEdgeBiDir %
                            (subjNam, objNam, prp_col, qname(prop, grph)))
                else:
                    # One connection only: We cannot see the other.
                    stream.write(pattEdgeOrien %
                                 (subjNam, objNam, prp_col, qname(prop, grph)))
            elif prop in [
                    pc.property_rdf_data_nolist1, pc.property_rdf_data_nolist2,
                    pc.property_rdf_data_nolist3
            ]:
                # TODO: Il suffit de tester si obj est un url de la forme "entity.py" ???
                # HTML and images urls can be "flattened" because the nodes have no descendants.
                # Do not create a node for this.
                # MIME links displayed in the same column as sub-directory.
                # Also, it might be enough to test if the object has the form "entity.py" because it has no descendant.
                # TODO: CGIPROP: Can it have several html or sub-rdf ?? It is necessary !
                fieldsSet[subj].append((prop, obj))
            else:
                objNam = RdfNodeToDotLabelExtended(obj, prop)
                # C est la que si subjNam est dans une liste de dictCollapsedSubjectsToObjectLists,
                # il faut rajouter devant, le nom du record, c est a dire SON subjNam + "_table_rdf_data:".
                try:
                    # Syntax with colon required by DOT.
                    propNam = lib_exports.PropToShortPropNam(prop)
                    subjNam = SubjNamFromCollapsed(propNam, subjNam)
                except KeyError:
                    # sys.stderr.write("PASS subjNam=%s objNam=%s\n"%(subjNam,objNam))
                    pass

                stream.write(pattEdgeOrien %
                             (subjNam, objNam, prp_col, qname(prop, grph)))
        elif obj == None:
            # No element created in nodes[]
            fieldsSet[subj].append((prop, "Null"))
        else:
            # For Literals. No element created in nodes[]
            # Literals can be processed according to their type.
            # Some specific properties cannot have children so they can be stored as literals?
            # Les proprietes comme "pid", on devrait plutot afficher le lien vers le process, dans la table ???
            # Les URLs de certaines proprietes sont affichees en colonnes.
            # Ou bien pour ces proprietes, on recree un entity.py ??

            fieldsSet[subj].append((prop, obj))

    logfil.write(TimeStamp() +
                 " Rdf2Dot: Replacing vectors: CollapsedProperties=%d.\n" %
                 (len(CollapsedProperties)))

    # Now, replaces each vector by a single object containg a HTML table.
    # TODO: Unfortunately, the prop is lost, which implies that all children are mixed together.

    def ProcessCollapsedProperties(propNam):
        dictCollapsedSubjectsToObjectLists = dictPropsCollapsedSubjectsToObjectLists[
            propNam]
        logfil.write(TimeStamp() +
                     " Rdf2Dot: dictCollapsedSubjectsToObjectLists=%d.\n" %
                     (len(dictCollapsedSubjectsToObjectLists)))

        for subjUrl, nodLst in lib_util.six_iteritems(
                dictCollapsedSubjectsToObjectLists):
            subjNam = RdfNodeToDotLabel(subjUrl)

            subjNamTab = CollapsedLabel(propNam, subjNam)
            try:
                # TODO: Cette logique ajoute parfois un niveau de noeud inutile. Plus exactement, ca duplique un noeud.
                # Ou plus exactement, le noed est represente par deux objects graphiques:
                # * Un qui a les scripts.
                # * Un autre qui a la liste HTML qu on fabrique.
                # => Peut-on imaginer de melanger les deux ??
                # Dans WritePatterns: Ajouter le nom du noeud au label.
                subjNam = SubjNamFromCollapsed(propNam, subjNam)
            except KeyError:
                pass

            # Point from the subject to the table containing the objects.
            stream.write(pattEdgeOrien %
                         (subjNam, subjNamTab, "GREEN", propNam))

            (labText, subjEntityGraphicClass,
             entity_id) = lib_naming.ParseEntityUri(subjUrl)

            # Probleme avec les champs:
            # Faire une premiere passe et reperer les fields, detecter les noms des colonnes, leur attribuer ordre et indice.
            # Seconde passe pour batir les lignes.
            # Donc on ordonne toutes les colonnes.
            # Pour chaque field: les prendre dans le sens du header et quand il y a un trou, colonne vide.
            # Inutile de trier les field, mais il d'abord avoir une liste complete des champs, dans le bon sens.
            # CA SUPPOSE QUE DANS FIELDSSET LES KEYS SONT UNIQUES.
            # SI ON NE PEUT PAS, ALORS ON METTRA DES LISTES. MAIS CETTE CONTRAINTE SIMPLIFIE L'AFFICHAGE.

            # DOMMAGE QU ON SCANNE LES OBJETS DEUX FOIS UNIQUEMENT POUR AVOIR LES NOMS DES CHAMPS !!!!!!!!!!!!!
            # TODO: HEURISTIQUE: ON pourrait s'arreter aux dix premiers. Ou bien faire le tri avant ?
            # On bien prendre les colonnes de la premiere ligne, et recommencer si ca ne marche pas.
            # Unique columns of the descendant of this subject.
            rawFieldsKeys = set()
            for obj in nodLst:
                # One table per node.
                rawFieldsKeys.update(fld[0] for fld in fieldsSet[obj])

            # sys.stderr.write("rawFieldsKeys BEFORE =%s\n" % str(rawFieldsKeys) )

            # Mandatory properties must come at the beginning of the columns of the header, with first indices.
            # BUG: Si on retire html de cette liste alors qu il y a des valeurs, colonnes absentes.
            # S il y a du html ou du RDF, on veut que ca vienne en premier.
            fieldsKeysOrdered = []
            for fldPriority in FlatPropertertiesList:
                try:
                    # Must always be appended. BUT IF THERE IS NO html_data, IS IT WORTH ?
                    # TODO: Remove if not HTML and no sub-rdf. CGIPROP

                    # If the property is never used, exception then next property.
                    rawFieldsKeys.remove(fldPriority)
                    fieldsKeysOrdered.append(fldPriority)
                except KeyError:
                    pass

            # This one is always removed because its content is concatenated at the first column.
            for fldToRemove in [pc.property_information]:
                try:
                    rawFieldsKeys.remove(fldToRemove)
                except KeyError:
                    pass

            # Appends rest of properties, sorted.
            fieldsKeys = fieldsKeysOrdered + sorted(rawFieldsKeys)

            # sys.stderr.write("fieldsKeys=%s\n" % str(fieldsKeys) )

            # This assumes that the header columns are sorted.
            keyIndices = {
                nameKey: indexKey
                for (indexKey, nameKey) in enumerate(fieldsKeys, 1)
            }

            numberKeys = len(keyIndices) + 1

            # Apparently, no embedded tables.
            dictHtmlLines = dict()
            for objUri in nodLst:
                # One table per node.
                subObjId = RdfNodeToDotLabel(objUri)

                # Beware "\L" which should not be replaced by "<TABLE>" but this is not the right place.
                subNodUri = objUri.replace('&', '&amp;')

                try:
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = lib_naming.ParseEntityUriShort(objUri)
                except UnicodeEncodeError:
                    sys.stderr.write("UnicodeEncodeError error:%s\n" %
                                     (objUri))
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = ("Utf problem1", "Utf problem2",
                                     "Utf problem3")

                # sys.stderr.write("subEntityGraphicClass=%s\n"%subEntityGraphicClass)

                # If this is a script, always displayed on white, even if reletd to a specific entity.
                # THIS IS REALLY A SHAME BECAUSE WE JUST NEED THE ORIGINAL PROPERTY.
                if objUri.find("entity.py") < 0:
                    objColor = "#FFFFFF"
                else:
                    objColor = lib_patterns.EntityClassToColor(
                        subEntityGraphicClass)
                # This lighter cololor for the first column.
                objColorLight = lib_patterns.ColorLighter(objColor)

                # Some colors a bit clearer ? Or take the original color of the class ?
                td_bgcolor_plain = '<td BGCOLOR="%s" ' % objColor
                td_bgcolor_light = '<td BGCOLOR="%s" ' % objColorLight
                td_bgcolor = td_bgcolor_plain

                # Some columns might not have a value. The first column is for the key.
                columns = [td_bgcolor + " ></td>"] * numberKeys

                # Just used for the vertical order of lines, one line per object.
                title = ""

                # TODO: CGIPROP. This is not a dict, the same key can appear several times ?
                for (key, val) in fieldsSet[objUri]:
                    if key == pc.property_information:
                        # This can be a short string only.
                        title += val
                        continue

                    # TODO: This is hard-coded.
                    if IsFlatProperty(key):

                        # In fact, it might also be an internal URL with "entity.py"
                        if lib_kbase.IsLiteral(val):
                            if isinstance(val.value, (list, tuple)):
                                strHtml = FormatElementAux(val.value)
                                sys.stderr.write("val.value=%s\n" % strHtml)
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % strHtml
                            else:
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % val.value
                        else:
                            valTitle = lib_naming.ParseEntityUri(val)[0]

                            valTitleUL = lib_exports.DotUL(valTitle)
                            tmpCell = td_bgcolor + 'href="%s" align="left" >%s</td>' % (
                                val, valTitleUL)

                    else:
                        try:
                            float(val)
                            tmpCell = td_bgcolor + 'align="right">%s</td>' % val
                        except:
                            # Wraps the string if too long. Can happen only with a literal.
                            tmpCell = td_bgcolor + 'align="left">%s</td>' % lib_exports.StrWithBr(
                                val)

                    idxKey = keyIndices[key]
                    columns[idxKey] = tmpCell

                if title:
                    title_key = title
                else:
                    title_key = subObjNam

                # Maybe the first column is a literal ?
                if subEntityId != "PLAINTEXTONLY":
                    # WE SHOULD PROBABLY ESCAPE HERE TOO.
                    columns[
                        0] = td_bgcolor_light + 'port="%s" href="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri, title_key)
                else:
                    subNodUri = cgi.escape(subNodUri)
                    columns[
                        0] = td_bgcolor_light + 'port="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri)

                # Several scripts might have the same help text, so add a number.
                # "Title" => "Title"
                # "Title" => "Title/2"
                # "Title" => "Title/3" etc...
                # Beware that it is quadratic with the number of scripts with identical info.
                title_idx = 2
                title_uniq = title_key
                while title_uniq in dictHtmlLines:
                    title_uniq = "%s/%d" % (title_key, title_idx)
                    title_idx += 1

                # TODO: L'ordre est base sur les chaines mais devrait etre base sur le contenu. Exemple:
                # TODO: "(TUT_UnixProcess) Handle=10" vient avant "(TUT_UnixProcess) Handle=2"
                # TODO: title_uniq devrait etre plutot la liste des proprietes.
                # TODO: By clicking on the column names, we could change the order.
                dictHtmlLines[title_uniq] = "".join(columns)

            # Replace the first column by more useful information.
            numNodLst = len(nodLst)

            # TODO: Compute this once for all.
            eltNam = subEntityGraphicClass.split("/")[-1]
            if not eltNam:
                # TODO: This is not the right criteria. Must select if we are listing scripts.
                eltNam = "script"

            eltNamPlural = lib_grammar.ToPlural(eltNam, numNodLst)
            txtElements = "%d %s" % (numNodLst, eltNamPlural)
            header = '<td border="1">' + lib_exports.DotBold(
                txtElements) + "</td>"

            # TODO: Replace each column name with a link which sorts the line based on this column.
            # The order of columns could be specified with an extra cgi argument with the columns names.
            for key in fieldsKeys:
                columnTitle = qname(key, grph)
                columnTitle = columnTitle.replace("_", " ").capitalize()
                header += "<td border='1'>" + lib_exports.DotBold(
                    columnTitle) + "</td>"
            # With an empty key, it comes first when sorting.
            dictHtmlLines[""] = header

            # MAYBE SHOULD BE DONE TWICE !!!!! SEE ALSO ELSEWHERE !!!!
            subjUrlClean = subjUrl.replace('&', '&amp;')

            # ATTENTION: La forme du record est celle du sujet.
            # ca veut donc dire qu'on va avoir la meme couleur pour des objets de types
            # differents s'ils sont dans la meme relation avec un sujet identique ?
            numFields = len(fieldsKeys) + 1

            # The label might be truncated
            if subjEntityGraphicClass:
                helpText = "List of " + subjEntityGraphicClass + " objects in " + labText
            else:
                helpText = "List of scripts in " + labText

            # TODO: Le title and the content are not necessarily of the same class.
            # labTextWithBr is the first line of the table containing nodes linked with the
            # same property. Unfortunately we have lost this property.
            labText = lib_exports.TruncateInSpace(labText, 30)
            labTextWithBr = lib_exports.StrWithBr(labText)
            labTextWithBr += ": " + propNam

            if entity_id == "PLAINTEXTONLY":
                subjUrlClean = ""

            # This color is the table's contour.
            lib_patterns.WritePatterned(stream, subjEntityGraphicClass,
                                        subjNamTab, helpText, '"#000000"',
                                        subjUrlClean, numFields, labTextWithBr,
                                        dictHtmlLines)

            # TODO: Eviter les repetitions de la meme valeur dans une colonne en comparant d une ligne a l autre.
            # TODO: Si une cellule est identique jusqu a un delimiteur, idem, remplacer par '"'.

    if CollapsedProperties:
        for collapsedProp in CollapsedProperties:
            collapsedPropNam = lib_exports.PropToShortPropNam(collapsedProp)
            ProcessCollapsedProperties(collapsedPropNam)

    logfil.write(TimeStamp() +
                 " Rdf2Dot: Display remaining nodes. dictRdf2Dot=%d\n" %
                 len(dictRdf2Dot))

    # Now, display the normal nodes, which are not displayed in tables.
    for objRdfNode, objLabel in lib_util.six_iteritems(dictRdf2Dot):
        # TODO: Avoids this lookup.
        if objLabel in dictCollapsedObjectLabelsToSubjectLabels:
            continue

        objPropsAsHtml = FieldsToHtmlVertical(grph, fieldsSet[objRdfNode])

        labHRef = objRdfNode.replace('&', '&amp;')

        try:
            # TODO: Probleme ici: La chaine est deja codee pour HTML ce qui en rend le parsing different
            # TODO: ... de celui d'un URL deja decode. DOMMAGE: On quote puis unquote !!!
            (labText, objEntityGraphClass,
             entity_id) = lib_naming.ParseEntityUri(
                 lib_util.urllib_unquote(objRdfNode))
        except UnicodeEncodeError:
            sys.stderr.write("UnicodeEncodeError error:%s\n" % (objRdfNode))

        # WritePatterned receives an list of strings similar to "<td>jhh</td><td>jhh</td><td>jhh</td>"
        # This function adds <tr> and </tr> on both sides.
        # This avoids concatenations.

        # Ampersand are intentionnally doubled, because later on they are replaced twice.
        # That is, interpreted twice as HTML entities.
        # This might be temporary until we replace CGI arguments by genuine WMI Monikers.
        labTextNoAmp = labText.replace("&amp;amp;", " ")
        labTextNoAmp = labTextNoAmp.strip()
        labTextClean = lib_exports.StrWithBr(labTextNoAmp)
        # Two columns because it encompasses the key and the value.

        if objEntityGraphClass:
            helpText = labTextNoAmp + " is a " + objEntityGraphClass
        else:
            if labTextClean.startswith("http"):
                helpText = "External URL " + labTextNoAmp
            else:
                helpText = "Script " + labTextNoAmp

        # This color is the object's contour.
        lib_patterns.WritePatterned(stream, objEntityGraphClass, objLabel,
                                    helpText, '"#000000"', labHRef, 2,
                                    labTextClean, objPropsAsHtml)

    logfil.write(TimeStamp() + " Rdf2Dot: Leaving\n")
    stream.write("}\n")
Exemple #25
0
    def ProcessCollapsedProperties(propNam):
        dictCollapsedSubjectsToObjectLists = dictPropsCollapsedSubjectsToObjectLists[
            propNam]
        logfil.write(TimeStamp() +
                     " Rdf2Dot: dictCollapsedSubjectsToObjectLists=%d.\n" %
                     (len(dictCollapsedSubjectsToObjectLists)))

        for subjUrl, nodLst in lib_util.six_iteritems(
                dictCollapsedSubjectsToObjectLists):
            subjNam = RdfNodeToDotLabel(subjUrl)

            subjNamTab = CollapsedLabel(propNam, subjNam)
            try:
                # TODO: Cette logique ajoute parfois un niveau de noeud inutile. Plus exactement, ca duplique un noeud.
                # Ou plus exactement, le noed est represente par deux objects graphiques:
                # * Un qui a les scripts.
                # * Un autre qui a la liste HTML qu on fabrique.
                # => Peut-on imaginer de melanger les deux ??
                # Dans WritePatterns: Ajouter le nom du noeud au label.
                subjNam = SubjNamFromCollapsed(propNam, subjNam)
            except KeyError:
                pass

            # Point from the subject to the table containing the objects.
            stream.write(pattEdgeOrien %
                         (subjNam, subjNamTab, "GREEN", propNam))

            (labText, subjEntityGraphicClass,
             entity_id) = lib_naming.ParseEntityUri(subjUrl)

            # Probleme avec les champs:
            # Faire une premiere passe et reperer les fields, detecter les noms des colonnes, leur attribuer ordre et indice.
            # Seconde passe pour batir les lignes.
            # Donc on ordonne toutes les colonnes.
            # Pour chaque field: les prendre dans le sens du header et quand il y a un trou, colonne vide.
            # Inutile de trier les field, mais il d'abord avoir une liste complete des champs, dans le bon sens.
            # CA SUPPOSE QUE DANS FIELDSSET LES KEYS SONT UNIQUES.
            # SI ON NE PEUT PAS, ALORS ON METTRA DES LISTES. MAIS CETTE CONTRAINTE SIMPLIFIE L'AFFICHAGE.

            # DOMMAGE QU ON SCANNE LES OBJETS DEUX FOIS UNIQUEMENT POUR AVOIR LES NOMS DES CHAMPS !!!!!!!!!!!!!
            # TODO: HEURISTIQUE: ON pourrait s'arreter aux dix premiers. Ou bien faire le tri avant ?
            # On bien prendre les colonnes de la premiere ligne, et recommencer si ca ne marche pas.
            # Unique columns of the descendant of this subject.
            rawFieldsKeys = set()
            for obj in nodLst:
                # One table per node.
                rawFieldsKeys.update(fld[0] for fld in fieldsSet[obj])

            # sys.stderr.write("rawFieldsKeys BEFORE =%s\n" % str(rawFieldsKeys) )

            # Mandatory properties must come at the beginning of the columns of the header, with first indices.
            # BUG: Si on retire html de cette liste alors qu il y a des valeurs, colonnes absentes.
            # S il y a du html ou du RDF, on veut que ca vienne en premier.
            fieldsKeysOrdered = []
            for fldPriority in FlatPropertertiesList:
                try:
                    # Must always be appended. BUT IF THERE IS NO html_data, IS IT WORTH ?
                    # TODO: Remove if not HTML and no sub-rdf. CGIPROP

                    # If the property is never used, exception then next property.
                    rawFieldsKeys.remove(fldPriority)
                    fieldsKeysOrdered.append(fldPriority)
                except KeyError:
                    pass

            # This one is always removed because its content is concatenated at the first column.
            for fldToRemove in [pc.property_information]:
                try:
                    rawFieldsKeys.remove(fldToRemove)
                except KeyError:
                    pass

            # Appends rest of properties, sorted.
            fieldsKeys = fieldsKeysOrdered + sorted(rawFieldsKeys)

            # sys.stderr.write("fieldsKeys=%s\n" % str(fieldsKeys) )

            # This assumes that the header columns are sorted.
            keyIndices = {
                nameKey: indexKey
                for (indexKey, nameKey) in enumerate(fieldsKeys, 1)
            }

            numberKeys = len(keyIndices) + 1

            # Apparently, no embedded tables.
            dictHtmlLines = dict()
            for objUri in nodLst:
                # One table per node.
                subObjId = RdfNodeToDotLabel(objUri)

                # Beware "\L" which should not be replaced by "<TABLE>" but this is not the right place.
                subNodUri = objUri.replace('&', '&amp;')

                try:
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = lib_naming.ParseEntityUriShort(objUri)
                except UnicodeEncodeError:
                    sys.stderr.write("UnicodeEncodeError error:%s\n" %
                                     (objUri))
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = ("Utf problem1", "Utf problem2",
                                     "Utf problem3")

                # sys.stderr.write("subEntityGraphicClass=%s\n"%subEntityGraphicClass)

                # If this is a script, always displayed on white, even if reletd to a specific entity.
                # THIS IS REALLY A SHAME BECAUSE WE JUST NEED THE ORIGINAL PROPERTY.
                if objUri.find("entity.py") < 0:
                    objColor = "#FFFFFF"
                else:
                    objColor = lib_patterns.EntityClassToColor(
                        subEntityGraphicClass)
                # This lighter cololor for the first column.
                objColorLight = lib_patterns.ColorLighter(objColor)

                # Some colors a bit clearer ? Or take the original color of the class ?
                td_bgcolor_plain = '<td BGCOLOR="%s" ' % objColor
                td_bgcolor_light = '<td BGCOLOR="%s" ' % objColorLight
                td_bgcolor = td_bgcolor_plain

                # Some columns might not have a value. The first column is for the key.
                columns = [td_bgcolor + " ></td>"] * numberKeys

                # Just used for the vertical order of lines, one line per object.
                title = ""

                # TODO: CGIPROP. This is not a dict, the same key can appear several times ?
                for (key, val) in fieldsSet[objUri]:
                    if key == pc.property_information:
                        # This can be a short string only.
                        title += val
                        continue

                    # TODO: This is hard-coded.
                    if IsFlatProperty(key):

                        # In fact, it might also be an internal URL with "entity.py"
                        if lib_kbase.IsLiteral(val):
                            if isinstance(val.value, (list, tuple)):
                                strHtml = FormatElementAux(val.value)
                                sys.stderr.write("val.value=%s\n" % strHtml)
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % strHtml
                            else:
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % val.value
                        else:
                            valTitle = lib_naming.ParseEntityUri(val)[0]

                            valTitleUL = lib_exports.DotUL(valTitle)
                            tmpCell = td_bgcolor + 'href="%s" align="left" >%s</td>' % (
                                val, valTitleUL)

                    else:
                        try:
                            float(val)
                            tmpCell = td_bgcolor + 'align="right">%s</td>' % val
                        except:
                            # Wraps the string if too long. Can happen only with a literal.
                            tmpCell = td_bgcolor + 'align="left">%s</td>' % lib_exports.StrWithBr(
                                val)

                    idxKey = keyIndices[key]
                    columns[idxKey] = tmpCell

                if title:
                    title_key = title
                else:
                    title_key = subObjNam

                # Maybe the first column is a literal ?
                if subEntityId != "PLAINTEXTONLY":
                    # WE SHOULD PROBABLY ESCAPE HERE TOO.
                    columns[
                        0] = td_bgcolor_light + 'port="%s" href="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri, title_key)
                else:
                    subNodUri = cgi.escape(subNodUri)
                    columns[
                        0] = td_bgcolor_light + 'port="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri)

                # Several scripts might have the same help text, so add a number.
                # "Title" => "Title"
                # "Title" => "Title/2"
                # "Title" => "Title/3" etc...
                # Beware that it is quadratic with the number of scripts with identical info.
                title_idx = 2
                title_uniq = title_key
                while title_uniq in dictHtmlLines:
                    title_uniq = "%s/%d" % (title_key, title_idx)
                    title_idx += 1

                # TODO: L'ordre est base sur les chaines mais devrait etre base sur le contenu. Exemple:
                # TODO: "(TUT_UnixProcess) Handle=10" vient avant "(TUT_UnixProcess) Handle=2"
                # TODO: title_uniq devrait etre plutot la liste des proprietes.
                # TODO: By clicking on the column names, we could change the order.
                dictHtmlLines[title_uniq] = "".join(columns)

            # Replace the first column by more useful information.
            numNodLst = len(nodLst)

            # TODO: Compute this once for all.
            eltNam = subEntityGraphicClass.split("/")[-1]
            if not eltNam:
                # TODO: This is not the right criteria. Must select if we are listing scripts.
                eltNam = "script"

            eltNamPlural = lib_grammar.ToPlural(eltNam, numNodLst)
            txtElements = "%d %s" % (numNodLst, eltNamPlural)
            header = '<td border="1">' + lib_exports.DotBold(
                txtElements) + "</td>"

            # TODO: Replace each column name with a link which sorts the line based on this column.
            # The order of columns could be specified with an extra cgi argument with the columns names.
            for key in fieldsKeys:
                columnTitle = qname(key, grph)
                columnTitle = columnTitle.replace("_", " ").capitalize()
                header += "<td border='1'>" + lib_exports.DotBold(
                    columnTitle) + "</td>"
            # With an empty key, it comes first when sorting.
            dictHtmlLines[""] = header

            # MAYBE SHOULD BE DONE TWICE !!!!! SEE ALSO ELSEWHERE !!!!
            subjUrlClean = subjUrl.replace('&', '&amp;')

            # ATTENTION: La forme du record est celle du sujet.
            # ca veut donc dire qu'on va avoir la meme couleur pour des objets de types
            # differents s'ils sont dans la meme relation avec un sujet identique ?
            numFields = len(fieldsKeys) + 1

            # The label might be truncated
            if subjEntityGraphicClass:
                helpText = "List of " + subjEntityGraphicClass + " objects in " + labText
            else:
                helpText = "List of scripts in " + labText

            # TODO: Le title and the content are not necessarily of the same class.
            # labTextWithBr is the first line of the table containing nodes linked with the
            # same property. Unfortunately we have lost this property.
            labText = lib_exports.TruncateInSpace(labText, 30)
            labTextWithBr = lib_exports.StrWithBr(labText)
            labTextWithBr += ": " + propNam

            if entity_id == "PLAINTEXTONLY":
                subjUrlClean = ""

            # This color is the table's contour.
            lib_patterns.WritePatterned(stream, subjEntityGraphicClass,
                                        subjNamTab, helpText, '"#000000"',
                                        subjUrlClean, numFields, labTextWithBr,
                                        dictHtmlLines)
Exemple #26
0
    def ProcessCollapsedProperties(propNam):
        dictCollapsedSubjectsToObjectLists = dict_props_collapsed_subjects_to_object_lists[
            propNam]
        logfil.write(TimeStamp() +
                     " Rdf2Dot: dictCollapsedSubjectsToObjectLists=%d.\n" %
                     (len(dictCollapsedSubjectsToObjectLists)))

        for subjUrl, nodLst in lib_util.six_iteritems(
                dictCollapsedSubjectsToObjectLists):
            subjNam = _rdf_node_to_dot_label(subjUrl)

            subjNamTab = CollapsedLabel(propNam, subjNam)
            try:
                # TODO: This logic adds an extra level of node: Try to flatten the tree.
                subjNam = SubjNamFromCollapsed(propNam, subjNam)
            except KeyError:
                pass

            # This points from the subject to the table containing the objects.
            # TODO: This color should be a parameter.
            stream.write(_pattern_edge_oriented %
                         (subjNam, subjNamTab, "GREEN", propNam))

            (labText, subjEntityGraphicClass,
             entity_id) = lib_naming.ParseEntityUri(subjUrl)

            # At the moment, two passes are necessary:
            # * A first pass to create the compte list of fields, because they might be a bit different
            #   from one record to the other. The column names pf these fields get an unique index number
            #   and can therefore be sorted.
            # * A second pass uses these result, to display the lines.
            #
            # This could be faster by assuming that the first ten columns have all the fields.
            # We could then start the second pass, and if an undetected column is found,
            # then restart from scratch.

            # Unique columns of the descendant of this subject.
            rawFieldsKeys = set()
            for obj in nodLst:
                # One table per node.
                rawFieldsKeys.update(fld[0] for fld in fieldsSet[obj])

            # sys.stderr.write("rawFieldsKeys BEFORE =%s\n" % str(rawFieldsKeys) )

            # Mandatory properties must come at the beginning of the columns of the header, with first indices.
            # BUG: Si on retire html de cette liste alors qu il y a des valeurs, colonnes absentes.
            # S il y a du html ou du RDF, on veut que ca vienne en premier.
            fieldsKeysOrdered = []
            for fldPriority in _flat_properties_list:
                try:
                    # Must always be appended. BUT IF THERE IS NO html_data, IS IT WORTH ?
                    # TODO: Remove if not HTML and no sub-rdf. CGIPROP

                    # If the property is never used, exception then next property.
                    rawFieldsKeys.remove(fldPriority)
                    fieldsKeysOrdered.append(fldPriority)
                except KeyError:
                    pass

            # This one is always removed because its content is concatenated at the first column.
            for fldToRemove in [pc.property_information]:
                try:
                    rawFieldsKeys.remove(fldToRemove)
                except KeyError:
                    pass

            # Appends rest of properties, sorted.
            fieldsKeys = fieldsKeysOrdered + sorted(rawFieldsKeys)

            # sys.stderr.write("fieldsKeys=%s\n" % str(fieldsKeys) )

            # This assumes that the header columns are sorted.
            keyIndices = {
                nameKey: indexKey
                for (indexKey, nameKey) in enumerate(fieldsKeys, 1)
            }

            numberKeys = len(keyIndices) + 1

            # Apparently, no embedded tables.
            dictHtmlLines = dict()
            for objUri in nodLst:
                # One table per node.
                subObjId = _rdf_node_to_dot_label(objUri)

                # Beware "\L" which should not be replaced by "<TABLE>" but this is not the right place.
                subNodUri = objUri.replace('&', '&amp;')

                try:
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = lib_naming.ParseEntityUriShort(objUri)
                except UnicodeEncodeError:
                    WARNING("UnicodeEncodeError error:%s", objUri)
                    (subObjNam, subEntityGraphicClass,
                     subEntityId) = ("Utf problem1", "Utf problem2",
                                     "Utf problem3")

                # sys.stderr.write("subEntityGraphicClass=%s\n"%subEntityGraphicClass)

                # If this is a script, always displayed on white, even if related to a specific entity.
                # THIS IS REALLY A SHAME BECAUSE WE JUST NEED THE ORIGINAL PROPERTY.
                if objUri.find("entity.py") < 0:
                    objColor = "#FFFFFF"
                else:
                    objColor = lib_patterns.EntityClassToColor(
                        subEntityGraphicClass)
                # This lighter cololor for the first column.
                objColorLight = lib_patterns.ColorLighter(objColor)

                # Some colors a bit clearer ? Or take the original color of the class ?
                td_bgcolor_plain = '<td BGCOLOR="%s" ' % objColor
                td_bgcolor_light = '<td BGCOLOR="%s" ' % objColorLight
                td_bgcolor = td_bgcolor_plain

                # Some columns might not have a value. The first column is for the key.
                columns = [td_bgcolor + " ></td>"] * numberKeys

                # Just used for the vertical order of lines, one line per object.
                title = ""

                # TODO: CGIPROP. This is not a dict, the same key can appear several times ?
                for (key, val) in fieldsSet[objUri]:
                    if key == pc.property_information:
                        # This can be a short string only.
                        title += val
                        continue

                    # TODO: This is hard-coded.
                    if is_flat_property(key):

                        # In fact, it might also be an internal URL with "entity.py"
                        if lib_kbase.IsLiteral(val):
                            if isinstance(val.value, (list, tuple)):
                                strHtml = _format_element_aux(val.value)
                                DEBUG("val.value=%s", strHtml)
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % strHtml
                            else:
                                tmpCell = td_bgcolor + 'align="left">%s</td>' % val.value
                        else:
                            # This displays objects in a table: The top-level object must be
                            # in the same host, so there is no need to display a long label.
                            valTitle = lib_naming.ParseEntityUriShort(val)[0]
                            assert isinstance(valTitle, lib_util.six_text_type)

                            # There might be non-ascii characters such as accents etc...
                            try:
                                valTitle.encode('ascii')
                            except UnicodeEncodeError:
                                valTitle = "Not ascii"

                            valTitleUL = lib_exports.DotUL(valTitle)
                            tmpCell = td_bgcolor + 'href="%s" align="left" >%s</td>' % (
                                val, valTitleUL)

                    else:
                        try:
                            float(val)
                            tmpCell = td_bgcolor + 'align="right">%s</td>' % val
                        except:
                            # Wraps the string if too long. Can happen only with a literal.
                            tmpCell = td_bgcolor + 'align="left">%s</td>' % lib_exports.StrWithBr(
                                val)

                    idxKey = keyIndices[key]
                    columns[idxKey] = tmpCell

                if title:
                    title_key = title
                else:
                    title_key = subObjNam

                # Maybe the first column is a literal ?
                if subEntityId != "PLAINTEXTONLY":
                    # WE SHOULD PROBABLY ESCAPE HERE TOO.
                    columns[
                        0] = td_bgcolor_light + 'port="%s" href="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri, title_key)
                else:
                    subNodUri = lib_util.html_escape(subNodUri)
                    columns[
                        0] = td_bgcolor_light + 'port="%s" align="LEFT" >%s</td>' % (
                            subObjId, subNodUri)

                # Several scripts might have the same help text, so add a number.
                # "Title" => "Title"
                # "Title" => "Title/2"
                # "Title" => "Title/3" etc...
                # Beware that it is quadratic with the number of scripts with identical info.
                title_idx = 2
                title_uniq = title_key
                while title_uniq in dictHtmlLines:
                    title_uniq = "%s/%d" % (title_key, title_idx)
                    title_idx += 1

                # TODO: L'ordre est base sur les chaines mais devrait etre base sur le contenu. Exemple:
                # TODO: "(TUT_UnixProcess) Handle=10" vient avant "(TUT_UnixProcess) Handle=2"
                # TODO: title_uniq devrait etre plutot la liste des proprietes.
                # TODO: By clicking on the column names, we could change the order.
                dictHtmlLines[title_uniq] = "".join(columns)

            # Replace the first column by more useful information.
            numNodLst = len(nodLst)

            # WBEM and WMI classes have the syntax: "ns1/ns2/ns3:class" and the class it self can have base classes.
            # Survol classes have the syntax: "dir/dir/dir/class": This considers that namespaces are not really
            # necessary and can be replaced by classes. Also, there is a one-to-one match between the class inheritance
            # tree and its directory.
            # If Survol had to be started from scratch, there would be one Python class per survol class,
            # and they would be stored in the top dir "root/cimv2" ... it is not too late !
            #
            # This strips the upper directories: "mysql/instance" or "oracle/table", if this is a Survol class
            eltNam = subEntityGraphicClass.split("/")[-1]
            # This strips the namespace: "root/cimv2:CIM_LogicalElement", if this is a WBEM or WMI class.
            eltNam = eltNam.split(":")[-1]
            if not eltNam:
                # TODO: This is not the right criteria. Must select if we are listing scripts.
                eltNam = "script"

            eltNamPlural = lib_grammar.ToPlural(eltNam, numNodLst)
            txtElements = "%d %s" % (numNodLst, eltNamPlural)
            header = '<td border="1">' + lib_exports.DotBold(
                txtElements) + "</td>"

            # TODO: Replace each column name with a link which sorts the line based on this column.
            # The order of columns could be specified with an extra cgi argument with the columns names.
            for key in fieldsKeys:
                columnTitle = lib_kbase.qname(key, grph)
                columnTitle = columnTitle.replace("_", " ").capitalize()
                header += "<td border='1'>" + lib_exports.DotBold(
                    columnTitle) + "</td>"
            # With an empty key, it comes first when sorting.
            dictHtmlLines[""] = header

            # MAYBE SHOULD BE DONE TWICE !!!!! SEE ALSO ELSEWHERE !!!!
            subjUrlClean = subjUrl.replace('&', '&amp;')

            # BEWARE: The shape and the color of this HTML table is from the subjects,
            # because the elements can be of different classes, even if the share the same predicate.
            # TODO: Each row should have its own color according to its class.
            numFields = len(fieldsKeys) + 1

            # The rows of this HTML table could belong to different classes:
            # What the shared is the predicate. Hence, the predicate, property name is used as a title.
            propNamPlural = lib_grammar.ToPlural(propNam, None)
            helpText = "List of " + propNamPlural + " in " + labText

            # TODO: Le title and the content are not necessarily of the same class.
            # labTextWithBr is the first line of the table containing nodes linked with the
            # same property. Unfortunately we have lost this property.
            labText = lib_exports.TruncateInSpace(labText, 30)
            labTextWithBr = lib_exports.StrWithBr(labText)
            labTextWithBr += ": " + propNam

            if entity_id == "PLAINTEXTONLY":
                subjUrlClean = ""

            # This color is the table's contour.
            lib_patterns.WritePatterned(stream, subjEntityGraphicClass,
                                        subjNamTab, helpText, '"#000000"',
                                        subjUrlClean, numFields, labTextWithBr,
                                        dictHtmlLines)
Exemple #27
0
def WriteOtherUrls(topUrl):
    """
		This displays the URL to view the same document, in other ouput formats.
	"""

    WrtAsUtf('<table class="other_urls">')

    if topUrl:
        topUrl_with_mode = UrlInHtmlMode(topUrl)
        WrtAsUtf("""
		<tr><td align="left" colspan="2"><a href="%s"><b>Home</b></a></td></tr>
		""" % topUrl_with_mode)

    # Because Graphviz is not available on OVH platform.
    if not lib_util.modeOVH:
        WrtAsUtf("""
		<tr>
			<td class="other_urls"><a href="%s">SVG format</a></td>
			<td>Graphviz&trade; generated</td>
		</tr>
		""" % lib_exports.ModedUrl("svg"))

    WrtAsUtf("""
	<tr>
		<td class="other_urls"><a href="%s">RDF format</a></td>
		<td>Semantic Web, OWL standard / Prot&eacute;g&eacute;&trade;...</td>
	</tr>
	""" % lib_exports.ModedUrl("rdf"))

    urlD3 = lib_exports.UrlToMergeD3()

    WrtAsUtf("""
	<tr>
		<td class="other_urls"><a href="%s">D3</a></td>
		<td>Javascript D3 library</td>
	</tr>
	""" % urlD3)

    host_wbem_wmi = lib_util.currentHostname

    # This callback receives a RDF property (WBEM or WMI) and a map
    # which represents the CIM links associated to the current object.
    def WMapToHtml(theMap, propData):
        sys.stderr.write("WMapToHtml len=%d\n" % len(theMap))
        for urlSubj in theMap:
            (subjText, subjEntityGraphClass,
             subjEntityId) = lib_naming.ParseEntityUri(
                 lib_util.urllib_unquote(urlSubj))
            WrtAsUtf("<tr>")
            WrtAsUtf("<td valign='top'><a href='%s'>%s</a></td>" %
                     (str(urlSubj), subjText))
            WrtAsUtf("<td>")
            WrtAsUtf("<table>")
            for theProp, urlObj in theMap[urlSubj]:
                WrtAsUtf("<tr>")
                propNam = lib_exports.PropToShortPropNam(theProp)
                WrtAsUtf("<td><i>%s</i></td>" % propNam)
                if lib_kbase.IsLiteral(urlObj):
                    WrtAsUtf("<td>%s</td>" % (str(urlObj)))
                else:
                    (objText, objEntityGraphClass,
                     objEntityId) = lib_naming.ParseEntityUri(
                         lib_util.urllib_unquote(urlObj))
                    WrtAsUtf("<td><a href='%s'>%s</a></td>" %
                             (str(urlObj), objText))
                WrtAsUtf("</tr>")
            WrtAsUtf("</table>")
            WrtAsUtf("</td>")
        WrtAsUtf("</tr>")

    callingUrl = lib_util.RequestUri()
    (entity_label, entity_type,
     entity_id) = lib_naming.ParseEntityUri(callingUrl, longDisplay=True)
    nameSpace = ""

    mapWbem = CIM_ComputerSystem.AddWbemServers(host_wbem_wmi, nameSpace,
                                                entity_type, entity_id)
    WMapToHtml(mapWbem, pc.property_wbem_data)
    mapWmi = CIM_ComputerSystem.AddWmiServers(host_wbem_wmi, nameSpace,
                                              entity_type, entity_id)
    WMapToHtml(mapWmi, pc.property_wmi_data)
    mapSurvol = CIM_ComputerSystem.AddSurvolServers(host_wbem_wmi, nameSpace,
                                                    entity_type, entity_id)
    WMapToHtml(mapSurvol, pc.property_survol_agent)

    WrtAsUtf('</table>')
Exemple #28
0
def WriteScriptInformation(theCgi, gblCgiEnvList):
    """
		This displays general information about this script and the object if there is one.
	"""
    sys.stderr.write("WriteScriptInformation entity_type=%s\n" %
                     (theCgi.m_entity_type))

    # This is already called in lib_common, when creating CgiEnv.
    # It does not matter because this is very fast.
    callingUrl = lib_util.RequestUri()
    (entity_label, entity_graphic_class,
     entity_id) = lib_naming.ParseEntityUri(callingUrl, longDisplay=True)
    sys.stderr.write("entity_label=%s entity_graphic_class=%s entity_id=%s\n" %
                     (entity_label, entity_graphic_class, entity_id))

    # WrtAsUtf('<table class="list_of_merged_scripts">')
    WrtAsUtf('<table border="0">')
    if len(gblCgiEnvList):
        sys.stderr.write("gblCgiEnvList=%s\n" % str(gblCgiEnvList))
        # This step is dedicated to the merging of several scripts.

        WrtAsUtf(
            "<tr align=left><td colspan=2 align=left><h2>Fusion of data from %d scripts</h2></td></tr>"
            % len(gblCgiEnvList))
        for aCgiEnv in gblCgiEnvList:
            sys.stderr.write("aCgiEnv=%s\n" % str(aCgiEnv))
            sys.stderr.write("aCgiEnv.m_page_title=%s\n" %
                             str(aCgiEnv.m_page_title))
            sys.stderr.write("aCgiEnv.m_calling_url=%s\n" %
                             str(aCgiEnv.m_calling_url))
            (page_title_first, page_title_rest) = lib_util.SplitTextTitleRest(
                aCgiEnv.m_page_title)
            WrtAsUtf(
                "<tr><td><a href='%s'>%s</td><td><i>%s</i></td></tr>" %
                (aCgiEnv.m_calling_url, page_title_first, page_title_rest))

    else:
        (page_title_first,
         page_title_rest) = lib_util.SplitTextTitleRest(theCgi.m_page_title)
        WrtAsUtf("<tr><td colspan=2><h2>%s</h2></td></tr>" %
                 (page_title_first))
        if page_title_rest:
            WrtAsUtf("<tr><td colspan=2>%s</td></tr>" % (page_title_rest))

    WrtAsUtf('</table>')

    if theCgi.m_entity_type:
        # WrtAsUtf('m_entity_id: %s<br>'%(theCgi.m_entity_id))

        WrtAsUtf('<table class="table_script_information">')

        entity_module = lib_util.GetEntityModule(theCgi.m_entity_type)
        entDoc = entity_module.__doc__
        if not entDoc:
            entDoc = ""

        urlClass = lib_util.EntityClassUrl(theCgi.m_entity_type)
        urlClass_with_mode = UrlInHtmlMode(urlClass)
        WrtAsUtf("""
		<tr>
			<td><a href='%s'>%s</a></td>
			<td>%s</td>
		</tr>
		""" % (urlClass_with_mode, theCgi.m_entity_type, entDoc))

        for keyProp in theCgi.m_entity_id_dict:
            keyVal = theCgi.m_entity_id_dict[keyProp]

            WrtAsUtf("""
			<tr>
				<td>%s</td>
				<td>%s</td>
			</tr>
			""" % (keyProp, keyVal))

        WrtAsUtf('</table>')
Exemple #29
0
def _display_class_objects_no_jinja(dict_subj_prop_obj):
    """The subjects must be sorted by their title."""
    tuples_subjects_list = []
    for a_subj in dict_subj_prop_obj:
        subj_str = str(a_subj)
        subj_title, entity_graphic_class, entity_id = lib_naming.ParseEntityUri(
            subj_str)
        if subj_title:
            # The intention is to detect a specific test case with accented characters.
            if subj_title[0] == 'Y' and subj_title.find("Boulogne"):
                logging.debug("_display_class_objects_no_jinja subj_str=%s" %
                              subj_str)
                logging.debug("_display_class_objects_no_jinja subj_title=%s" %
                              subj_title)
                continue
        else:
            logging.debug("NO TITLE FOR %s" % subj_str)
        tuples_subjects_list.append(
            (a_subj, subj_str, subj_title, entity_graphic_class, entity_id))

    # Sorted by the title of the subject, which is the third value of the tuple.
    lib_util.natural_sort_list(tuples_subjects_list, key=lambda tup: tup[2])

    # Apparently, a problem is that "%" gets transformed into an hexadecimal number, preventing decoding.
    def _custom_decode_hex(the_str):
        the_str = lib_util.survol_unescape(the_str)
        return the_str.replace("%25", "%").replace("%2F", "/").replace(
            "%5C", "\\").replace("%3A", ":")

    # Now it iterates on the sorted list.
    # This reuses all the intermediate values.
    for a_subj, subj_str, subj_title, entity_graphic_class, entity_id in tuples_subjects_list:
        # FIXME: This is a specific test to catch a specific condition...
        if a_subj.find("Boulogne") >= 0 or subj_str.find(
                "Boulogne") >= 0 or subj_title.find("Boulogne") >= 0:
            logging.debug("a_subj=%s" % a_subj)
            logging.debug("subj_str=%s" % subj_str)
            logging.debug("subj_title=%s" % subj_title)
            continue

        dict_pred = dict_subj_prop_obj[a_subj]

        # Total number of lines.
        cnt_preds = 0
        for a_pred in dict_pred:
            lst_objs = dict_pred[a_pred]
            cnt_preds += len(lst_objs)

        must_write_col_one_subj = True

        subj_str_with_mode = _url_in_html_mode(subj_str)

        # The predicates, i.e. the properties associated a subject with an object,
        # must be alphabetically sorted.
        for a_pred in lib_util.natural_sorted(dict_pred):
            lst_objs = dict_pred[a_pred]

            pred_str = lib_exports.AntiPredicateUri(str(a_pred))
            cnt_objs = len(lst_objs)
            must_write_col_one_pred = True

            # The objects must be sorted by title.
            lst_tuples_objs = []
            for an_obj in lst_objs:
                obj_str = str(an_obj)
                obj_str = _custom_decode_hex(obj_str)
                obj_title = lib_naming.ParseEntityUri(obj_str)[0]
                lst_tuples_objs.append((an_obj, obj_str, obj_title))

            # Sorted by the title of the object, which is the third value of the tuple.
            lib_util.natural_sort_list(lst_tuples_objs, key=lambda tup: tup[2])

            for an_obj, obj_str, obj_title in lst_tuples_objs:
                # FIXME: This is a specific test to catch a specific condition...
                if an_obj.find("Boulogne") >= 0 or obj_str.find(
                        "Boulogne") >= 0 or obj_title.find("Boulogne") >= 0:
                    logging.debug("an_obj=%s" % an_obj)
                    logging.debug("obj_str=%s" % obj_str)
                    logging.debug("obj_title=%s" % obj_title)
                    continue

                # Nasty encoding errors. Probably the string should have been encoded before.
                if lib_util.isPlatformWindows and not lib_util.is_py3:
                    try:
                        dummy_str = obj_title.decode('ascii')
                    except UnicodeDecodeError as exc:
                        logging.debug("obj_title=%s" % obj_title)
                        obj_title = obj_title.decode('cp1252')

                yield '<tr>'

                if must_write_col_one_subj:
                    yield (
                        '<td valign="top" rowspan="%s"><a href="%s">%s</a></td>'
                        % (str(cnt_preds), subj_str_with_mode, subj_title))
                    must_write_col_one_subj = False

                if must_write_col_one_pred:
                    if a_pred not in _list_props_td_double_col_span:
                        yield '<td valign="top" rowspan="%s">%s</td>' % (
                            str(cnt_objs), pred_str)
                    must_write_col_one_pred = False

                if a_pred in _list_props_td_double_col_span:
                    col_span = 2
                else:
                    col_span = 1

                disp_mime_urls = True

                yield '<td colspan="%d">' % col_span
                if disp_mime_urls:
                    if lib_kbase.IsLink(an_obj):
                        obj_str_clean = lib_util.UrlNoAmp(obj_str)
                        mimeType = lib_mime.get_mime_type_from_url(
                            obj_str_clean)
                        if mimeType:
                            if mimeType.startswith("image/"):
                                yield (
                                    """<a href="%s"><img src="%s" alt="%s" height="42" width="42"></a>"""
                                    % (obj_str, obj_str, obj_title))
                            else:
                                yield """<a href="%s">%s</a>""" % (obj_str,
                                                                   obj_title)
                        else:
                            url_with_mode = lib_util.url_mode_replace(
                                obj_str, "html")
                            yield """<a href="%s">%s</a>""" % (url_with_mode,
                                                               obj_title)
                    else:
                        yield '%s' % obj_str
                else:
                    if lib_kbase.IsLink(an_obj):
                        url_with_mode = _url_in_html_mode(obj_str)
                        yield '<a href="%s">%s</a>' % (url_with_mode,
                                                       obj_title)
                    else:
                        yield '%s' % obj_str

                yield "</td>"
                yield "</tr>"
Exemple #30
0
def DispClassObjects(dictSubjPropObj):
    listPropsTdDoubleColSpan = [
        pc.property_information, pc.property_rdf_data_nolist2,
        pc.property_rdf_data_nolist1
    ]

    WrtAsUtf('<table class="class_objects">')

    # The subjects must be sorted by their title.
    lstTuplesSubjects = []
    for aSubj in dictSubjPropObj:
        subj_str = str(aSubj)
        (subj_title, entity_graphic_class,
         entity_id) = lib_naming.ParseEntityUri(subj_str)
        lstTuplesSubjects.append(
            (aSubj, subj_str, subj_title, entity_graphic_class, entity_id))

    # Sorted by the title of the subject, which is the third value of the tuple.
    lib_util.natural_sort_list(lstTuplesSubjects, key=lambda tup: tup[2])

    # Now it iterates on the sorted list.
    # This reuses all the intermediate values.
    for aSubj, subj_str, subj_title, entity_graphic_class, entity_id in lstTuplesSubjects:
        dictPred = dictSubjPropObj[aSubj]

        arrayGraphParams = lib_patterns.TypeToGraphParams(entity_graphic_class)
        # "Graphic_shape","Graphic_colorfill","Graphic_colorbg","Graphic_border","Graphic_is_rounded"
        colorClass = arrayGraphParams[1]

        # Total number of lines.
        cntPreds = 0
        for aPred in dictPred:
            lstObjs = dictPred[aPred]
            cntPreds += len(lstObjs)

        mustWriteColOneSubj = True

        subj_str_with_mode = UrlInHtmlMode(subj_str)

        # The predicates, i.e. the properties associated a subject with an object,
        # must be alphabetically sorted.
        for aPred in lib_util.natural_sorted(dictPred):
            lstObjs = dictPred[aPred]

            predStr = lib_exports.AntiPredicateUri(str(aPred))
            cntObjs = len(lstObjs)
            mustWriteColOnePred = True

            # The objects must be sorted by title.
            lstTuplesObjs = []
            for anObj in lstObjs:
                obj_str = str(anObj)
                obj_str = DesHex(obj_str)
                obj_title = lib_naming.ParseEntityUri(obj_str)[0]
                lstTuplesObjs.append((anObj, obj_str, obj_title))

            # Sorted by the title of the object, which is the third value of the tuple.
            lib_util.natural_sort_list(lstTuplesObjs, key=lambda tup: tup[2])

            for anObj, obj_str, obj_title in lstTuplesObjs:

                WrtAsUtf('<tr bgcolor="%s">' % colorClass)

                if mustWriteColOneSubj:
                    WrtAsUtf(
                        '<td valign="top" rowspan="%s"><a href="%s">%s</a></td>'
                        % (str(cntPreds), subj_str_with_mode, subj_title))
                    mustWriteColOneSubj = False

                if mustWriteColOnePred:
                    if aPred not in listPropsTdDoubleColSpan:
                        WrtAsUtf('<td valign="top" rowspan="%s">%s</td>' %
                                 (str(cntObjs), predStr))
                    mustWriteColOnePred = False

                if aPred in listPropsTdDoubleColSpan:
                    colSpan = 2
                else:
                    colSpan = 1

                dispMimeUrls = True

                WrtAsUtf('<td colspan="%d">' % (colSpan))
                if dispMimeUrls:
                    if lib_kbase.IsLink(anObj):
                        objStrClean = lib_util.UrlNoAmp(obj_str)
                        mimeType = lib_mime.GetMimeTypeFromUrl(objStrClean)
                        if mimeType:
                            if mimeType.startswith("image/"):
                                WrtAsUtf(
                                    """<a href="%s"><img src="%s" alt="%s" height="42" width="42"></a>"""
                                    % (obj_str, obj_str, obj_title))
                            else:
                                WrtAsUtf("""<a href="%s">%s</a>""" %
                                         (obj_str, obj_title))
                        else:
                            url_with_mode = lib_util.AnyUriModed(
                                obj_str, "html")
                            WrtAsUtf("""<a href="%s">%s</a>""" %
                                     (url_with_mode, obj_title))
                    else:
                        WrtAsUtf('%s' % (obj_str))
                else:
                    if lib_kbase.IsLink(anObj):
                        url_with_mode = UrlInHtmlMode(obj_str)
                        WrtAsUtf('<a href="%s">%s</a>' %
                                 (url_with_mode, obj_title))
                    else:
                        WrtAsUtf('%s' % (obj_str))

                WrtAsUtf("</td>")

                WrtAsUtf("</tr>")

    WrtAsUtf(" </table>")