Created
July 28, 2016 12:25
-
-
Save ableasdale/ae0dadda3fd43f8778e18eb8ab0cc1e4 to your computer and use it in GitHub Desktop.
MarkLogic: HTTP Multipart Post Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xquery version "1.0-ml" encoding "utf-8"; | |
(:~ | |
: Mark Logic multi-part POST Library | |
: Assembles a multi-part POST and performs an xdmp:post() sending the data to a webservice URI. | |
: | |
: The document can be read from the database or the filesystem. First the database is checked - | |
: if the information provided does not resolve a document in the database, it will fall back to | |
: trying to get the document from the filesystem | |
: | |
: @author <a href="mailto:[email protected]">Alex Bleasdale</a> | |
: | |
:) | |
declare namespace http = "xdmp:http"; | |
declare default function namespace "http://www.w3.org/2005/xpath-functions"; | |
(: Public functions :) | |
(:~ | |
: Takes 3 parameters and formats and performs a multi-part http POST | |
: to a given URI | |
: | |
: @param $uri as xs:string | |
: - the URI for the webservice | |
: @param $boundary as xs:string | |
: - a string denoting the boundary string value for demarcating | |
: break-points between message parts | |
: @param $data as node()+ | |
: - | |
: @return | |
: - the XML response from the Web Service. | |
: | |
: Example usage: | |
: | |
: local:multipart-post( | |
: "http://webservice.com/", | |
: "------------12345xyz", | |
: (<data name="file" filename="blah.pdf" type="application/pdf">document-uri OR filesystem/path/to/test-doc.pdf</data>, | |
: <data name="api_key">1234xyz</data>, | |
: <data name="method">docs.upload</data>) ) | |
: | |
:) | |
declare function local:multipart-post( | |
$uri as xs:string, | |
$boundary as xs:string, | |
$data as element(data)+ | |
) as item()+ | |
{ | |
xdmp:http-post( | |
$uri, | |
<options xmlns="xdmp:http"> | |
<headers> | |
<Content-Type>multipart/form-data; boundary={$boundary}</Content-Type> | |
</headers> | |
</options>, | |
local:multipart-encode($data, $boundary) | |
) | |
}; | |
(: Private Functions :) | |
declare private function local:create-parts($data as element(data)+) as node()+ { | |
( | |
for $data-item in $data | |
return local:create-part($data-item) | |
) | |
}; | |
declare private function local:create-part($data as element(data)) as node() { | |
(: | |
: If it has a mime type (denoted by a type attribute), then it's a file. First check to see whether | |
: the path is to a document-uri (for a document already stored in the database. If it isn't | |
: a doc in the db, check to see whether the document exists at a location on the filesystem | |
: of the host machine | |
:) | |
if (exists($data/@*[local-name(.) eq "type"])) | |
then ( | |
if (exists(doc($data/text()))) | |
then (xdmp:log(concat("local :: Document: ", $data/text(), " is a valid URI in the database"), "debug"), doc($data/text())/node()) | |
else (xdmp:log(concat("local :: Document: ", $data/text(), " is not in the database, trying the filesystem"), "debug"), xdmp:document-get($data/text())/node()) | |
) | |
else ( | |
if (empty(xdmp:unquote($data/text(), (), "format-binary"))) | |
then (text {""}) | |
else (xdmp:unquote($data/text(), (), "format-binary")) | |
) | |
}; | |
declare private function local:prepare-meta($data as element(data)) as element()+ { | |
( | |
local:process-content-disposition($data), | |
local:process-content-type($data) | |
) | |
}; | |
declare private function local:multipart-encode($data as element(data)+, $boundary as xs:string) { | |
let $parts := local:create-parts($data) | |
return | |
xdmp:multipart-encode( | |
$boundary, | |
<manifest xmlns="xdmp:multipart"> | |
{ | |
for $part at $pos in $parts | |
return element part { | |
element http:headers { | |
local:prepare-meta($data[$pos]) | |
} | |
} | |
} | |
</manifest>, $parts) | |
}; | |
declare private function local:process-content-disposition($data as element(data)) as element(Content-Disposition) { | |
( | |
let $partial-string := concat("form-data; ", local:extract-data-from-attribute($data, "name")) | |
let $string := if (empty(local:extract-data-from-attribute($data, "filename"))) | |
then ($partial-string) | |
else (concat($partial-string, "; ", local:extract-data-from-attribute($data, "filename"))) | |
return | |
element Content-Disposition {$string} | |
) | |
}; | |
declare private function local:process-content-type($data as element(data)) as element(Content-Type)? { | |
if (exists($data/@*[local-name(.) eq "type"])) | |
then (element Content-Type {string($data/@*[local-name(.) eq "type"])}) | |
else () | |
}; | |
declare private function local:extract-data-from-attribute($data as element(data), $attr as xs:string) as xs:string? { | |
if (exists($data/@*[local-name(.) eq $attr])) | |
then (fn:concat($attr, '="', string($data/@*[local-name(.) eq $attr]), '"')) | |
else () | |
}; | |
(: Main :) | |
local:multipart-post( | |
"http://httpbin.org/post", | |
"----blah", | |
(<data name="file" filename="blah.pdf" type="application/pdf">/Users/ableasdale/Desktop/pdf-test.pdf</data>, | |
<data name="api_key">1234xyz</data>, | |
<data name="method">docs.upload</data>) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment