""" A commandline tool for drawing RDF graphs in Graphviz DOT format You can draw the graph of an RDF file directly: .. code-block: bash rdf2dot my_rdf_file.rdf | dot -Tpng | display """ from __future__ import annotations import collections import html import sys from typing import Any, Dict, TextIO import rdflib import rdflib.extras.cmdlineutils from rdflib import XSD from rdflib.graph import Graph from rdflib.term import Literal, Node, URIRef LABEL_PROPERTIES = [ rdflib.RDFS.label, rdflib.URIRef("http://purl.org/dc/elements/1.1/title"), rdflib.URIRef("http://xmlns.com/foaf/0.1/name"), rdflib.URIRef("http://www.w3.org/2006/vcard/ns#fn"), rdflib.URIRef("http://www.w3.org/2006/vcard/ns#org"), ] XSDTERMS = [ XSD[x] for x in ( "anyURI", "base64Binary", "boolean", "byte", "date", "dateTime", "decimal", "double", "duration", "float", "gDay", "gMonth", "gMonthDay", "gYear", "gYearMonth", "hexBinary", "ID", "IDREF", "IDREFS", "int", "integer", "language", "long", "Name", "NCName", "negativeInteger", "NMTOKEN", "NMTOKENS", "nonNegativeInteger", "nonPositiveInteger", "normalizedString", "positiveInteger", "QName", "short", "string", "time", "token", "unsignedByte", "unsignedInt", "unsignedLong", "unsignedShort", ) ] EDGECOLOR = "blue" NODECOLOR = "black" ISACOLOR = "black" def rdf2dot(g: Graph, stream: TextIO, opts: Dict[str, Any] = {}): """ Convert the RDF graph to DOT writes the dot output to the stream """ fields = collections.defaultdict(set) nodes: Dict[Node, str] = {} def node(x: Node) -> str: if x not in nodes: nodes[x] = "node%d" % len(nodes) return nodes[x] def label(x: Node, g: Graph): for labelProp in LABEL_PROPERTIES: # noqa: N806 l_ = g.value(x, labelProp) if l_: return l_ try: # type error: Argument 1 to "compute_qname" of "NamespaceManager" has incompatible type "Node"; expected "str" return g.namespace_manager.compute_qname(x)[2] # type: ignore[arg-type] except Exception: return x def formatliteral(l: Literal, g): # noqa: E741 v = html.escape(l) if l.datatype: return ""%s"^^%s" % (v, qname(l.datatype, g)) elif l.language: return ""%s"@%s" % (v, l.language) return ""%s"" % v def qname(x: URIRef, g: Graph) -> str: try: q = g.compute_qname(x) return q[0] + ":" + q[2] except Exception: return x def color(p): return "BLACK" stream.write('digraph { \n node [ fontname="DejaVu Sans" ] ; \n') for s, p, o in g: sn = node(s) if p == rdflib.RDFS.label: continue if isinstance(o, (rdflib.URIRef, rdflib.BNode)): on = node(o) opstr = ( "\t%s -> %s [ color=%s, label=< %s > ] ;\n" ) # type error: Argument 1 to "qname" has incompatible type "Node"; expected "URIRef" stream.write(opstr % (sn, on, color(p), qname(p, g))) # type: ignore[arg-type] else: # type error: Argument 1 to "qname" has incompatible type "Node"; expected "URIRef" fields[sn].add((qname(p, g), formatliteral(o, g))) # type: ignore[arg-type] for u, n in nodes.items(): stream.write("# %s %s\n" % (u, n)) f = [ "
| %s | |
| " + "%s | " + "