Hi all,
Perhaps this is hidden somewhere in the rdflib repo and I wasn’t able to find it, but I found myself wanting to encode rdflib.term.Literal values to JSON as e.g. {“value”: literal.value, “datatype”: literal.datatype, …}. I ended up adapting the advice of a SO post. Here is my answer on SO with an rdflib example: [https://stackoverflow.com/a/69588931/1820042](https://stackoverflow.com/a/69588931/1820042).
Also reproduced below. I hope folks find it useful. Also feel free to point out where this has already been done, and I’ll pip install that instead of my custom code!
from json.encoder import (_make_iterencode, JSONEncoder,
encode_basestring_ascii, INFINITY,
encode_basestring)
class CustomObjectEncoder(JSONEncoder):
def iterencode(self, o, _one_shot=False):
"""Encode the given object and yield each string
representation as available.
For example::
for chunk in JSONEncoder().iterencode(bigobject):
mysocket.write(chunk)
Change from json.encoder.JSONEncoder.iterencode is setting
_one_shot=False and isinstance=self.isinstance
in call to `_make_iterencode`.
And not using `c_make_encoder`.
"""
if self.check_circular:
markers = {}
else:
markers = None
if self.ensure_ascii:
_encoder = encode_basestring_ascii
else:
_encoder = encode_basestring
def floatstr(o, allow_nan=self.allow_nan,
_repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
# Check for specials. Note that this type of test is processor
# and/or platform-specific, so do tests which don't depend on the
# internals.
if o != o:
text = 'NaN'
elif o == _inf:
text = 'Infinity'
elif o == _neginf:
text = '-Infinity'
else:
return _repr(o)
if not allow_nan:
raise ValueError(
"Out of range float values are not JSON compliant: " +
repr(o))
return text
_iterencode = _make_iterencode(
markers, self.default, _encoder, self.indent, floatstr,
self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, _one_shot=False, isinstance=self.isinstance)
return _iterencode(o, 0)
Example subclass:
import datetime
from rdflib.term import Literal, BNode
class RDFTermEncoder(CustomObjectEncoder):
def isinstance(self, o, cls):
if isinstance(o, (Literal, BNode)):
return False
return isinstance(o, cls)
def default(self, o):
if isinstance(o, Literal):
rv = {"value": o.value}
if o.datatype is not None:
rv["datatype"] = o.datatype
if o.language is not None:
rv["lang"] = o.language
return rv
if isinstance(o, BNode):
return "http://localhost/bnode/" + str(o)
if isinstance(o, datetime.datetime):
return o.isoformat()
if isinstance(o, datetime.date):
return str(o)
# Let the base class default method raise the TypeError
return super().default(o)
I just used this successfully for my work as
db_json = json.loads(json.dumps(db_custom, cls=RDFTermEncoder))
Best,
Donny
—
Donny Winston, PhD (he/him/his) | Polyneme LLC
https://donnywinston.com | https://polyneme.xyz
If I’ve emailed you, I’d love to speak with you.
Schedule a meeting (15min+): https://meet.polyneme.xyz
--
http://github.com/RDFLib
---
You received this message because you are subscribed to the Google Groups "rdflib-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rdflib-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rdflib-dev/5a70d567-652c-45da-b500-7776447210dd%40www.fastmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rdflib-dev/CADjV5jeHfZUZgYnABPZoJxgJxxouLcvODAXXyaYb-RYx7W-aVw%40mail.gmail.com.