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
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
def _format_element(val, depth=0): if lib_kbase.IsLink(val): valTitle = "_format_element " + external_url_to_title(val) valTitleUL = lib_exports.DotUL(valTitle) return "<td align='left' balign='left' border='0' href='%s'>%s</td>" % ( val, valTitleUL) resStr = _format_element_aux(val, depth) return "<td align='left' balign='left' border='0'>%s</td>" % resStr
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('&', '&') 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('&', '&') # 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)
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('&', '&') 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('&', '&') # 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)