zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #23162
[Merge] lp:~zorba-coders/zorba/http-client-based-on-json-http-client into lp:zorba/http-client-module
Federico Cavalieri has proposed merging lp:~zorba-coders/zorba/http-client-based-on-json-http-client into lp:zorba/http-client-module.
Requested reviews:
Cezar Andrei (cezar-andrei)
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/http-client-based-on-json-http-client/+merge/169578
Added module version 2, based on JSON http-client
--
https://code.launchpad.net/~zorba-coders/zorba/http-client-based-on-json-http-client/+merge/169578
Your team Zorba Coders is subscribed to branch lp:zorba/http-client-module.
=== added file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/CMakeLists.txt 2013-06-15 00:50:31 +0000
@@ -0,0 +1,15 @@
+# Copyright 2006-2008 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.
+ADD_SUBDIRECTORY(v2)
+ADD_SUBDIRECTORY(v1)
=== removed directory 'src/org'
=== removed file 'src/org/CMakeLists.txt'
--- src/org/CMakeLists.txt 2011-10-06 08:18:34 +0000
+++ src/org/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-# Copyright 2006-2008 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.
-ADD_SUBDIRECTORY(expath)
=== removed directory 'src/org/expath'
=== removed file 'src/org/expath/CMakeLists.txt'
--- src/org/expath/CMakeLists.txt 2011-10-06 08:18:34 +0000
+++ src/org/expath/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-# Copyright 2006-2008 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.
-ADD_SUBDIRECTORY(ns)
=== removed directory 'src/org/expath/ns'
=== removed file 'src/org/expath/ns/CMakeLists.txt'
--- src/org/expath/ns/CMakeLists.txt 2012-01-18 07:49:28 +0000
+++ src/org/expath/ns/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-# Copyright 2006-2008 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.
-
-DECLARE_ZORBA_MODULE (URI "http://expath.org/ns/http-client" FILE "http-client.xq" VERSION 1.0)
=== added directory 'src/v1'
=== renamed file 'src/CMakeLists.txt' => 'src/v1/CMakeLists.txt'
--- src/CMakeLists.txt 2011-07-26 10:42:50 +0000
+++ src/v1/CMakeLists.txt 2013-06-15 00:50:31 +0000
@@ -12,8 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# all external module libraries are generated in the directory
-# of the corresponding .xq file
-MESSAGE(STATUS "Add org")
-ADD_SUBDIRECTORY(org)
-MESSAGE(STATUS "End modules")
+DECLARE_ZORBA_MODULE (URI "http://expath.org/ns/http-client" FILE "http-client.xq" VERSION 1.0)
\ No newline at end of file
=== renamed file 'src/org/expath/ns/http-client.xq' => 'src/v1/http-client.xq'
=== added directory 'src/v2'
=== added file 'src/v2/CMakeLists.txt'
--- src/v2/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/v2/CMakeLists.txt 2013-06-15 00:50:31 +0000
@@ -0,0 +1,15 @@
+# Copyright 2006-2008 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.
+
+DECLARE_ZORBA_MODULE (URI "http://expath.org/ns/http-client" FILE "http-client.xq" VERSION 2.0)
\ No newline at end of file
=== added file 'src/v2/http-client.xq'
--- src/v2/http-client.xq 1970-01-01 00:00:00 +0000
+++ src/v2/http-client.xq 2013-06-15 00:50:31 +0000
@@ -0,0 +1,803 @@
+xquery version "3.0";
+
+(:
+ : Copyright 2006-2013 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 an implementation of the
+ : <a href="http://expath.org/modules/http-client/">EXPath HTTP Client</a>.
+ : It provides functions for making HTTP requests and implements the
+ : <code>http:send-request()</code> functions as specified by EXPath.
+ : </p>
+ :
+ : <p>
+ : In general, the <code>http:send-request()</code> functions take a description
+ : of the HTTP request to make as parameter, execute the request, and return a
+ : representation of the HTTP response. For instance, in the following code
+ : snippet, we fetch a blog feed:
+ : </p>
+ : <pre>
+ : import module namespace http = "http://expath.org/ns/http-client";
+ :
+ : http:send-request(
+ : <http:request href="http://www.zorba-xquery.com/blog/feed" method="get" />
+ : )
+ : </pre>
+ :
+ : <p>
+ : The <code>http:send-request()</code> functions are declared as sequential.
+ : Sequential functions are allowed to have side effects. For example, most probably,
+ : an HTTP POST request is a request that has side effects because it adds/changes
+ : a remote resource. Sequential functions are specified in the
+ : <a href="http://www.zorba-xquery.com/html/documentation/latest/zorba/scripting_tutorial">XQuery Scripting Extension</a>.
+ : </p>
+ :
+ : <p>
+ : The response is returned as a sequence of one or more items. The first
+ : one is an <code>http:response</code> element with quite the same
+ : structure as an http:request, but without the content itself.
+ : The content is returned as the second item (or several items in case of
+ : a multipart response) as a string, a document node, or a binary item.
+ : This depends on the content-type specified in the HTTP response.
+ : Specifically, the rules are as follows:
+ :
+ : <ul>
+ : <li>A document node is returned if the media type has a MIME type of
+ : text/xml, application/xml, text/xml-external-parsed-entity, or
+ : application/xml-external-parsed-entity, as defined in [RFC 3023]
+ : (except that application/xml-dtd is considered a text media type).
+ : MIME types ending by +xml are also XML media types.</li>
+ : <li>A document node is returned if the media type has a MIME type of
+ : text/html. In order to be able to make HTML parseable, tidy is automatically
+ : invoked. If you want to prevent that, you can also set your own content-type
+ : by setting the override-media-type attribute in the request element.
+ : For tidying, the following <a href="http://tidy.sourceforge.net/docs/quickref.html">options</a>
+ : will be used:
+ : <ul>
+ : <li>TidyXmlOut=yes</li>
+ : <li>TidyDoctypeMode=TidyDoctypeOmit</li>
+ : <li>TidyQuoteNbsp=yes</li>
+ : <li>TidyCharEncoding="utf8"</li>
+ : <li>TidyNewline="LF"</li>
+ : </ul>
+ : </li>
+ : <li>An xs:string item is returned if the media type has a text MIME type,
+ : i.e. beginning with text/.</li>
+ : <li>An xs:base64Binary item is returned for all the other media types.</li>
+ : </ul>
+ : </p>
+ :
+ :
+ : <p>
+ : The structure of a request element is defined in the schema that is imported
+ : by this module. The details are described in the
+ : <a href="http://expath.org/spec/http-client#d2e183">specification</a>.
+ : Analogously, the response element is also described in this
+ : <a href="http://expath.org/spec/http-client#d2e491">specification</a>.
+ : </p>
+ :
+ : @author Federico Cavalieri
+ : @project EXPath/HTTP Client
+ :
+ :)
+module namespace http = "http://expath.org/ns/http-client";
+
+import module namespace json-http = "http://zorba.io/modules/http-client";
+import module namespace error = "http://expath.org/ns/error";
+
+import module namespace tidy="http://www.zorba-xquery.com/modules/converters/html";
+
+import schema namespace tidy-options="http://www.zorba-xquery.com/modules/converters/html-options";
+import schema namespace http-schema = "http://expath.org/ns/http-client";
+import module namespace libjn = "http://jsoniq.org/function-library";
+
+declare namespace an = "http://www.zorba-xquery.com/annotations";
+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
+declare namespace ser = "http://www.w3.org/2010/xslt-xquery-serialization";
+declare namespace err = "http://www.w3.org/2005/xqt-errors";
+
+declare option ver:module-version "2.0";
+
+(:~
+ : <p>
+ : This function sends an HTTP request and returns the corresponding response.
+ : </p>
+ :
+ : <p>
+ : This function is declared as sequential (see XQuery Scripting).
+ : Sequential functions are allowed to have side effects. For example, most probably,
+ : an HTTP POST request is a request that has side effects because it adds/changes
+ : a remote resource.
+ : </p>
+ :
+ : @param $request Contains the various parameters of the request.
+ : See the
+ : <a href="http://expath.org/spec/http-client#d2e183">specification</a>.
+ : for a full description of the structure of this element.
+ : @param $href is the HTTP or HTTPS URI to send the request to. It must be a valid
+ : xs:anyURI, but is declared as a string to be able to pass literal strings
+ : (without requiring to explicitly cast it to an xs:anyURI). If specified,
+ : any href URI specified in the request element will be ignored.
+ : @param $bodies is the sequence of request body contents, 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 DELETE, GET, HEAD and OPTIONS methods.
+ : @return a sequence of items, where the first item is a element of type
+ : http:responseType. The response element is also described in the
+ : <a href="http://expath.org/spec/http-client#d2e483">specification</a>.
+ : If there is one (or several, in case of multipart) response body, the response bodies
+ : are the next items in the sequence.
+ :
+ : @error error:HC001 An HTTP error occurred.
+ : @error error:HC002 Error parsing the response content as XML.
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all
+ : other attributes (except media-type).
+ : @error error:HC005 The specified request object 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.
+ : @error error:HCV03 The specified charset is unsupported.
+ :
+ :)
+declare %an:sequential function http:send-request(
+ $request as element()?,
+ $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));
+ http:tidy-result($xml-response, fn:data($request/@override-media-type))
+ }
+ } catch XPTY0004 {
+ fn:error($error:HC005, "The request element is not valid.")
+ } 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.
+ : </p>
+ :
+ : <p>
+ : Calling this function is equivalent to calling:
+ : <code>
+ : http:send-request($request, $href, ())
+ : </code>
+ : </p>
+ :
+ : @see documentation of <a href="#send-request-3">send-request</a> with three parameters.
+ :
+ : @param $request see request parameter of <a href="#send-request-3">send-request#3</a>
+ : @param $href see href parameter of <a href="#send-request-3">send-request#3</a>
+ : @return see return of <a href="#send-request-3">send-request#3</a>
+ :
+ : @error error:HC001 An HTTP error occurred.
+ : @error error:HC002 Error parsing the response content as XML.
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all
+ : other attributes (except media-type).
+ : @error error:HC005 The specified request object 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.
+ : @error error:HCV03 The specified charset is unsupported.
+ :)
+declare %an:sequential function http:send-request(
+ $request as element()?,
+ $href as xs:string?) as item()+ {
+ http:send-request($request, $href, ())
+};
+
+(:~
+ : <p>
+ : This function sends an HTTP request and returns the corresponding response.
+ : </p>
+ :
+ : <p>
+ : Calling this function is equivalent to calling
+ : <code>
+ : http:send-request($request, (), ())
+ : </code>
+ : </p>
+ :
+ : @see documentation of <a href="#send-request-3">send-request</a> with three parameters.
+ :
+ : @param $request see request parameter of the sequential
+ : <a href="#send-request-3">send-request</a> function with three parameters.
+ : @return see return value of the sequential
+ : <a href="#send-request-3">send-request</a> function with three parameters.
+ :
+ : @error error:HC001 An HTTP error occurred.
+ : @error error:HC002 Error parsing the response content as XML.
+ : @error error:HC004 The src attribute on the body element is mutually exclusive with all
+ : other attributes (except media-type).
+ : @error error:HC005 The specified request object 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.
+ : @error error:HCV03 The specified charset is unsupported.
+ :)
+declare %an:sequential function http:send-request (
+ $request as element()) as item()+ {
+ http:send-request($request, (), ())
+};
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function applies Tidy on all the response
+ : bodies in an HTTP response whose content-type is
+ : "text/html".
+ :
+ : @param $response XML response.
+ : @override-media-type an HTTP media-type. If specified, its MIME-type
+ : is used in place of the bodies MIME-type contained in the HTTP
+ : response.
+ : @return XML response, where Tidy has been applied on all HTML
+ : bodies.
+ :)
+declare %private function http:tidy-result($response as item()+, $override-media-type as xs:string?) as item()+
+{
+ $response[1],
+ for $body at $pos in fn:subsequence($response, 2)
+ let $media-type := ($override-media-type, ($response[1]//http-schema:body)[$pos]/@media-type/data(.))[1]
+ let $mime-type := if (fn:contains($media-type,";"))
+ then fn:substring-before($media-type,";")
+ else $media-type
+ return
+ if ($mime-type eq "text/html") then
+ tidy:parse($body)
+ else
+ $body
+};
+
+
+(:~
+ : 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":
+ if ($body/node())
+ then fn:serialize($body/node(), http:serialization-parameters($body))
+ else fn:serialize($content, http:serialization-parameters($body))
+ }
+ |}
+ }
+ else ()
+};
+
+(:~
+ : 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
+ {
+ 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 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)
+ |}
+};
+
+(:~
+ : 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()
+};
+
+(:~
+ : 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 ()
+};
\ No newline at end of file
Follow ups