Skip to content

Instantly share code, notes, and snippets.

@ableasdale
Created July 28, 2016 12:25
Show Gist options
  • Save ableasdale/ae0dadda3fd43f8778e18eb8ab0cc1e4 to your computer and use it in GitHub Desktop.
Save ableasdale/ae0dadda3fd43f8778e18eb8ab0cc1e4 to your computer and use it in GitHub Desktop.
MarkLogic: HTTP Multipart Post Example
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