Какой лучший способ выбрать другую клавишу JSON, если первая не существует с помощью JMESPath? - PullRequest
0 голосов
/ 24 марта 2020

Имеется JSON с некоторыми данными о продукте, например:

{
  "sku": 123,
  "product": {
    "name": "Some name",
    "images": {
      "normalImage": "http://somelink.com/1.jpg",
      "bigImage": "http://somelink.com/1b.jpg"
    }
  }
}

Я хочу выбрать ссылку на изображение, но bigImage существует только в некоторых продуктах, поэтому иногда мне нужно выбрать normalImage вместо.

Очевидное решение выглядит так:

jmespath.search('product.images.bigImage') or jmespath.search('product.images.normalImage')

но я чувствую, что это можно сделать лучше. Как это сделать оптимальным образом, используя синтаксис JMESPath?

Ответы [ 2 ]

2 голосов
/ 01 апреля 2020

Как насчет следующего для использования только синтаксиса JMESPath?

product.images.[bigImage, normalImage][?@]|[0]

Идея состоит в том, что мы создаем массив всех изображений, которые мы хотим использовать в порядке предпочтения, отфильтровывая отсутствующие затем выберите первый элемент в оставшемся массиве.

Предостережение - это не различает guish между пропущенными и null (или другими значениями типа "ложь", такими как пустые строки), так вам, возможно, придется немного его настроить, если это имеет значение для вашего конкретного случая.

1 голос
/ 24 марта 2020

Для этого можно создать класс CustomFunctions, аналогично примерам, приведенным на странице GitHub .

from jmespath import search
from jmespath import functions
from jmespath import Options

from json import loads

class CustomFunctions(functions.Functions):

    # Method that selects 'bigImage' key value if it exists
    # Otherwise return 'normalImage' value
    # dict.get() is perfect for this, since it returns a default value if a key doesn't exist
    # Use type 'object' since thats the equivalant type to a Python dictionary in JSON
    # Make sure to decorate function signature as well to indicate types
    # Make sure to also put _func_ before your function name
    @functions.signature({'types': ['object']})
    def _func_choose_key(self, d):
        return d.get('bigImage', d['normalImage'])

if __name__ == "__main__":

    # Get custom function options
    options = Options(custom_functions=CustomFunctions())

    # Test method which runs JMESPath query with custom function
    def test(json):
        json_dict = loads(json)
        return search('product.images | choose_key(@)', json_dict, options=options)


    # TEST 1 - bigImage key exists
    json1 = """{
        "sku": 123,
        "product": {
            "name": "Some name",
            "images": {
                "normalImage": "http://somelink.com/1.jpg",
                "bigImage": "http://somelink.com/1b.jpg"
            }
        }
    }"""

    print("Test1: %s" % test(json1))


    # TEST 2 - bigImage key doesn't exist
    json2 = """{
        "sku": 123,
        "product": {
            "name": "Some name",
            "images": {
                "normalImage": "http://somelink.com/1.jpg"
            }
        }
    }"""


    print("Test2: %s" % test(json2))

, которая выводит следующие результаты:

Test1: http://somelink.com/1b.jpg  # When bigImage key exists
Test2: http://somelink.com/1.jpg   # When bigImage key doesn't exist

Если JMESPath становится слишком сложным, мы всегда можем использовать старый добрый стандартный словарный подход:

def test2(json):
    json_dict = loads(json)
    images = json_dict["product"]["images"]
    return images.get("bigImage", images["normalImage"])

# TEST 1 - bigImage key exists
json1 = """{
    "sku": 123,
    "product": {
        "name": "Some name",
        "images": {
            "normalImage": "http://somelink.com/1.jpg",
            "bigImage": "http://somelink.com/1b.jpg"
        }
    }
}"""

print("Test1: %s" % test2(json1))


# TEST 2 - bigImage key doesn't exist
json2 = """{
    "sku": 123,
    "product": {
        "name": "Some name",
        "images": {
            "normalImage": "http://somelink.com/1.jpg"
        }
    }
}"""


print("Test2: %s" % test2(json2))

, который также печатает те же результаты:

Test1: http://somelink.com/1b.jpg  # When bigImage key exists
Test2: http://somelink.com/1.jpg   # When bigImage key doesn't exist
...