Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I had this exact problem in Python and wanted to be able to use dot-notation (i.e "book.metadata.title") to query the structure (like MongoDB, etc do) so built my own library for doing it:

https://github.com/imranghory/pson

(Also available from pypi via "pip install pson")



  class MyDict(object):
    def __init__(self, d):
      self.__dict__.extend(d)
    def __repr__(self):
      return repr(self.__dict__)

  import json
  r = json.loads('{"body": {"translations": [{"tr...', object_hook=MyDict)

  >>> r.header.title
  u'Hello World'

  >>> r.body.translations[1]
  {u'translation': u'guten tag', u'language': u'german'}

  >>> map(attrgetter('language'), r.body.translations)
  [u'french', u'german']


The code in the library is actually pretty simple, but deals with many practical edge-cases (stepping into an array, handling missing values gracefully, etc.) that the above code doesn't.

My longer term intention is adding other useful json manipulation and search functions to the library.


Yeah. I just don't like putting syntax in a string; I'd rather use Python itself.

By the way, you should remove the pprint import from the library, since you don't use it :)


I considered that approach but found the JSON returned by some third-party apis contained characters in keys (dashes, spaces, etc) which have special meanings in python so can't be used natively.


Interesting, I thought I was a rare breed using the following function quite a bit in my code. However, it seems these things are a dime a dozen. -- I modeled this one after the way Django does it. I think the only thing it does that yours doesn't is all a function if one of the dict values is an object. Thats useful for get_somevalue() type things on a tree of objects.

    def rget(obj, attrstr, default=None, delim='.'):
        try:
            parts = attrstr.split(delim, 1)
            attr = parts[0]
            attrstr = parts[1] if len(parts) == 2 else None
            if isinstance(obj, dict): value = obj[attr]
            elif isinstance(obj, list): value = obj[int(attr)]
            elif isinstance(obj, tuple): value = obj[int(attr)]
            elif isinstance(obj, object): value = getattr(obj, attr)
            if attrstr: return rget(value, attrstr, default, delim)
            return value
        except:
            return default


The jmespath library from boto is quite similar to this, and possibly has way more traction. Some differences:

- jmespath uses `body.translations[0].language` instead of `body.translations.0.language`, and it can also do `body.translations[].language`.

- jmespath doesn't support the "missing" use case




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: