[cl-json-devel] Guidance requested: how to dispatch members to external decoders?
Hraban Luyat
hraban at 0brg.net
Mon Aug 15 19:20:09 UTC 2011
Aha! :internal-decoder! Perfect, exactly what I need. Thank you very
much for your extensive explanation.
Also, I will change the spec to send the data as an array instead of
an object to enforce order.
Thanks again.
Sincerely,
Hraban Luyat
2011/8/15 Boris Smilga <boris.smilga at gmail.com>:
> On 14 Aug 2011, at 16:24, Hraban Luyat wrote:
>
>> The semantics of my incoming messages are thus:
>>
>> object:
>> - "type": string denoting the type
>> - "payload": type-specific payload
>>
>> I want to create a decoder that only extracts the type and uses that
>> to determine which decoder to send the payload to. Then it continues
>> with whatever lisp object the decoder returned.
>>
>> What I thought would be appropriate is to create a generic function;
>>
>> (defgeneric json->data (type payload))
>>
>> and then simply register decoders as follows:
>>
>> (defmethod json->data ((type (eq :foo)) payload)
>> "Decode message of type foo."
>> ...)
>>
>> (defmethod json->data ((type (eq :bar)) payload)
>> "Decode message of type bar."
>> ...)
>>
>> But now I am not really sure how to glue this together. What would you
>> recommend? Is this the right frame of mind at all or should I take a
>> totally different approach?
>
> Why, yes, you can certainly make it that way.
>
> Re. gluing it together: there is some relevant reading in CL-JSON User Guide
> under http://common-lisp.net/project/cl-json/#DECODER-CUSTOMIZATION . To
> apply the API to your case, you'd have to define a dynamic variable which
> would store the type while the decoder is waiting for the payload to arrive,
> and another, which would store the payload while the decoder is waiting for
> the end of the object:
>
> (defvar *payload-type* nil)
>
> (defvar *payload* nil)
>
> Then you customize your decoder to decode top-level JSON {} objects in the
> following way:
>
> (let ((default-decoder (json:current-decoder)))
> (json:bind-custom-vars
> (;; Initialize variables in the dynamic scope of the object:
> :beginning-of-object
> (lambda () (setq *payload-type* nil *payload* nil))
> ;; The handler for key sets the internal decoder and the
> ;; handler for value depending on the key:
> :object-key
> (lambda (json-id)
> (let ((lisp-id
> (json:safe-json-intern
> (funcall json:*json-identifier-name-to-lisp*
> json-id))))
> (case lisp-id
> ;; If the key is "type", the value is decoded in the
> ;; standard way and stored in *payload-type*:
> ((:type)
> (json:set-custom-vars
> :internal-decoder
> default-decoder
> :object-value
> (lambda (value) (setq *payload-type* value))))
> ;; If the key is "payload", the value is decoded by
> ;; your type-specific decoder and stored in *payload*:
> ((:payload)
> (json:set-custom-vars
> :internal-decoder
> (lambda (stream)
> (json->data *payload-type* stream))
> :object-value
> (lambda (value) (setq *payload* value)))))))
> ;; The value of the whole object is the value decoded from
> ;; its "payload" field:
> :end-of-object
> (lambda () *payload*)
> ;; This you need only if your type+payload objects may be
> ;; nested:
> :object-scope
> '(*payload* *payload-type*))
> (decode-json)))
>
> For clarity, I've left out any safety checks, which you might want to put in
> here or there. Also, this code includes a tacit assumption that, in your
> objects, the "type" field always precedes the "payload" field. If you
> cannot guarantee this, you'll have to provide a json->data method for type
> NIL which maybe decodes to some intermediate representation, and add code to
> the value handler for "type" fields to finalize such semi-parsed values if
> found in *payload*.
>
> Hope this helps; feel free to ask me for clarifications if you find some
> portion of the code to be too obscure.
>
> Sincerely,
> - B. Smilga.
>
>
> _______________________________________________
> cl-json-devel mailing list
> cl-json-devel at common-lisp.net
> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/cl-json-devel
>
More information about the cl-json-devel
mailing list