xapix-io / paos

Clojure SOAP client
Eclipse Public License 1.0
93 stars 12 forks source link

add function builder for making response parsers based on output-mapping from parsed wsdl #1

Closed DeLaGuardo closed 6 years ago

DeLaGuardo commented 6 years ago

Incomming data:

{:soapenv:Envelope ;; Top level xml tag
   {:soapenv:Header nil,
    :soapenv:Body
    {:v1:airlineByIcaoResponse
     {:return|attrs ;; set of attributes for :return tag
      {:offset nil}
      :return ;; this xml tag can be found multiple times in parent tag (:v1:airlineByIcaoResponse)
      [{:category nil,
        :iata nil,
        :name nil,
        :icao nil,
        :dateFrom nil,
        :dateTo nil,
        :active nil,
        :phoneNumber nil,
        :fs nil}]}}}}

Output:

fn xml_string => map

This function should use clojure.zip for lazy xml parsing without growing heap.

dupuchba commented 5 years ago

Hello, I'd like to parse my response based on the output-mapping. Have you done any-work on it ? Before I implement-it myself :-)

zarkone commented 5 years ago

hey, i think you mean something like this:

(defn convert-template
  "Converts soap templates with `?` to renderable template"
  [template]
  (->> template
       (service/xml->element)
       (service/->template)))

(defn render [template content]
  (selmer/render template content))

(defn make-parser [template]
  (-> template
      (service/xml->element)
      (service/->parse-fn)))

?

dupuchba commented 5 years ago

I don't quite get what template means in the project. I request a resource with success with a big xml but if I try to use service/parse-response it returns an almost empty response but the xml is pretty big. So thought that some response context was not set. Anyway I can manually extract the xml but what a pain in the ass ^^

DeLaGuardo commented 5 years ago

Could you describe your desired workflow?

But if I understand you right ->

Normally parsing is done by function generated out from wsdl file which describes how your server's responses might look like (as an xml template <users><user><id>?</id><address>?</address></user></root>) If you don't have wsdl or autogenerated xml template is broken - you can make your own service by using paos.service/->service function.

Simplest example from the repl:

user=> (def response-tpl "<root><usersInfo><!--1 or more repetitions:--><user><!--type: integer--><id>?</id><!--Optional:--><name>?</name></user><count>?</count></usersInfo></root>")
#'user/response-tpl
user=> (def response-xml "<root><usersInfo><user><id>0</id><name>Kirill</name></user><user><id>1</id></user><count>2</count></usersInfo></root>")
#'user/response-xml
user=> (def service (p/->service nil nil nil response-tpl nil))
#'user/service
user=> (p/parse-response service response-xml)
{"root" {"usersInfo" {"users" [{"user" {"id" {"__value" "0"}, "name" {"__value" "Kirill"}}} {"user" {"id" {"__value" "1"}, "name" {"__value" nil}}}] "count" {"__value" "2"}}}}

But in that case you have to prepare your template by yourself. There are some rules:

dupuchba commented 5 years ago

@DeLaGuardo Thanks a lot for your time, your response might help.

Concerning my "issue" : I do have a wsdl file containing output format which is not taken into account during response parsing : Example :

<xs:complexType name="UserInfo">
<xs:sequence>
<xs:element name="LastName" type="xs:string"/>
<xs:element name="FirstName" type="xs:string"/>
<xs:element name="Surname" type="xs:string"/>
</xs:sequence>
</xs:complexType>

The xml response is working good but parsing send back an empty map with the "Envelop" tag. That's why I was looking into templating

DeLaGuardo commented 5 years ago

Is it possible to share your wsdl? There are a lot of corner cases that are not covered by paos, but example might help to improve it.

dupuchba commented 5 years ago

hum, anyway to share it privetely ?

DeLaGuardo commented 5 years ago
dupuchba commented 5 years ago

done