diff options
Diffstat (limited to 'jsonpointer.py')
-rw-r--r-- | jsonpointer.py | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/jsonpointer.py b/jsonpointer.py new file mode 100644 index 0000000..b1f0d72 --- /dev/null +++ b/jsonpointer.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# python-json-pointer - An implementation of the JSON Pointer syntax +# https://github.com/stefankoegl/python-json-pointer +# +# Copyright (c) 2011 Stefan Kögl <stefan@skoegl.net> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +""" Identify specific nodes in a JSON document according to +http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 """ + +# Will be parsed by setup.py to determine package metadata +__author__ = 'Stefan Kögl <stefan@skoegl.net>' +__version__ = '0.1' +__website__ = 'https://github.com/stefankoegl/python-json-pointer' +__license__ = 'Modified BSD License' + + +import urllib + + +class JsonPointerException(Exception): + pass + + +def resolve_pointer(doc, pointer): + """ + Resolves pointer against doc and returns the referenced object + + >>> obj = {"foo": {"anArray": [ {"prop": 44}], "another prop": {"baz": "A string" }}} + + >>> resolve_pointer(obj, '/') == obj + True + + >>> resolve_pointer(obj, '/foo') + {'another prop': {'baz': 'A string'}, 'anArray': [{'prop': 44}]} + + >>> resolve_pointer(obj, '/foo/another%20prop') + {'baz': 'A string'} + + >>> resolve_pointer(obj, '/foo/another%20prop/baz') + 'A string' + + >>> resolve_pointer(obj, '/foo/anArray/0') + {'prop': 44} + """ + + parts = pointer.split('/') + if parts.pop(0) != '': + raise JsonPointerException('location must starts with /') + + parts = map(urllib.unquote, parts) + + for part in parts: + doc = walk(doc, part) + + return doc + + +def walk(doc, part): + """ Walks one step in doc and returns the referenced part """ + + if not part: + return doc + + # Its not clear if a location "1" should be considered as 1 or "1" + # We prefer the integer-variant if possible + part_variants = _try_parse(part) + [part] + + for variant in part_variants: + try: + return doc[variant] + except: + continue + + raise JsonPointerException("'%s' not found in %s" % (part, doc)) + + +def _try_parse(val, cls=int): + try: + return [cls(val)] + except: + return [] |