← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/http-client-wrapper into lp:zorba

 

Federico Cavalieri has proposed merging lp:~zorba-coders/zorba/http-client-wrapper into lp:zorba.

Requested reviews:
  Cezar Andrei (cezar-andrei)
  Chris Hillery (ceejatec)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980

HTTP client request/response conversion in a separate module
-- 
https://code.launchpad.net/~zorba-coders/zorba/http-client-wrapper/+merge/176980
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'modules/http-client/CMakeLists.txt'
--- modules/http-client/CMakeLists.txt	2013-07-25 09:30:55 +0000
+++ modules/http-client/CMakeLists.txt	2013-07-25 15:45:37 +0000
@@ -39,6 +39,10 @@
     DECLARE_ZORBA_MODULE(FILE json/http-client.xq VERSION 1.0
       URI "http://zorba.io/modules/http-client";
       LINK_LIBRARIES ${CURL_LIBRARIES})
+      
+    DECLARE_ZORBA_MODULE(FILE conv/http-client-wrapper.xq VERSION 1.0
+      URI "http://zorba.io/modules/http-client-wrapper";
+      LINK_LIBRARIES ${CURL_LIBRARIES})
     
     IF (WIN32) # Copy certificates for windows only
       IF (MSVC_IDE)

=== added directory 'modules/http-client/conv'
=== added file 'modules/http-client/conv/http-client-wrapper.xq'
--- modules/http-client/conv/http-client-wrapper.xq	1970-01-01 00:00:00 +0000
+++ modules/http-client/conv/http-client-wrapper.xq	2013-07-25 15:45:37 +0000
@@ -0,0 +1,772 @@
+xquery version "3.0";
+
+(:
+ : Copyright 2006-2009 The FLWOR Foundation.
+ :
+ : Licensed under the Apache License, Version 2.0 (the "License");
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an "AS IS" BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+:)
+
+
+(:~
+ : <p>This module provides conversion functions between the 
+ : XML Expath http-client request and response formats and the 
+ : JSON http-client request and response formats used by the
+ : <code>http://zorba.io/modules/http-client</code> module.   
+ : </p>
+ :
+ : <p>This module is reserved for internal use by the 
+ : <code>http://www.zorba-xquery.com/modules/http-client</code> and the 
+ : <code>http://expath.org/ns/http-client</code> modules.
+ : This module may be removed at any time. Method signature and 
+ : semantics may change.        
+ : </p>
+ :
+ : @author Federico Cavalieri
+ : @project Zorba/Input Output/HTTP Client
+ :)
+module namespace http-wrapper = "http://zorba.io/modules/http-client-wrapper";;
+
+import module namespace error = "http://expath.org/ns/error";;
+import module namespace json-http = "http://zorba.io/modules/http-client";;
+import module namespace libjn = "http://jsoniq.org/function-library";;
+
+import schema namespace http-schema = "http://expath.org/ns/http-client";;
+
+declare namespace an = "http://www.zorba-xquery.com/annotations";;
+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";;
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+declare namespace ser  = "http://www.w3.org/2010/xslt-xquery-serialization";;
+declare namespace jn = "http://jsoniq.org/functions";;
+
+declare option ver:module-version "1.0";
+
+(:~
+ : <p>This function sends an HTTP request and returns the corresponding response.
+ : This function is declared sequential and can be used to issue
+ : requests which change the state of the server.</p>
+ :
+ : <p>Its inputs, outputs, and behavior are identical to the
+ : <a href="http://expath.org/spec/http-client";>EXPath http-client</a>'s
+ : send-request() function (except that HTML responses are not tidied
+ : into XML - see <a href="#expath_relation">the note above</a>). It
+ : is provided here for use in Zorba installations that do not have
+ : the EXPath module available. If you have the option of using the 
+ : EXPath module instead of this function, please do so, as it will
+ : allow your application to be more interoperable between different
+ : XQuery engines.</p>
+ :
+ : <p>Full documentation of the $request parameter can be found in
+ : <a href="http://expath.org/spec/http-client#d2e183";>the EXPath
+ : specification</a>.</p>
+ :
+ : @param $request Contains the various parameters of the request (see above).
+ : @param $href The URL to which the request will be made (see
+ :  <a href="#url_string">note</a> above). If this
+ :  parameter is specified, it will override the "href" attribute of
+ :  $request.
+ : @param $bodies is the request body content, for HTTP methods that can
+ :  contain a body in the request (i.e. POST and PUT). It is an error if this
+ :  param is not the empty sequence for methods 
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error error:HC001 An HTTP error occurred.
+ : @error error:HC002 Error parsing the response content as XML.
+ : @error error:HC003 With a multipart response, the override-media-type must be either a multipart media type or application/octet-stream.
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type).
+ : @error error:HC005 The input request element is not valid.
+ : @error error:HC006 A timeout occurred waiting for the response.
+ : @error error:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request
+~:)
+declare %an:sequential function http-wrapper:http-sequential-request(
+  $request as element()?,
+  $href as xs:string?,
+  $bodies as item()*) as item()+
+{
+  try 
+  {
+     {
+       variable $json-request := http-wrapper:json-request($request, $href, $bodies);
+       variable $json-response := json-http:send-request($json-request);       
+       variable $xml-response :=  http-wrapper:xml-response($json-response, fn:data($request/@override-media-type));         
+       $xml-response       
+     }
+  } catch XPTY0004 {
+    fn:error($error:HC005, "The input request element is not valid.")
+  } catch json-http:HTTP {
+    fn:error($error:HC001, "An HTTP error occurred.")
+  } catch json-http:REQUEST {
+    fn:error($error:HC005, "The input request element is not valid.")
+  } catch json-http:TIMEOUT {
+    fn:error($error:HC006, "A timeout occurred waiting for the response.")
+  } catch json-http:FOLLOW {
+    fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.")
+  } catch json-http:CHARSET {
+    fn:error($error:HC005, "The input request element is not valid: invalid charset specified.")
+  } catch * {
+    fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value)
+  }
+};
+
+(:~
+ : <p>This function sends an HTTP request and returns the corresponding response.
+ : This function is declared non-deterministic and should only be used to issue
+ : requests which do not change the state of the server.</p>
+ :
+ : <p>Its inputs, outputs, and behavior are identical to the
+ : <a href="http://expath.org/spec/http-client";>EXPath http-client</a>'s
+ : send-request() function (except that HTML responses are not tidied
+ : into XML - see <a href="#expath_relation">the note above</a>). It
+ : is provided here for use in Zorba installations that do not have
+ : the EXPath module available. If you have the option of using the 
+ : EXPath module instead of this function, please do so, as it will
+ : allow your application to be more interoperable between different
+ : XQuery engines.</p>
+ :
+ : <p>Full documentation of the $request parameter can be found in
+ : <a href="http://expath.org/spec/http-client#d2e183";>the EXPath
+ : specification</a>.</p>
+ :
+ : @param $request Contains the various parameters of the request (see above).
+ : @param $href The URL to which the request will be made (see
+ :  <a href="#url_string">note</a> above). If this
+ :  parameter is specified, it will override the "href" attribute of
+ :  $request.
+ : @param $bodies is the request body content, for HTTP methods that can
+ :  contain a body in the request (i.e. POST and PUT). It is an error if this
+ :  param is not the empty sequence for methods 
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error error:HC001 An HTTP error occurred.
+ : @error error:HC002 Error parsing the response content as XML.
+ : @error error:HC003 With a multipart response, the override-media-type must be either a multipart media type or application/octet-stream.
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type).
+ : @error error:HC005 The input request element is not valid.
+ : @error error:HC006 A timeout occurred waiting for the response.
+ : @error error:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request
+~:)
+declare %an:nondeterministic function http-wrapper:http-nondeterministic-request(
+  $request as element()?,
+  $href as xs:string?,
+  $bodies as item()*) as item()+
+{
+  try 
+  {
+     {
+       variable $json-request := http-wrapper:json-request($request, $href, $bodies);
+       variable $json-response := json-http:send-nondeterministic-request($json-request);
+       variable $xml-response :=  http-wrapper:xml-response($json-response, fn:data($request/@override-media-type));  
+       $xml-response       
+     }
+  } catch XPTY0004 {
+    fn:error($error:HC005, "The input request element is not valid.")
+  } catch json-http:HTTP {
+    fn:error($error:HC001, "An HTTP error occurred.")
+  } catch json-http:REQUEST {
+    fn:error($error:HC005, "The input request element is not valid.")
+  } catch json-http:TIMEOUT {
+    fn:error($error:HC006, "A timeout occurred waiting for the response.")
+  } catch json-http:FOLLOW {
+    fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.")
+  } catch json-http:CHARSET {
+    fn:error($error:HC005, "The input request element is not valid: invalid charset specified.")
+  } catch * {
+    fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value)
+  }  
+};
+
+
+(:
+ :  JSON Response to XML Response Conversion
+ :)
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts a JSON HTTP module response, as
+ : used by the http://zorba.io/modules/http-client module 
+ : and returns its EXPath XML representation.
+ :
+ : @param $response a JSON response representation.
+ : @param $override-media-type if specified, is used in place of all
+ :  body media-types in the response.
+ : @return EXPath XML response representation.
+ : @error error:HC002 Error parsing the response content as XML.
+ :)
+declare %private function http-wrapper:xml-response($response as object(), $override-media-type as xs:string?) as item()+
+{
+  validate 
+  {
+    element http-schema:response
+    {
+      attribute message {$response("message")},
+      attribute status {$response("status")},
+      http-wrapper:xml-headers($response("headers")),
+      http-wrapper:xml-body($response("body")),
+      http-wrapper:xml-multipart($response("multipart"))    
+    }
+  },
+  http-wrapper:get-bodies(libjn:descendant-objects($response)("body"), $override-media-type)  
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts a JSON HTTP module response, as
+ : used by the http://zorba.io/modules/http-client module 
+ : and returns its EXPath XML representation.
+ : 
+ : If the body media-type indicates that the response body 
+ : has an XML content, the response body is parsed as XML
+ : before being returned. 
+ :
+ : @param $bodies a sequence JSON bodies.
+ : @param $override-media-type if specified, is used in place of all body media-types.
+ : @return body contents.
+ : @error error:HC002 Error parsing the response content as XML.
+ :)
+declare %private function http-wrapper:get-bodies($bodies as object()*, $override-media-type as xs:string?) as item()*
+{
+  for $body in $bodies
+  let $media-type := ($override-media-type, $body("media-type"))[1]
+  let $mime-type := if (fn:contains($media-type,";"))
+                    then fn:substring-before($media-type,";")
+                    else $media-type
+  return 
+    if ($mime-type eq "text/xml" or
+        $mime-type eq "application/xml" or
+        $mime-type eq "text/xml-external-parsed-entity" or
+        $mime-type eq "application/xml-external-parsed-entity" or
+        fn:ends-with($mime-type,"+xml"))
+    then 
+      try {
+        parse-xml($body("content"))}
+      catch FODC0006 {
+        fn:error($error:HC002, "Error parsing the response content as XML.")}        
+    else $body("content")
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts the headers portion of a JSON HTTP module 
+ : response, as used by the http://zorba.io/modules/http-client module 
+ : and returns its EXPath XML representation.
+ :
+ : @param $headers JSON representation of an headers set.
+ : @return XML representation of the given headers.
+ :)
+declare %private function http-wrapper:xml-headers($headers as object()?) as element()*
+{
+  if (exists($headers))
+  then 
+    for $header-name in jn:keys($headers)
+    return 
+      element http-schema:header 
+      {
+         attribute name {$header-name},
+         attribute value {$headers($header-name)}
+      }
+  else ()
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts the body portion of a JSON HTTP module 
+ : response, as used by the http://zorba.io/modules/http-client module 
+ : and returns its EXPath XML representation.
+ :
+ : @param $body JSON representation of a body.
+ : @return XML representation of the given body.
+ :)
+declare %private function http-wrapper:xml-body($body as object()?) as element()?
+{
+  if(exists($body))
+  then 
+    element http-schema:body
+    {
+      attribute media-type {$body("media-type")}
+    }
+  else ()  
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts the multipart portion of a JSON HTTP module 
+ : response, as used by the http://zorba.io/modules/http-client module 
+ : and returns its EXPath XML representation.
+ :
+ : @param $multipart JSON representation of a multipart.
+ : @return XML representation of the given multipart.
+ :)
+declare %private function http-wrapper:xml-multipart($multipart as object()?) as element()?
+{
+  if(exists($multipart))
+  then 
+    element http-schema:multipart
+    {
+      attribute media-type {$multipart("media-type")},
+      
+      if ($multipart("boundary")) 
+      then attribute boundary {$multipart("boundary")}
+      else (),
+      
+      for $part in jn:members($multipart("part"))
+      return
+      ( 
+        http-wrapper:xml-headers($part("headers")),
+        http-wrapper:xml-body($part("body"))
+      )
+    }
+  else ()
+};
+
+(:
+ : XML Request to JSON Request
+ :)
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts an XML EXPath HTTP request and returns its 
+ : JSON representation, as used by the http://zorba.io/modules/http-client
+ : module. 
+ :
+ : @param $request XML EXPath HTTP request.
+ : @param $href is the HTTP or HTTPS URI to send the request to. If specified,
+ :  any href URI specified in the request element is ignored.
+ : @param $bodies the request bodies content.  
+ : @return JSON HTTP request representation.
+ :
+ : @error error:HC005 The specified request object is not valid.
+ :)
+declare %private function http-wrapper:json-request($request as element()?, $href as xs:string?, $bodies as item()*) as item()
+{
+  if (http-wrapper:check-params($request, $href, $bodies))
+  then
+  {
+    variable $req := if ($request) 
+                     then try {
+                         validate { http-wrapper:set-content-type($request) }}
+                       catch XQDY0027 {
+                         fn:error($error:HC005, "The request element is not valid.")}
+                      else ();
+    {|
+      
+      {"method": if ($req/@method) then $req/@method/string(.) else "GET"},
+      
+      if ($href)
+        then {"href": $href} 
+        else {"href": $req/@href/string(.)},
+      
+      if ($request)
+      then 
+      ( 
+        http-wrapper:json-authentication($req),      
+        http-wrapper:json-options($req),
+        http-wrapper:json-headers($req/http-schema:header),      
+        http-wrapper:json-body($req/http-schema:body,$bodies),
+        http-wrapper:json-multipart($req/http-schema:multipart,$bodies)
+      )
+      else ()      
+      
+     |}
+     
+  }
+  else ()
+  
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts an XML EXPath HTTP request and returns the  
+ : JSON representation of its authentication options, as used by the 
+ : http://zorba.io/modules/http-client module. 
+ :
+ : @param $request XML EXPath HTTP request.
+ : @return JSON HTTP request authentication representation.
+ :)
+declare %private function http-wrapper:json-authentication($request as element()) as object()?
+{
+  if (xs:boolean($request/@send-authorization/data(.)))
+  then 
+  {
+    "authentication" :
+    {
+      "username": $request/@username/string(.),
+      "password": $request/@password/string(.),
+      "auth-method": $request/@auth-method/string(.)
+    }
+  }
+  else ()
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts an XML EXPath HTTP request and returns the  
+ : JSON representation of its options, as used by the 
+ : http://zorba.io/modules/http-client module. 
+ :
+ : @param $request XML EXPath HTTP request.
+ : @return JSON HTTP request options representation.
+ :)
+declare %private function http-wrapper:json-options($request as element()) as object()?
+{
+  if ($request/@status-only || $request/@override-media-type || 
+      $request/@follow-redirect || $request/@timeout || $request/@user-agent)
+  then
+  {
+    "options": 
+    {
+      {|
+        if ($request/@status-only) 
+        then {"status-only": xs:boolean($request/@status-only/data(.))} 
+        else (),
+        
+        if ($request/@override-media-type) 
+        then {"override-media-type": $request/@override-media-type/string(.)} 
+        else (),
+        
+        if ($request/@follow-redirect) 
+        then {"follow-redirect": xs:boolean($request/@follow-redirect/data(.))} 
+        else (),
+              
+        if ($request/@timeout) 
+        then {"timeout": $request/@timeout/data(.)} 
+        else (),
+        
+        if ($request/@user-agent) 
+        then {"user-agent": $request/@user-agent/string(.)} 
+        else ()
+      |}
+    }
+  }
+  else ()
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accepts a sequence of headers in the XML EXPath HTTP request
+ : format and returns their JSON representation, as used by the 
+ : http://zorba.io/modules/http-client module. 
+ :
+ : @param $headers XML EXPath HTTP headers.
+ : @return JSON HTTP request headers representation.
+ :)
+declare %private function http-wrapper:json-headers($headers as element()*) as object()?
+{
+  if ($headers) 
+  then
+  {
+    "headers": 
+    {|
+      for $header in $headers
+      group by $name := $header/@name
+      return {$name: string-join($header/@value,",")}
+    |}
+  }
+  else ()
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accept a body element in the XML EXPath HTTP request
+ : format and returns its JSON representation, as used by the 
+ : http://zorba.io/modules/http-client module. 
+ :
+ : @param $body XML EXPath HTTP body element.
+ : @param $content body content.
+ : @return JSON HTTP request headers representation.
+ :)
+declare %private function http-wrapper:json-body($body as element()?, $content as item()*) as object()?
+{
+  if ($body)
+  then 
+  {
+    "body": 
+    {|
+      {"media-type": $body/@media-type/string(.)},
+      
+      if ($body/@src)
+      then {"src": $body/@src/string(.)}
+      else {"content": http-wrapper:produce-content($body,$content)}      
+    |}
+  }  
+  else ()
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function serializes a request body. 
+ :
+ : @param $body request contents. 
+ : @return serialized body.
+ :)
+declare %private function http-wrapper:produce-content($body as element(), $content as item()*) as xs:string
+{
+  let $request-body := if ($body/node()) 
+                       then $body/node()                                             
+                       else $content
+  return
+    if ($body/@method eq "binary")
+    then if ($request-body instance of xs:base64Binary or $request-body instance of xs:hexBinary)
+         then $request-body
+         else 
+            copy $serialization-parameters := http-wrapper:serialization-parameters($body)
+            modify delete node $serialization-parameters/ser:method
+            return fn:serialize($request-body,$serialization-parameters)         
+    else fn:serialize($request-body, http-wrapper:serialization-parameters($body))
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accept a body element in the XML EXPath HTTP request
+ : format and returns the serializer parameters to be used to serialize 
+ : its content. 
+ :
+ : @param $body XML EXPath HTTP body element. 
+ : @return serializer parameters.
+ :)
+declare %private function http-wrapper:serialization-parameters($body as element()) as element()
+{
+  element ser:serialization-parameters
+  {
+    http-wrapper:default-serialization-parameters($body),
+    for $option in $body/(@method | @byte-order-mark | @cdata-section-elements |
+                          @doctype-public | @doctype-system | @encoding |
+                          @escape-uri-attributes | @indent |@normalization-form |
+                          @omit-xml-declaration | @standalone | @suppress-indentation |
+                          @undeclare-prefixes | @version)
+    return 
+      element {QName("http://www.w3.org/2010/xslt-xquery-serialization",local-name($option))}
+              {attribute value {$option/string(.)}}           
+  }
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function return this module default serialization parameters. 
+ :
+ : @param $body XML EXPath HTTP body element. 
+ : @return serializer parameters.
+ :)
+declare %private function http-wrapper:default-serialization-parameters($body as element()) as element()*
+{
+  if ($body/@method/string(.) eq "xml")
+  then
+  (
+    if ($body/@omit-xml-declaration)
+    then ()
+    else 
+      element {QName("http://www.w3.org/2010/xslt-xquery-serialization","omit-xml-declaration";)}
+              {attribute value {"no"}}
+  )
+  else ()  
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accept a multipart element in the XML EXPath HTTP request
+ : format and returns its JSON representation, as used by the 
+ : http://zorba.io/modules/http-client module. 
+ :
+ : @param $multipart XML EXPath HTTP multipart  element.
+ : @param $bodies multipart bodies content.
+ : @return JSON HTTP request multipart representation.
+ :)
+declare %private function http-wrapper:json-multipart($multipart as element()?, $bodies as item()*) as object()?
+{
+  if ($multipart)
+  then 
+  {
+    "multipart": 
+    {| 
+       {"media-type": $multipart/@media-type/string(.)},
+       
+       if ($multipart/@boundary) 
+       then {"boundary": $multipart/@boundary/string(.)} 
+       else (),
+       
+       {"parts":
+         [
+           let $requests:= $multipart/*
+           for $part in $requests
+           group by $bodies-before:= count($requests[local-name(.) eq "body" and . << $part])
+           return 
+             let $content := 
+               if ($part/self::http-schema:body/@src) 
+               then () (: The content will be downloaded from the "src" url :)
+               else if ($part/self::http-schema:body/node())
+                 then ($part/self::http-schema:body/node()) (: the content is made by the body children :)
+                 else (: the content is the 1+n-th body item, where n is the number of parts 
+                         before the current one which body has no src attributes and no childrens :) 
+                      ($bodies[1+count($requests[local-name(.) eq "body" and 
+                         not(@content) and not(node()) and . << $part/self::http-schema:body])]) 
+             return http-wrapper:json-part($part/self::http-schema:header, $part/self::http-schema:body, $content)
+         ]}         
+    |}
+  }
+  else ()
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function accept a part headers, body and content  in the XML 
+ : EXPath HTTP request format and returns its JSON representation, as 
+ : used by the http://zorba.io/modules/http-client module. 
+ :
+ : @param $headers XML EXPath HTTP header elements.
+ : @param $body XML EXPath HTTP body element.
+ : @param $content XML EXPath HTTP body content. 
+ : @return JSON HTTP request part representation.
+ :)
+declare %private function http-wrapper:json-part($headers as element()*, $body as element(), $content as item()*) as item() 
+{    
+  {|
+    http-wrapper:json-headers($headers),
+    http-wrapper:json-body($body,$content)
+  |}      
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function checks if the request, href, and bodies parameters
+ : are consistent.
+ :
+ : @param $request The request which needs to be checked.
+ : @param $href The href which needs to be checked.
+ : @param $bodies The bodies element which needs to be checked.
+ : @return true if the parameters are consistent. Otherwise,
+ :         this function raises an error.
+ :
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type).
+ : @error error:HC005 The specified request object is not valid.
+ :
+ :)
+declare %private function http-wrapper:check-params(
+  $request as element(http-schema:request)?,
+  $href as xs:string?,
+  $bodies as item()*) as xs:boolean {
+  let $multipart := $request/http-schema:multipart
+  let $override := $request/@override-media-type/string(.)
+  let $should-be-empty :=
+    for $x in $request//http-schema:body
+    return
+      if ($x/@src and fn:not((fn:count($x/@*) eq 2))) then 1
+      else ()
+  return
+    if (fn:empty($href) and fn:empty($request)) then
+      fn:error($error:HC005, "The request element is not valid.")
+    else if ($href eq "") then
+      fn:error($error:HC005, "The request element is not valid.")
+    else if (not(count($request//http-schema:body[not(exists(node())) and not(exists(@src))]) eq count($bodies))) then
+      fn:error($error:HC005, "The request element is not valid.")
+    else if ($should-be-empty) then
+      fn:error($error:HC004, "The src attribute on the body element is mutually exclusive with all other attributes (except the media-type).")
+    else
+      fn:true()
+};
+
+(:~
+ : This adds a default method attribute to all body elements which
+ : don't contain a method attribute.
+ :
+ : @param $request The request which need to be copied.
+ : @return A copy of $request with all request//body/@method set.
+ :)
+declare %private function http-wrapper:set-content-type(
+  $request as element(http-schema:request)?)
+    as element(http-schema:request)? {
+  if ($request) then
+    <http-schema:request>{$request/@*}
+    {
+    for $x in $request/node()
+    return
+      typeswitch($x)
+        case element(http-schema:body) return http-wrapper:create-body($x)
+        case element(http-schema:multipart) return http-wrapper:create-multipart($x)
+        default return $x
+    }
+    </http-schema:request>
+  else ()
+};
+
+
+(:~
+ : This function takes an http-schema:body element, copies it, and
+ : adds a method attribute to the copy if there is none
+ : in the original element.
+ :
+ : @param $body is the original http-schema:body element
+ : @return a http-schema:body element with a corresponding <code>@method</code>
+ :   attribute 
+ :)
+declare %private function http-wrapper:create-body (
+  $body as element(http-schema:body))
+    as element(http-schema:body) {
+  <http-schema:body>{$body/@*}
+  {
+    if ($body/@method) then
+      ()
+    else
+      attribute method {
+        if ($body/@media-type eq "text/xml" or
+            $body/@media-type eq "application/xml" or
+            $body/@media-type eq "text/xml-external-parsed-entity" or
+            $body/@media-type eq "application/xml-external-parsed-entity") then
+              "xml"
+         else if ($body/@media-type eq "text/html") then "html"
+         else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text"
+         else "binary"
+      }
+  }
+  {$body/node()}
+  </http-schema:body>
+};
+
+(:~
+ : This function takes an http-schema:multipart element, copies it and
+ : adds a @method attribute to all body elements which don't have
+ : one.
+ :
+ : @param $multipart the original http-schema:multipart
+ : @return a copy of $multipart with all $multipart/body/@method set 
+ :)
+declare %private function http-wrapper:create-multipart (
+  $multipart as element(http-schema:multipart))
+    as element(http-schema:multipart) {
+    <http-schema:multipart>{$multipart/@*}
+    {
+    for $x in $multipart/node()
+    return
+      typeswitch($x)
+        case element(http-schema:body) return http-wrapper:create-body($x)
+        default return $x
+    }
+    </http-schema:multipart>
+};

=== modified file 'modules/http-client/xml/http-client.xq'
--- modules/http-client/xml/http-client.xq	2013-07-24 07:21:59 +0000
+++ modules/http-client/xml/http-client.xq	2013-07-25 15:45:37 +0000
@@ -251,6 +251,7 @@
 
 import module namespace error = "http://expath.org/ns/error";;
 import module namespace json-http = "http://zorba.io/modules/http-client";;
+import module namespace http-wrapper = "http://zorba.io/modules/http-client-wrapper";;
 import module namespace libjn = "http://jsoniq.org/function-library";;
 
 import schema namespace http-schema = "http://expath.org/ns/http-client";;
@@ -304,25 +305,7 @@
   $href as xs:string?,
   $bodies as item()*) as item()+ 
 {
-  if (http:check-params($request, $href, $bodies))
-  then
-    {
-      variable $req := 
-        if ($request) 
-        then
-          try 
-          {
-            validate { http:set-content-type($request) }
-          }
-          catch XQDY0027 
-          {
-            fn:error($error:HC005, "The request element is not valid.")
-          }
-        else ();
-      variable $result := http:http-sequential-impl($req, $href, $bodies);
-      $result
-    }
-  else ()
+  http-wrapper:http-sequential-request($request, $href, $bodies)  
 };
 
 
@@ -342,7 +325,7 @@
  :)
 declare %an:nondeterministic function http:get($href as xs:string) as item()+
 {
-  http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true"/>}, (), ())
+  http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true"/>}, (), ())
 };
 
 (:~
@@ -361,7 +344,7 @@
  :)
 declare %an:nondeterministic function http:get-node($href as xs:string) as item()+
 {
-  http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/xml; charset=utf-8"/>}, (), ())
+  http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/xml; charset=utf-8"/>}, (), ())
 };
 
 (:~
@@ -381,7 +364,7 @@
  :)
 declare %an:nondeterministic function http:get-text($href as xs:string) as item()+
 {
-  http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/plain; charset=utf-8"/>}, (), ())
+  http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="text/plain; charset=utf-8"/>}, (), ())
 };
 
 (:~
@@ -401,7 +384,7 @@
  :)
 declare %an:nondeterministic function http:get-binary($href as xs:string) as item()+
 {
-  http:http-nondeterministic-impl(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="binary"/>}, (), ())
+  http-wrapper:http-nondeterministic-request(validate {<http-schema:request method="GET" href="{$href}" follow-redirect="true" override-media-type="binary"/>}, (), ())
 };
 
 (:~
@@ -418,7 +401,7 @@
  : @example test/rbkt/Queries/zorba/http-client/xml/head/head_status.xq
  :)
 declare %an:nondeterministic function http:head($href as xs:string) as item() {
-  http:http-nondeterministic-impl(
+  http-wrapper:http-nondeterministic-request(
     validate {
       <http-schema:request method="HEAD" href="{$href}">
       </http-schema:request>
@@ -438,7 +421,7 @@
  : @example test/rbkt/Queries/zorba/http-client/xml/options/options.xq
  :)
 declare %an:nondeterministic function http:options($href as xs:string) as xs:string* {
-  let $resp := http:http-nondeterministic-impl(
+  let $resp := http-wrapper:http-nondeterministic-request(
     validate {
       <http-schema:request method="OPTIONS" href="{$href}">
       </http-schema:request>
@@ -529,7 +512,7 @@
       case xs:base64Binary return "binary"
       default return "text";
 
-  variable $result := http:http-sequential-impl(validate {
+  variable $result := http-wrapper:http-sequential-request(validate {
     <http-schema:request href="{$href}" method="PUT">
       <http-schema:body media-type="{$content-type}" method="{$method}">{$body}</http-schema:body>
     </http-schema:request>}
@@ -553,7 +536,7 @@
  :)
 declare %an:sequential function http:delete($href as xs:string) as item()+
 {
-  http:http-sequential-impl(
+  http-wrapper:http-sequential-request(
     validate {
       <http-schema:request method="DELETE" href="{$href}">
       </http-schema:request>
@@ -642,7 +625,7 @@
       case xs:base64Binary return "binary"
       default return "text";
 
-  variable $result := http:http-sequential-impl(validate {
+  variable $result := http-wrapper:http-sequential-request(validate {
     <http-schema:request href="{$href}" method="POST">
       <http-schema:body media-type="{$content-type}" method="{$method}">{$body}</http-schema:body>
     </http-schema:request>}
@@ -650,650 +633,3 @@
 
   $result
 };
-
-(:~
- : This function takes an http-schema:body element, copies it, and
- : adds a method attribute to the copy if there is none
- : in the original element.
- :
- : @param $body is the original http-schema:body element
- : @return a http-schema:body element with a corresponding <code>@method</code>
- :   attribute 
- :)
-declare %private function http:create-body (
-  $body as element(http-schema:body))
-    as element(http-schema:body) {
-  <http-schema:body>{$body/@*}
-  {
-    if ($body/@method) then
-      ()
-    else
-      attribute method {
-        if ($body/@media-type eq "text/xml" or
-            $body/@media-type eq "application/xml" or
-            $body/@media-type eq "text/xml-external-parsed-entity" or
-            $body/@media-type eq "application/xml-external-parsed-entity") then
-              "xml"
-         else if ($body/@media-type eq "text/html") then "html"
-         else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text"
-         else "binary"
-      }
-  }
-  {$body/node()}
-  </http-schema:body>
-};
-
-(:~
- : This function takes an http-schema:multipart element, copies it and
- : adds a @method attribute to all body elements which don't have
- : one.
- :
- : @param $multipart the original http-schema:multipart
- : @return a copy of $multipart with all $multipart/body/@method set 
- :)
-declare %private function http:create-multipart (
-  $multipart as element(http-schema:multipart))
-    as element(http-schema:multipart) {
-    <http-schema:multipart>{$multipart/@*}
-    {
-    for $x in $multipart/node()
-    return
-      typeswitch($x)
-        case element(http-schema:body) return http:create-body($x)
-        default return $x
-    }
-    </http-schema:multipart>
-};
-
-
-(:~
- : This adds a default method attribute to all body elements which
- : don't contain a method attribute.
- :
- : @param $request The request which need to be copied.
- : @return A copy of $request with all request//body/@method set.
- :)
-declare %private function http:set-content-type(
-  $request as element(http-schema:request)?)
-    as element(http-schema:request)? {
-  if ($request) then
-    <http-schema:request>{$request/@*}
-    {
-    for $x in $request/node()
-    return
-      typeswitch($x)
-        case element(http-schema:body) return http:create-body($x)
-        case element(http-schema:multipart) return http:create-multipart($x)
-        default return $x
-    }
-    </http-schema:request>
-  else ()
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function checks if the request, href, and bodies parameters
- : are consistent.
- :
- : @param $request The request which needs to be checked.
- : @param $href The href which needs to be checked.
- : @param $bodies The bodies element which needs to be checked.
- : @return true if the parameters are consistent. Otherwise,
- :         this function raises an error.
- :
- : @error error:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type).
- : @error error:HC005 The specified request object is not valid.
- :
- :)
-declare %private function http:check-params(
-  $request as element(http-schema:request)?,
-  $href as xs:string?,
-  $bodies as item()*) as xs:boolean {
-  let $multipart := $request/http-schema:multipart
-  let $override := $request/@override-media-type/string(.)
-  let $should-be-empty :=
-    for $x in $request//http-schema:body
-    return
-      if ($x/@src and fn:not((fn:count($x/@*) eq 2))) then 1
-      else ()
-  return
-    if (fn:empty($href) and fn:empty($request)) then
-      fn:error($error:HC005, "The request element is not valid.")
-    else if ($href eq "") then
-      fn:error($error:HC005, "The request element is not valid.")
-    else if (not(count($request//http-schema:body[not(exists(node())) and not(exists(@src))]) eq count($bodies))) then
-      fn:error($error:HC005, "The request element is not valid.")
-    else if ($should-be-empty) then
-      fn:error($error:HC004, "The src attribute on the body element is mutually exclusive with all other attributes (except the media-type).")
-    else
-      fn:true()
-};
-
-
-(:
- :  JSON Response to XML Response Conversion
- :)
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts a JSON HTTP module response, as
- : used by the http://zorba.io/modules/http-client module 
- : and returns its EXPath XML representation.
- :
- : @param $response a JSON response representation.
- : @param $override-media-type if specified, is used in place of all
- :  body media-types in the response.
- : @return EXPath XML response representation.
- : @error error:HC002 Error parsing the response content as XML.
- :)
-declare %private function http:xml-response($response as object(), $override-media-type as xs:string?) as item()+
-{
-  validate 
-  {
-    element http-schema:response
-    {
-      attribute message {$response("message")},
-      attribute status {$response("status")},
-      http:xml-headers($response("headers")),
-      http:xml-body($response("body")),
-      http:xml-multipart($response("multipart"))    
-    }
-  },
-  http:get-bodies(libjn:descendant-objects($response)("body"), $override-media-type)  
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts a JSON HTTP module response, as
- : used by the http://zorba.io/modules/http-client module 
- : and returns its EXPath XML representation.
- : 
- : If the body media-type indicates that the response body 
- : has an XML content, the response body is parsed as XML
- : before being returned. 
- :
- : @param $bodies a sequence JSON bodies.
- : @param $override-media-type if specified, is used in place of all body media-types.
- : @return body contents.
- : @error error:HC002 Error parsing the response content as XML.
- :)
-declare %private function http:get-bodies($bodies as object()*, $override-media-type as xs:string?) as item()*
-{
-  for $body in $bodies
-  let $media-type := ($override-media-type, $body("media-type"))[1]
-  let $mime-type := if (fn:contains($media-type,";"))
-                    then fn:substring-before($media-type,";")
-                    else $media-type
-  return 
-    if ($mime-type eq "text/xml" or
-        $mime-type eq "application/xml" or
-        $mime-type eq "text/xml-external-parsed-entity" or
-        $mime-type eq "application/xml-external-parsed-entity" or
-        fn:ends-with($mime-type,"+xml"))
-    then 
-      try {
-        parse-xml($body("content"))}
-      catch FODC0006 {
-        fn:error($error:HC002, "Error parsing the response content as XML.")}        
-    else $body("content")
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts the headers portion of a JSON HTTP module 
- : response, as used by the http://zorba.io/modules/http-client module 
- : and returns its EXPath XML representation.
- :
- : @param $headers JSON representation of an headers set.
- : @return XML representation of the given headers.
- :)
-declare %private function http:xml-headers($headers as object()?) as element()*
-{
-  if (exists($headers))
-  then 
-    for $header-name in jn:keys($headers)
-    return 
-      element http-schema:header 
-      {
-         attribute name {$header-name},
-         attribute value {$headers($header-name)}
-      }
-  else ()
-};
-
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts the body portion of a JSON HTTP module 
- : response, as used by the http://zorba.io/modules/http-client module 
- : and returns its EXPath XML representation.
- :
- : @param $body JSON representation of a body.
- : @return XML representation of the given body.
- :)
-declare %private function http:xml-body($body as object()?) as element()?
-{
-  if(exists($body))
-  then 
-    element http-schema:body
-    {
-      attribute media-type {$body("media-type")}
-    }
-  else ()  
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts the multipart portion of a JSON HTTP module 
- : response, as used by the http://zorba.io/modules/http-client module 
- : and returns its EXPath XML representation.
- :
- : @param $multipart JSON representation of a multipart.
- : @return XML representation of the given multipart.
- :)
-declare %private function http:xml-multipart($multipart as object()?) as element()?
-{
-  if(exists($multipart))
-  then 
-    element http-schema:multipart
-    {
-      attribute media-type {$multipart("media-type")},
-      
-      if ($multipart("boundary")) 
-      then attribute boundary {$multipart("boundary")}
-      else (),
-      
-      for $part in jn:members($multipart("part"))
-      return
-      ( 
-        http:xml-headers($part("headers")),
-        http:xml-body($part("body"))
-      )
-    }
-  else ()
-};
-
-(:
- : XML Request to JSON Request
- :)
-(:~
- : Private function used internally by this module.
- :
- : This function accepts an XML EXPath HTTP request and returns its 
- : JSON representation, as used by the http://zorba.io/modules/http-client
- : module. 
- :
- : @param $request XML EXPath HTTP request.
- : @param $href is the HTTP or HTTPS URI to send the request to. If specified,
- :  any href URI specified in the request element is ignored.
- : @param $bodies the request bodies content.  
- : @return JSON HTTP request representation.
- :
- : @error error:HC005 The specified request object is not valid.
- :)
-declare %private function http:json-request($request as element()?, $href as xs:string?, $bodies as item()*) as item()
-{
-  if (http:check-params($request, $href, $bodies))
-  then
-  {
-    variable $req := if ($request) 
-                     then try {
-                         validate { http:set-content-type($request) }}
-                       catch XQDY0027 {
-                         fn:error($error:HC005, "The request element is not valid.")}
-                      else ();
-    {|
-      
-      {"method": if ($req/@method) then $req/@method/string(.) else "GET"},
-      
-      if ($href)
-        then {"href": $href} 
-        else {"href": $req/@href/string(.)},
-      
-      if ($request)
-      then 
-      ( 
-        http:json-authentication($request),      
-        http:json-options($request),
-        http:json-headers($request/http-schema:header),      
-        http:json-body($request/http-schema:body,$bodies),
-        http:json-multipart($request/http-schema:multipart,$bodies)
-      )
-      else ()      
-      
-     |}
-     
-  }
-  else ()
-  
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts an XML EXPath HTTP request and returns the  
- : JSON representation of its authentication options, as used by the 
- : http://zorba.io/modules/http-client module. 
- :
- : @param $request XML EXPath HTTP request.
- : @return JSON HTTP request authentication representation.
- :)
-declare %private function http:json-authentication($request as element()) as object()?
-{
-  if (xs:boolean($request/@send-authorization/data(.)))
-  then 
-  {
-    "authentication" :
-    {
-      "username": $request/@username/string(.),
-      "password": $request/@password/string(.),
-      "auth-method": $request/@auth-method/string(.)
-    }
-  }
-  else ()
-};
-
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts an XML EXPath HTTP request and returns the  
- : JSON representation of its options, as used by the 
- : http://zorba.io/modules/http-client module. 
- :
- : @param $request XML EXPath HTTP request.
- : @return JSON HTTP request options representation.
- :)
-declare %private function http:json-options($request as element()) as object()?
-{
-  if ($request/@status-only || $request/@override-media-type || 
-      $request/@follow-redirect || $request/@timeout || $request/@user-agent)
-  then
-  {
-    "options": 
-    {
-      {|
-        if ($request/@status-only) 
-        then {"status-only": xs:boolean($request/@status-only/data(.))} 
-        else (),
-        
-        if ($request/@override-media-type) 
-        then {"override-media-type": $request/@override-media-type/string(.)} 
-        else (),
-        
-        if ($request/@follow-redirect) 
-        then {"follow-redirect": xs:boolean($request/@follow-redirect/data(.))} 
-        else (),
-              
-        if ($request/@timeout) 
-        then {"timeout": $request/@timeout/data(.)} 
-        else (),
-        
-        if ($request/@user-agent) 
-        then {"user-agent": $request/@user-agent/string(.)} 
-        else ()
-      |}
-    }
-  }
-  else ()
-};
-
-
-(:~
- : Private function used internally by this module.
- :
- : This function accepts a sequence of headers in the XML EXPath HTTP request
- : format and returns their JSON representation, as used by the 
- : http://zorba.io/modules/http-client module. 
- :
- : @param $headers XML EXPath HTTP headers.
- : @return JSON HTTP request headers representation.
- :)
-declare %private function http:json-headers($headers as element()*) as object()?
-{
-  if ($headers) 
-  then
-  {
-    "headers": 
-    {|
-      for $header in $headers
-      group by $name := $header/@name
-      return {$name: string-join($header/@value,",")}
-    |}
-  }
-  else ()
-};
-
-
-(:~
- : Private function used internally by this module.
- :
- : This function accept a body element in the XML EXPath HTTP request
- : format and returns its JSON representation, as used by the 
- : http://zorba.io/modules/http-client module. 
- :
- : @param $body XML EXPath HTTP body element.
- : @param $content body content.
- : @return JSON HTTP request headers representation.
- :)
-declare %private function http:json-body($body as element()?, $content as item()*) as object()?
-{
-  if ($body)
-  then 
-  {
-    "body": 
-    {|
-      {"media-type": $body/@media-type/string(.)},
-      
-      if ($body/@src)
-      then {"src": $body/@src/string(.)}
-      else {"content": http:produce-content($body,$content)}      
-    |}
-  }  
-  else ()
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function serializes a request body. 
- :
- : @param $body request contents. 
- : @return serialized body.
- :)
-declare %private function http:produce-content($body as element(), $content as item()*) as xs:string
-{
-  let $request-body := if ($body/node()) 
-                       then $body/node()                                             
-                       else $content
-  return
-    if ($body/@method eq "binary")
-    then if ($request-body instance of xs:base64Binary or $request-body instance of xs:hexBinary)
-         then $request-body
-         else 
-            copy $serialization-parameters := http:serialization-parameters($body)
-            modify delete node $serialization-parameters/ser:method
-            return fn:serialize($request-body,$serialization-parameters)         
-    else fn:serialize($request-body, http:serialization-parameters($body))
-};
-
-
-(:~
- : Private function used internally by this module.
- :
- : This function accept a body element in the XML EXPath HTTP request
- : format and returns the serializer parameters to be used to serialize 
- : its content. 
- :
- : @param $body XML EXPath HTTP body element. 
- : @return serializer parameters.
- :)
-declare %private function http:serialization-parameters($body as element()) as element()
-{
-  element ser:serialization-parameters
-  {
-    http:default-serialization-parameters($body),
-    for $option in $body/(@method | @byte-order-mark | @cdata-section-elements |
-                          @doctype-public | @doctype-system | @encoding |
-                          @escape-uri-attributes | @indent |@normalization-form |
-                          @omit-xml-declaration | @standalone | @suppress-indentation |
-                          @undeclare-prefixes | @version)
-    return 
-      element {QName("http://www.w3.org/2010/xslt-xquery-serialization",local-name($option))}
-              {attribute value {$option/string(.)}}           
-  }
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function return this module default serialization parameters. 
- :
- : @param $body XML EXPath HTTP body element. 
- : @return serializer parameters.
- :)
-declare %private function http:default-serialization-parameters($body as element()) as element()*
-{
-  if ($body/@method/string(.) eq "xml")
-  then
-  (
-    if ($body/@omit-xml-declaration)
-    then ()
-    else 
-      element {QName("http://www.w3.org/2010/xslt-xquery-serialization","omit-xml-declaration";)}
-              {attribute value {"no"}}
-  )
-  else ()  
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accept a multipart element in the XML EXPath HTTP request
- : format and returns its JSON representation, as used by the 
- : http://zorba.io/modules/http-client module. 
- :
- : @param $multipart XML EXPath HTTP multipart  element.
- : @param $bodies multipart bodies content.
- : @return JSON HTTP request multipart representation.
- :)
-declare %private function http:json-multipart($multipart as element()?, $bodies as item()*) as object()?
-{
-  if ($multipart)
-  then 
-  {
-    "multipart": 
-    {| 
-       {"media-type": $multipart/@media-type/string(.)},
-       
-       if ($multipart/@boundary) 
-       then {"boundary": $multipart/@boundary/string(.)} 
-       else (),
-       
-       {"parts":
-         [
-           let $requests:= $multipart/*
-           for $part in $requests
-           group by $bodies-before:= count($requests[local-name(.) eq "body" and . << $part])
-           return 
-             let $content := 
-               if ($part/self::http-schema:body/@src) 
-               then () (: The content will be downloaded from the "src" url :)
-               else if ($part/self::http-schema:body/node())
-                 then ($part/self::http-schema:body/node()) (: the content is made by the body children :)
-                 else (: the content is the 1+n-th body item, where n is the number of parts 
-                         before the current one which body has no src attributes and no childrens :) 
-                      ($bodies[1+count($requests[local-name(.) eq "body" and 
-                         not(@content) and not(node()) and . << $part/self::http-schema:body])]) 
-             return http:json-part($part/self::http-schema:header, $part/self::http-schema:body, $content)
-         ]}         
-    |}
-  }
-  else ()
-};
-
-(:~
- : Private function used internally by this module.
- :
- : This function accept a part headers, body and content  in the XML 
- : EXPath HTTP request format and returns its JSON representation, as 
- : used by the http://zorba.io/modules/http-client module. 
- :
- : @param $headers XML EXPath HTTP header elements.
- : @param $body XML EXPath HTTP body element.
- : @param $content XML EXPath HTTP body content. 
- : @return JSON HTTP request part representation.
- :)
-declare %private function http:json-part($headers as element()*, $body as element(), $content as item()*) as item() 
-{    
-  {|
-    http:json-headers($headers),
-    http:json-body($body,$content)
-  |}      
-};
-
-declare %private %an:sequential function http:http-sequential-impl(
-  $request as schema-element(http-schema:request)?,
-  $href as xs:string?,
-  $bodies as item()*) as item()+
-{
-  try 
-  {
-     {
-       variable $json-request := http:json-request($request, $href, $bodies);
-       variable $json-response := json-http:send-request($json-request);       
-       variable $xml-response :=  http:xml-response($json-response, fn:data($request/@override-media-type));         
-       $xml-response       
-     }
-  (:} catch XPTY0004 {
-    fn:error($error:HC005, "The input request element is not valid."):)
-  } catch json-http:HTTP {
-    fn:error($error:HC001, "An HTTP error occurred.")
-  } catch json-http:REQUEST {
-    fn:error($error:HC005, "The input request element is not valid.")
-  } catch json-http:TIMEOUT {
-    fn:error($error:HC006, "A timeout occurred waiting for the response.")
-  } catch json-http:FOLLOW {
-    fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.")
-  } catch json-http:CHARSET {
-    fn:error($error:HC005, "The input request element is not valid: invalid charset specified.")
-  } (:catch * {
-    fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value)
-  }:)
-};
-
-declare %private %an:nondeterministic function http:http-nondeterministic-impl(
-  $request as schema-element(http-schema:request)?,
-  $href as xs:string?,
-  $bodies as item()*) as item()+
-{
-  try 
-  {
-     {
-       variable $json-request := http:json-request($request, $href, $bodies);
-       variable $json-response := json-http:send-nondeterministic-request($json-request);
-       variable $xml-response :=  http:xml-response($json-response, fn:data($request/@override-media-type));  
-       $xml-response       
-     }
-  } catch XPTY0004 {
-    fn:error($error:HC005, "The input request element is not valid.")
-  } catch json-http:HTTP {
-    fn:error($error:HC001, "An HTTP error occurred.")
-  } catch json-http:REQUEST {
-    fn:error($error:HC005, "The input request element is not valid.")
-  } catch json-http:TIMEOUT {
-    fn:error($error:HC006, "A timeout occurred waiting for the response.")
-  } catch json-http:FOLLOW {
-    fn:error($error:HCV02, "Trying to follow a redirect of a POST, PUT, or DELETE request.")
-  } catch json-http:CHARSET {
-    fn:error($error:HC005, "The input request element is not valid: invalid charset specified.")
-  } catch * {
-    fn:error(fn:QName($error:errNS, fn:local-name-from-QName($err:code)),$err:description, $err:value)
-  }  
-};


Follow ups