2016-10-26 2 views
1

Я работаю над простой веб-службой в Prolog и хочу ответить на мои пользователи данными, отформатированными как JSON. Хорошим средством является reply_json_dict/1, который принимает словарь и преобразует его в ответ HTTP с хорошо отформатированным корпусом JSON.с использованием словарей в swi-prolog

Моя проблема заключается в том, что создание самого словарного слова ответа кажется немного громоздким. Например, когда я возвращаю некоторые данные, у меня есть идентификатор данных, но может/не иметь свойств данных (возможно, несвязанной переменной). На данный момент я делаю следующее:

OutDict0 = _{ id : DataId }, 
(nonvar(Props) -> OutDict1 = OutDict0.put(_{ attributes : Props }) ; OutDict1 = OutDict0), 
reply_json_dict(OutDict1) 

, который работает отлично, поэтому выход является { "id" : "III" } или { "id" : "III", "attributes" : "AAA" } в зависимости от того или не связан Props, но ... Я ищу более простой подход. В первую очередь потому, что если мне нужно добавить несколько дополнительных пар ключ/значение, я в конечном итоге с несколькими последствиями, как:

OutDict0 = _{ id : DataId }, 
(nonvar(Props) -> OutDict1 = OutDict0.put(_{ attributes : Props }) ; OutDict1 = OutDict0), 
(nonvar(Time) -> OutDict2 = OutDict1.put(_{ time : Time }) ; OutDict2 = OutDict1), 
(nonvar(UserName) -> OutDict3 = OutDict2.put(_{ userName : UserName }) ; OutDict3 = OutDict2), 
reply_json_dict(OutDict3) 

И это кажется просто неправильно. Есть ли более простой способ?

Приветствия, Яцек

ответ

1

Большое спасибо и Борис за предложения!Я закончил с комбинацией ваших идей:

dict_filter_vars(DictIn, DictOut) :- 
    findall(Key=Value, (get_dict(Key, DictIn, Value), nonvar(Value)), Pairs), 
    dict_create(DictOut, _, Pairs). 

Что я могу использовать так просто:

DictWithVars = _{ id : DataId, attributes : Props, time : Time, userName : UserName }, 
dict_filter_vars(DictWithVars, DictOut), 
reply_json_dict(DictOut) 
+0

Хорошо, что вы решили это с помощью этих входов! Вопрос все еще как-то остается: зачем даже создавать dict, когда у вас уже есть список, который вам нужен? Учтите, что каждый раз, когда вы используете dict, это делает ваше приложение менее портативным, потому что dicts не являются стандартной функцией Prolog ... – mat

+0

Хорошая точка зрения, хотя я в меньшей степени обеспокоен мобильностью на данный момент. Самое приятное в том, что он держит ключи уникальными, поэтому сопоставление объектов JSON более естественно. Обратите внимание: несмотря на то, что стандарт JSON позволяет использовать не-уникальные ключи, многие библиотеки этого не делают, поэтому лучше сохранить их уникальными. – Jacek

+0

Вам не нужна скобка вокруг «Key = Value» в первом аргументе вашего 'findall'. –

3

Вместо того, чтобы возиться со словарями, моя рекомендация в данном случае является использование другого предиката испускать   JSON.

Например, рассмотрите json_write/2, что позволяет испускать JSON, а также на текущем выходе, как того требуют библиотеки HTTP  .

Пусть ваше представление полей данных является общим Name(Value) обозначение, которое используется на протяжении библиотек HTTP для обработки опций:

 
Fields0 = [attributes(Props),time(Time),userName(UserName)], 

Использование include/3, весь ваш пример будет выглядеть так:

 
main :- 
     Fields0 = [id(DataId),attributes(Props),time(Time),userName(UserName)], 
     include(ground, Fields0, Fields), 
     json_write(current_output, json(Fields)). 

Вы можете попробовать сами, подключив подходящие значения для отдельных элементов, которые являются sin gleton variables в фрагменте выше.

Например, мы можем (произвольно) использовать:

 
     Fields0 = [id(i9),attributes(_),time('12:00'),userName(_)], 

получает:

 
?- main. 
{"id":"i9", "time":"12:00"} 
true. 

Необходимо только, чтобы излучать подходящие Content-Type заголовка, и имеют тот же вывод, что reply_json_dict/1дал бы вам.

+1

Это выглядит аккуратным, большое предложение, спасибо. На данный момент я немного застрял со словарями. Постараюсь судить, сколько стоит переделать мой код на вашем пути. Cheers, Jacek – Jacek

+2

Отлично! Обратите внимание, что необходимые изменения крайне локальны: даже если весь остальной код использует словари, вы можете выводить значения таким образом, как я начертил, просто построив вместо этого список * вместо словаря. – mat

+1

@Jacek Вы можете сделать словарь фильтрованного списка с 'dict_create (D, _, Fields)' или добавить элементы списка в существующий dict с 'D = D0.put (Fields)'. –

2

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

?- Props = [a,b,c], get_time(Time), 
    D0 = _{id:001}, 
    include(ground, [props:Props,time:Time,user:UserName], Fs), 
    D = D0.put(Fs). 
D0 = _17726{id:1}, 
Fs = [props:[a, b, c], time:1477557597.205908], 
D = _17726{id:1, props:[a, b, c], time:1477557597.205908}. 

Это заимствует идею в ответ мата использовать include(ground).

Смежные вопросы