joewiz
8/5/2017 - 8:41 PM

An implementation of XQuery 3.1's fn:unparsed-text* functions for eXist

An implementation of XQuery 3.1's fn:unparsed-text* functions for eXist

xquery version "3.1";

(:~ 
  : An implementation of XQuery 3.1's fn:unparsed-text* functions for eXist, which does not support them natively as of 3.4.0.
  : Known limitations: 
  :   - Does not enforce encoding aspects of the XQuery spec beyond functionality natively supplied by the EXPath HTTP Client and eXist's internals.
  :
  : @author Joe Wicentowski
  : @version 0.2
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text
  :)
module namespace ut="http://joewiz.org/ns/xquery/unparsed-text";

import module namespace hc="http://expath.org/ns/http-client";

(:~
  : This function reads an external resource (for example, a file) and returns a string representation of the resource.
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @return  a string representation of the resource
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text
  :)
declare function ut:unparsed-text($href as xs:string?) as xs:string? {
    ut:unparsed-text($href, ())
};

(:~
  : This function reads an external resource (for example, a file) and returns a string representation of the resource.
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @param  $encoding the name of an encoding
  : @return  a string representation of the resource
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text
  :)
declare function ut:unparsed-text($href as xs:string?, $encoding as xs:string?) as xs:string? {
    if ($href castable as xs:anyURI and starts-with($href, "http")) then
        let $request := 
            <hc:request href="{$href}" method="GET" override-media-type="text/plain">
                {
                    if ($encoding) then 
                        <hc:header name="Accept-Charset" value="{$encoding}"/>
                    else 
                        ()
                }
            </hc:request>
        let $response := hc:send-request($request)
        let $response-body := $response[2]
        return
            $response-body
    else if (util:binary-doc-available($href)) then
        try { 
            util:binary-to-string(util:binary-doc($href)) 
        } catch * { 
            error(xs:QName("err:FOUT1170"), "cannot retrieve the string representation of the resource at " || $href)
        }
    else
        error(xs:QName("err:FOUT1170"), "cannot resolve " || $href || " to an absolute URI")
};

(:~
  : This function reads an external resource (for example, a file) and returns its contents as a sequence of strings, one for each line of text in the string representation of the resource.
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @param  $encoding the name of an encoding
  : @return  a sequence of strings, one for each line of text in the string representation of the resource
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text-lines
  :)
declare function ut:unparsed-text-lines($href as xs:string?, $encoding as xs:string?) {
    let $unparsed-text := ut:unparsed-text($href, $encoding)
    return
        tokenize($unparsed-text, "\r\n|\r|\n")[not(position() = last() and . = '')]
};

(:~
  : This function reads an external resource (for example, a file) and returns its contents as a sequence of strings, one for each line of text in the string representation of the resource.
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @return  a sequence of strings, one for each line of text in the string representation of the resource
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text-lines
  :)
declare function ut:unparsed-text-lines($href as xs:string?) {
    ut:unparsed-text-lines($href, ())
};

(:~
  : This function determines whether a call on the fn:unparsed-text function with identical arguments would return a string
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @param  $encoding the name of an encoding
  : @return  true if a call on fn:unparsed-text with the same arguments would succeed, and false if a call on fn:unparsed-text with the same arguments would fail with a non-recoverable dynamic error
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text-available
  :)
declare function ut:unparsed-text-available($href as xs:string?, $encoding as xs:string?) as xs:boolean {
    if ($href) then
        let $attempt := try { ut:unparsed-text($href, $encoding) } catch * { () }
        return if (exists($attempt)) then true() else false()
    else
        ()
};

(:~
  : This function determines whether a call on the fn:unparsed-text function with identical arguments would return a string
  : @param  $href an absolute URI for a resource for which a string representation is available
  : @return  true if a call on fn:unparsed-text with the same arguments would succeed, and false if a call on fn:unparsed-text with the same arguments would fail with a non-recoverable dynamic error
  : @see https://www.w3.org/TR/xpath-functions-31/#func-unparsed-text-available
  :)
declare function ut:unparsed-text-available($href as xs:string?) as xs:boolean {
    ut:unparsed-text-available($href, ())
};