post adjust

post adjust

xquery version "3.0";
module namespace post="http://markup.co.nz/#post";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace util="http://exist-db.org/xquery/util";
import module namespace xmldb="http://exist-db.org/xquery/xmldb";
import module namespace config="http://exist-db.org/xquery/apps/config"  at "../../modules/config.xqm";

declare namespace  xhtml =  "http://www.w3.org/1999/xhtml";
declare namespace  atom =  "http://www.w3.org/2005/Atom";

(:~
: Post
: @author Grant MacKenzie
: @version 0.01
:
:)

declare
function post:feed($node as node(), $model as map(*)) {

 let $getPageUpdated :=  function($item){
   let $updated :=  xs:date( $item/atom:updated/string() )
   let $formated := format-date($updated , "[D1o] [MNn] [Y]", "en", (), ())
   return
    $formated
  }

 let $getAuthor :=  function(){
   $model('page-author')
  }

 let $getPermalink :=  function($item){
  $item/atom:link[@rel='alternate']/@href/string()
  }

 let $getTitle :=  function($item){
   $item/atom:title/string()
  }

return

{
 for $item  at $i in collection($model('data-posts-path'))//atom:entry
   where $i lt 20
   order by $item/atom:updated descending
   return

{$item/atom:title/string()}

     {$item/atom:content/*/node()}

permalink: {$item/atom:title/string()}

  }

};

(:
 http://microformats.org/wiki/h-entry

h-entry properties, inside an element with class h-entry:

    p-name - entry name/title
    p-summary - short entry summary
    e-content - full content of the entry
    dt-published - when the entry was published
    dt-updated - when the entry was updated
    p-author - who wrote the entry, optionally embedded h-card(s)
    p-category - entry categories/tags
    u-url - entry permalink URL
    u-uid - unique entry ID
    p-location - location the entry was posted from, optionally embed h-card, h-adr, or h-geo

Microformats are amazing

Published by W. Developer
     on <time class="dt-published" datetime="2013-06-13 12:00:00">13th June 2013</time>

In which I extoll the virtues of using microformats.

Blah blah blah

:)

declare
function post:entry($node as node(), $model as map(*)) {
let $content :=

     { $model('page-content')/*/node() }

return
templates:process( $content, $model )
};

declare
function post:head-title($node as node(), $model as map(*)) {
<title>{ $model('page-title') }</title>
};

declare
function post:article($node as node(), $model as map(*)) {
let $content :=
    if( $model('page-isHome') ) then (
{ $model('page-content')/*/node() }
 )
    else (
{ $model('page-content')/*/node() }
 )
return
templates:process( $content, $model )
};

declare
function post:author($node as node(), $model as map(*)) {

By
{$model("page-author")}

};

xquery version "3.0";
module namespace post="http://markup.co.nz/#post";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace util="http://exist-db.org/xquery/util";
import module namespace xmldb="http://exist-db.org/xquery/xmldb";
import module namespace config="http://exist-db.org/xquery/apps/config"  at "../../modules/config.xqm";

declare namespace  xhtml =  "http://www.w3.org/1999/xhtml";
declare namespace  atom =  "http://www.w3.org/2005/Atom";

(:~
: Post
: @author Grant MacKenzie
: @version 0.01
:
:)

declare
function post:feed($node as node(), $model as map(*)) {

 let $getPageUpdated :=  function($item){
   let $updated :=  xs:date( $item/atom:updated/string() )
   let $formated := format-date($updated , "[D1o] [MNn] [Y]", "en", (), ())
   return
    $formated
  }

 let $getAuthor :=  function(){
   $model('page-author')
  }

 let $getPermalink :=  function($item){
  $item/atom:link[@rel='alternate']/@href/string()
  }

 let $getTitle :=  function($item){
   $item/atom:title/string()
  }

return

Latest 20 posts

{
 for $item  at $i in collection($model('data-posts-path'))//atom:entry
   where $i lt 20
   order by $item/atom:updated
   return

   {$item/atom:content/*/node()}

   Updated on the {$getPageUpdated($item)} by { $getAuthor() } , archived as
   {$getTitle($item)}

  }

};

(:
 http://microformats.org/wiki/h-entry

Microformats are amazing

Published by W. Developer
     on <time class="dt-published" datetime="2013-06-13 12:00:00">13th June 2013</time>

In which I extoll the virtues of using microformats.

Blah blah blah

:)

declare
function post:entry($node as node(), $model as map(*)) {
let $content :=

     { $model('page-content')/*/node() }

return
templates:process( $content, $model )
};

declare
function post:head-title($node as node(), $model as map(*)) {
<title>{ $model('page-title') }</title>
};

declare
function post:article($node as node(), $model as map(*)) {
let $content :=
    if( $model('page-isHome') ) then (
{ $model('page-content')/*/node() }
 )
    else (
{ $model('page-content')/*/node() }
 )
return
templates:process( $content, $model )
};

declare
function post:author($node as node(), $model as map(*)) {

By
{$model("page-author")}

};


Cosmetic addition of whitespace

Cosmetic addition of whitespace

declare default element namespace "http://www.w3.org/1999/xhtml";
declare namespace xfdf="http://ns.adobe.com/xfdf/";

<xhtml>

Issue #	Section	Page	Author	Observation

{
  for $h at $issue in //xfdf:highlight
  let $page := $h/@page + 1 (: XFDF page numbers are 0-based :)
  let $author := $h/@title
  let $comment := $h/xfdf:contents/text()
  let $rich_comment := $h/xfdf:contents-richtext/body/p/span/text()
  let $comment := fn:concat($comment,$rich_comment)
  return
{fn:string($issue)}	SECTION	{fn:string($page)}	{fn:string($author)}	{fn:string($comment)}

}

</xhtml>


Fix gene signature calculation

Fix gene signature calculation

;datasetGeneSignature
(fn [dataset samples genes weights]
 (let [probemap (:probemap (car (query {:select [:probemap]
                                        :from [:dataset]
                                        :where [:= :name dataset]})))
       get-probes (fn [gene] (xena-query {:select ["name" "position"]
                                          :from [probemap]
                                          :where [:in :any "genes" [gene]]}))
       avg (fn [scores] (mean scores 0))
       scores-for-gene (fn [gene]
                         (let [probes (get-probes gene)
                               probe-names (probes "name")
                               scores (fetch [{:table dataset
                                               :samples samples
                                               :columns probe-names}])]
                           (if (car probe-names) (car (avg scores)) [])))]

     ; putting in an object avoids a liberator encoding error
     {:scores (apply + (map (fn [w v] (* v w)) weights (map scores-for-gene genes)))}))

;datasetGeneSignature
(fn [dataset samples genes weights]
 (let [probemap (:probemap (car (query {:select [:probemap]
                                        :from [:dataset]
                                        :where [:= :name dataset]})))
       get-probes (fn [gene] (xena-query {:select ["name" "position"]
                                          :from [probemap]
                                          :where [:in :any "genes" [gene]]}))
       avg (fn [scores] (mean scores 0))
       scores-for-gene (fn [gene]
                         (let [probes (get-probes gene)
                               probe-names (probes "name")
                               scores (fetch [{:table dataset
                                               :samples samples
                                               :columns probe-names}])]
                           (if (car probe-names) (avg scores) [[]])))]

     ; putting in an object avoids a liberator encoding error
     {:scores (apply + (map (fn [w v] (* v w)) weights (car (map scores-for-gene genes))))}))


Complete BaseX binary module function signatures

xquery version "3.0";
(:~
: BaseX binary module functions
:
:)
module namespace bin = "http://expath.org/ns/binary";

import module namespace a = "http://reecedunn.co.uk/xquery/annotations" at "res://reecedunn.co.uk/xquery/annotations.xqy";

declare %a:since("basex", "9.0") function bin:hex($in as xs:string?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:bin($in as xs:string?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:octal($in as xs:string?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:to-octets($in as xs:base64Binary) as xs:integer* external;
declare %a:since("basex", "9.0") function bin:from-octets($in as xs:integer*) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:length($in as xs:base64Binary) as xs:integer external;
declare %a:since("basex", "9.0") function bin:part($in as xs:base64Binary?, $offset as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:part($in as xs:base64Binary?, $offset as xs:integer, $size as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:join($in as xs:base64Binary*) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:insert-before($in as xs:base64Binary?, $offset as xs:integer, $extra as xs:base64Binary?) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pad-left($in as xs:base64Binary?, $size as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:pad-left($in as xs:base64Binary?, $size as xs:integer, $octect as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:pad-right($in as xs:base64Binary?, $size as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:pad-right($in as xs:base64Binary?, $size as xs:integer, $octect as xs:integer) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:find($in as xs:base64Binary?, $offset as xs:integer, $search as xs:base64Binary) as xs:integer? external;
declare %a:since("basex", "9.0") function bin:decode-string($in as xs:base64Binary?, $encoding as xs:string) as xs:string? external;
declare %a:since("basex", "9.0") function bin:decode-string($in as xs:base64Binary?, $encoding as xs:string, $offset as xs:integer) as xs:string? external;
declare %a:since("basex", "9.0") function bin:decode-string($in as xs:base64Binary?, $encoding as xs:string, $offset as xs:integer, $size as xs:integer) as xs:string? external;
declare %a:since("basex", "9.0") function bin:encode-string($in as xs:string?, $encoding as xs:string) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:pack-double($in as xs:double) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pack-double($in as xs:double, $octet-order as xs:string) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pack-float($in as xs:float) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pack-float($in as xs:float, $octet-order as xs:string) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pack-integer($in as xs:integer, $size as xs:integer) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:pack-integer($in as xs:integer, $size as xs:integer, $octet-order as xs:string) as xs:base64Binary external;
declare %a:since("basex", "9.0") function bin:unpack-double($in as xs:base64Binary, $offset as xs:integer) as xs:double external;
declare %a:since("basex", "9.0") function bin:unpack-double($in as xs:base64Binary, $offset as xs:integer, $octet-order as xs:string) as xs:double external;
declare %a:since("basex", "9.0") function bin:unpack-float($in as xs:base64Binary, $offset as xs:integer) as xs:float external;
declare %a:since("basex", "9.0") function bin:unpack-float($in as xs:base64Binary, $offset as xs:integer, $octet-order as xs:string) as xs:float external;
declare %a:since("basex", "9.0") function bin:unpack-integer($in as xs:base64Binary, $offset as xs:integer, $size as xs:integer) as xs:integer external;
declare %a:since("basex", "9.0") function bin:unpack-integer($in as xs:base64Binary, $offset as xs:integer, $size as xs:integer, $octet-order as xs:string) as xs:integer external;
declare %a:since("basex", "9.0") function bin:unpack-unsigned-integer($in as xs:base64Binary, $offset as xs:integer, $size as xs:integer) as xs:integer external;
declare %a:since("basex", "9.0") function bin:unpack-unsigned-integer($in as xs:base64Binary, $offset as xs:integer, $size as xs:integer, $octet-order as xs:string) as xs:integer external;
declare %a:since("basex", "9.0") function bin:or($a as xs:base64Binary?, $b as xs:base64Binary?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:xor($a as xs:base64Binary?, $b as xs:base64Binary?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:and($a as xs:base64Binary?, $b as xs:base64Binary?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:not($in as xs:base64Binary?) as xs:base64Binary? external;
declare %a:since("basex", "9.0") function bin:shift($in as xs:base64Binary?, $by as xs:integer) as xs:base64Binary? external;


updated

updated

svn path=/trunk/eXist/; revision=6746

xquery version "1.0";

(: prints a list of all built-in functions :)

declare namespace util="http://exist-db.org/xquery/util";

(: Define a local function :)
declare function local:afunction() as xs:double {
	local:afunction(2)
};

(: An overloaded function :)
declare function local:afunction($a as xs:int) as xs:double {
	$a * 2.5
};

<!-- Currently known functions in eXist -->,
<functions>
<builtin-functions>
{
	for $mod in util:registered-modules()
	return
		<module uri="{$mod}">
		{
			for $f in util:registered-functions($mod)
			return
				util:describe-function($f)
		}
		</module>
}
</builtin-functions>
<my-functions>
{
	util:describe-function("local:afunction")
}
</my-functions>
</functions>

xquery version "1.0";

(: prints a list of all built-in functions :)

import module namespace utils="http://exist-db.org/xquery/collection-utils"
at "webapp/xquery/collections.xqm";

declare namespace util="http://exist-db.org/xquery/util";

(: Define a local function :)
declare function local:afunction() as xs:double {
	local:afunction(2)
};

(: An overloaded function :)
declare function local:afunction($a as xs:int) as xs:double {
	$a * 2.5
};

<!-- Currently known functions in eXist -->,
<functions>
<builtin-functions>
{
	for $mod in util:registered-modules()
	return
		<module uri="{$mod}">
		{
			for $f in util:registered-functions($mod)
			return
				util:describe-function($f)
		}
		</module>
}
</builtin-functions>
<my-functions>
{
	util:describe-function("local:afunction")
}
</my-functions>
</functions>


pm-backend: added utility listing to main index

xquery version "3.0";
declare namespace expath="http://expath.org/ns/pkg";
declare option exist:serialize "method=html5 media-type=text/html";
import module namespace export="http://politicalmashup.nl/modules/export";

    <meta charset="utf-8"/>
    <title>{doc("expath-pkg.xml")/expath:package/expath:title/text()}</title>
    {export:html-css-github()}

Political Mashup / Backend

Below is an overview of most utility scripts. See also documentation.politicalmashup.nl

export.xq

Facilitates listing all available data, with multiple input source and output format options.
          Useful for listings fed to curl etc.

id-members.xq

Identify political members based on their name and additional context. Explicitit member documents are available for Dutch an UK politicians.
          Possibly the most important script.

demo-search.xq

Search interface for the proceedings data.
          Has fewer options than search.politicalmashup.nl but is generally faster, and allows searching in all different language proceedings.

id-parldoc.xq

Identify parliamentary documents based on a dossier number and dossier subnumber. Script is able to correctly detect reprints.

id-parties.xq

Identify parties based on a string and a date.

list-updates.xq

List all documents added or updated since a given xs:dateTime.

list-votes.xq

List all votes per legislative period. Useful for the analyses requested by newspapers etc.

---------

analyse-members.xq

Allow analysis of members and their interactions, per legislative period: list all active members, list all text paragraphs from a member, list all scenes for inspection, and list all interruptions.

check-party-seats.xq

Old script used to analyse the seats distribution, to check if it is corectly extracted from the member data.
          Currently not very useful, but could be updated.

complete.xq

Analyses if the data is complete, by determining the sessions and items that should at least be availble, and checking for them.
          Note that this can be a computation-intensive script to run.

list-handle.xq

List a data collection as a Handle batch-script.

list-members.xq

List all members given filters (date, house, member-id etc.). More or less id-members.xq without a query.
          Used in the past to supply people with a lists of politicians in xml.

list-parldoc.xq

List all available parliamentary documents (currently only amendments) and their number of votes.

list-parties.xq

List all parties, given some filters.

list-party-seats.xq

List the seats of a party given some date and house. The seats are calculated dynamically during transformation, based on the people being a member for that party of that house.

get-votes.xq

Old, flaky, but important script that searches for votes in the proceedings based on a dossier- and sub-number.
          Throws an error when called without arguments, as an example see kst-32469-18.

stats.xq

Calculate statistics on the size of the data and percentage of members identified.

xquery version "1.0";

declare option exist:serialize "method=xhtml media-type=text/html";

            <title>Political Mashup - Backend Utilities</title>

Political Mashup - Backend Utilities


Change github URL (again) after current code restructuring

xquery version "3.1";

(:~
 : Test fn:unparsed-text and friends
 :)
module namespace upt="http://exist-db.org/xquery/test/unparsed-text";

import module namespace system="http://exist-db.org/xquery/system";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
import module namespace xmldb="http://exist-db.org/xquery/xmldb";

declare
    %test:setUp
function upt:store() {
    let $col := xmldb:create-collection("/db", "test-unparsed-text")
    return (
        xmldb:store($col, "test.txt", "Hello
world!
Hello
world!", "application/octet-stream"),
        xmldb:store($col, "test.xml", "
Hello world!
", "application/xml")
    )
};

declare
    %test:tearDown
function upt:cleanup() {
    xmldb:remove("/db/test-unparsed-text")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, 'eXist')")
function upt:unparsed-text-from-url() {
    unparsed-text("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, '----')")
function upt:unparsed-text-lines-from-url() {
    unparsed-text-lines("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README")[2]
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertEquals(6)
function upt:unparsed-text-lines-from-url-count() {
    count(unparsed-text-lines("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README"))
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, 'eXist')")
function upt:unparsed-text-from-url-encoding() {
    unparsed-text("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README", "UTF-8")
};

declare
    %test:assertEquals("Hello
world!
Hello
world!")
function upt:unparsed-text-from-db() {
    unparsed-text("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("Hello
world!
Hello
world!")
function upt:unparsed-text-from-db-full() {
    unparsed-text("xmldb:exist:///db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("Hello", "world!", "Hello", "world!")
function upt:unparsed-text-lines-from-db() {
    unparsed-text-lines("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("
Hello world!
")
function upt:unparsed-text-from-db-xml() {
    unparsed-text("/db/test-unparsed-text/test.xml")
};

declare
    %test:assertEquals(26436)
function upt:unparsed-text-from-file-dba() {
    let $home := translate(system:get-exist-home(), "\", "/")
    let $url := ``[file://`{$home}`/LICENSE]``
    return
        string-length(unparsed-text($url))
};

declare
    %test:assertEquals(504)
function upt:unparsed-text-lines-from-file-dba() {
    let $home := translate(system:get-exist-home(), "\", "/")
    let $url := ``[file://`{$home}`/LICENSE]``
    return
        count(unparsed-text-lines($url))
};

declare
    %test:assertError("FOUT1170")
function upt:unparsed-text-from-file-not-allowed() {
    system:as-user("guest", "guest", unparsed-text("file:///etc/passwd"))
};

declare
    %test:assertError("FOUT1170")
function upt:fragment-identifier() {
    unparsed-text-lines("http://www.example.org/#fragment")
};

declare
    %test:assertError("FOUT1170")
function upt:fragment-identifier-encoding() {
    unparsed-text("http://www.example.org/#fragment", "UTF-8")
};

declare
    %test:assertError("FOUT1170")
function upt:invalid-uri() {
    unparsed-text-lines("http://www.example.org/%gg")
};

declare
    %test:assertError("FOUT1170")
function upt:invalid-uri2() {
    unparsed-text-lines(":/")
};

declare
    %test:assertError("FOUT1170")
function upt:non-existant() {
    unparsed-text-lines("http://www.w3.org/fots/unparsed-text/does-not-exist.txt")
};

declare
    %test:assertError("FOUT1170")
function upt:unsupported-scheme() {
    fn:unparsed-text-lines("surely-nobody-supports-this:/path.txt")
};

declare
    %test:assertError("FOUT1170")
function upt:windows-path() {
    unparsed-text-lines("C:\file-might-exist.txt", "utf-8")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertTrue
function upt:unparsed-text-available-from-url() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertTrue
function upt:unparsed-text-available-from-url-encoding() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/README", "UTF-8")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertFalse
function upt:unparsed-text-available-from-url-encoding-no-content() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/exist-core/src/test/xquery/READMEaaaa", "UTF-8")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db() {
    unparsed-text-available("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db-full() {
    unparsed-text-available("xmldb:exist:///db/test-unparsed-text/test.txt")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db-xml() {
    unparsed-text-available("/db/test-unparsed-text/test.xml")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-fragment-identifier() {
    unparsed-text-available("http://www.example.org/#fragment")
};

declare
    %test:assertFalse
function upt:fragment-identifier-encoding() {
    unparsed-text-available("http://www.example.org/#fragment", "UTF-8")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-invalid-uri() {
    unparsed-text-available("http://www.example.org/%gg")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-invalid-uri2() {
    unparsed-text-available(":/")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-non-existant() {
    unparsed-text-available("http://www.w3.org/fots/unparsed-text/does-not-exist.txt")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-unsupported-scheme() {
    fn:unparsed-text-available("surely-nobody-supports-this:/path.txt")
};

xquery version "3.1";

(:~
 : Test fn:unparsed-text and friends
 :)
module namespace upt="http://exist-db.org/xquery/test/unparsed-text";

import module namespace system="http://exist-db.org/xquery/system";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
import module namespace xmldb="http://exist-db.org/xquery/xmldb";

declare
    %test:setUp
function upt:store() {
    let $col := xmldb:create-collection("/db", "test-unparsed-text")
    return (
        xmldb:store($col, "test.txt", "Hello
world!
Hello
world!", "application/octet-stream"),
        xmldb:store($col, "test.xml", "
Hello world!
", "application/xml")
    )
};

declare
    %test:tearDown
function upt:cleanup() {
    xmldb:remove("/db/test-unparsed-text")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, 'eXist')")
function upt:unparsed-text-from-url() {
    unparsed-text("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, '----')")
function upt:unparsed-text-lines-from-url() {
    unparsed-text-lines("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README")[2]
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertEquals(6)
function upt:unparsed-text-lines-from-url-count() {
    count(unparsed-text-lines("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README"))
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertXPath("contains($result, 'eXist')")
function upt:unparsed-text-from-url-encoding() {
    unparsed-text("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README", "UTF-8")
};

declare
    %test:assertEquals("Hello
world!
Hello
world!")
function upt:unparsed-text-from-db() {
    unparsed-text("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("Hello
world!
Hello
world!")
function upt:unparsed-text-from-db-full() {
    unparsed-text("xmldb:exist:///db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("Hello", "world!", "Hello", "world!")
function upt:unparsed-text-lines-from-db() {
    unparsed-text-lines("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertEquals("
Hello world!
")
function upt:unparsed-text-from-db-xml() {
    unparsed-text("/db/test-unparsed-text/test.xml")
};

declare
    %test:assertEquals(26436)
function upt:unparsed-text-from-file-dba() {
    let $home := translate(system:get-exist-home(), "\", "/")
    let $url := ``[file://`{$home}`/LICENSE]``
    return
        string-length(unparsed-text($url))
};

declare
    %test:assertEquals(504)
function upt:unparsed-text-lines-from-file-dba() {
    let $home := translate(system:get-exist-home(), "\", "/")
    let $url := ``[file://`{$home}`/LICENSE]``
    return
        count(unparsed-text-lines($url))
};

declare
    %test:assertError("FOUT1170")
function upt:unparsed-text-from-file-not-allowed() {
    system:as-user("guest", "guest", unparsed-text("file:///etc/passwd"))
};

declare
    %test:assertError("FOUT1170")
function upt:fragment-identifier() {
    unparsed-text-lines("http://www.example.org/#fragment")
};

declare
    %test:assertError("FOUT1170")
function upt:fragment-identifier-encoding() {
    unparsed-text("http://www.example.org/#fragment", "UTF-8")
};

declare
    %test:assertError("FOUT1170")
function upt:invalid-uri() {
    unparsed-text-lines("http://www.example.org/%gg")
};

declare
    %test:assertError("FOUT1170")
function upt:invalid-uri2() {
    unparsed-text-lines(":/")
};

declare
    %test:assertError("FOUT1170")
function upt:non-existant() {
    unparsed-text-lines("http://www.w3.org/fots/unparsed-text/does-not-exist.txt")
};

declare
    %test:assertError("FOUT1170")
function upt:unsupported-scheme() {
    fn:unparsed-text-lines("surely-nobody-supports-this:/path.txt")
};

declare
    %test:assertError("FOUT1170")
function upt:windows-path() {
    unparsed-text-lines("C:\file-might-exist.txt", "utf-8")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertTrue
function upt:unparsed-text-available-from-url() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertTrue
function upt:unparsed-text-available-from-url-encoding() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/README", "UTF-8")
};

declare
    %test:assumeInternetAccess("https://raw.githubusercontent.com")
    %test:assertFalse
function upt:unparsed-text-available-from-url-encoding-no-content() {
    unparsed-text-available("https://raw.githubusercontent.com/eXist-db/exist/develop/src/test/xquery/READMEaaaa", "UTF-8")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db() {
    unparsed-text-available("/db/test-unparsed-text/test.txt")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db-full() {
    unparsed-text-available("xmldb:exist:///db/test-unparsed-text/test.txt")
};

declare
    %test:assertTrue
function upt:unparsed-text-available-from-db-xml() {
    unparsed-text-available("/db/test-unparsed-text/test.xml")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-fragment-identifier() {
    unparsed-text-available("http://www.example.org/#fragment")
};

declare
    %test:assertFalse
function upt:fragment-identifier-encoding() {
    unparsed-text-available("http://www.example.org/#fragment", "UTF-8")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-invalid-uri() {
    unparsed-text-available("http://www.example.org/%gg")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-invalid-uri2() {
    unparsed-text-available(":/")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-non-existant() {
    unparsed-text-available("http://www.w3.org/fots/unparsed-text/does-not-exist.txt")
};

declare
    %test:assertFalse
function upt:unparsed-text-available-unsupported-scheme() {
    fn:unparsed-text-available("surely-nobody-supports-this:/path.txt")
};


fixed descriptions to show node() instead of just text(); added contributions from Loren (Version, Since, See)

svn path=/trunk/eXist/; revision=10964

xquery version "1.0";

(: $Id$ :)

(:~
    Main XQuery script for the RESTful function docs application.

    The parameters passed in from controller.xql are:
        basepath: Used as base path for URLs
        module:   Module name
        function: Function name

    The controller.xql intercepts URLs like
        http://exist-db.org/exist/functions/xmldb/login
    and parses and passes these parameters transparently to the script:
        basepath: /exist/functions/
        module:   xmldb
        function: login
:)

(: eXist module namespaces :)
declare namespace request="http://exist-db.org/xquery/request";
declare namespace text="http://exist-db.org/xquery/text";
declare namespace util="http://exist-db.org/xquery/util";

(: Document namespaces :)
declare namespace xq="http://www.xqdoc.org/1.0";

declare option exist:serialize "method=xhtml media-type=text/html indent=yes";

(: App root URL, passed in from controller.xql.  Used as base path for URLs. :)
declare variable $basepath := request:get-parameter('basepath', ());

(: Render a function or a set of functions :)
declare function local:render-function( $functionNode as element(xq:function)+, $showlinks as xs:boolean) as element() {
    let $parentModule := $functionNode/ancestor::xq:xqdoc/xq:module/xq:uri/text()
    let $parentModuleName := $functionNode/ancestor::xq:xqdoc/xq:module/xq:name/text()
    let $functionName := $functionNode/xq:name/text()
    let $functionSignature := $functionNode/xq:signature/text()
    let $functionDeprecated := $functionNode/xq:comment/xq:deprecated/text()
    let $functionDescription := $functionNode/xq:comment/xq:description/text()
    let $functionParagraphs := tokenize($functionDescription, "\n")
    let $functionVersion := $functionNode/xq:comment/xq:version/text()
    let $functionParameters := $functionNode/xq:comment/xq:param
    let $functionSees := $functionNode/xq:comment/xq:see
    let $functionReturns := $functionNode/xq:comment/xq:return/text()
    let $authors := $functionNode/xq:comment/xq:author
    let $sinces := $functionNode/xq:comment/xq:since
    return

{
                if ($showlinks) then
                    {$functionName}
                else $functionName
            }

{
                if (not(starts-with($functionSignature, $parentModuleName))) then
                    concat($parentModuleName, ':', $functionSignature)
                else
                    $functionSignature
            }

{
                for $desc in $functionParagraphs
                return

{$desc}

            }

{
                for $author in $authors
                return
                    {$author}
            }

            {
            if (string-length($functionVersion) > 0) then

Version {$functionVersion}

            else ()
            }

{
                if (empty($sinces)) then ()
                else

Since {string-join($sinces, ", ")}

            }

{
                for $see in $functionSees
                return

See {$see}

            }

{
                    for $parameter in $functionParameters
                    let $split := text:groups(normalize-space($parameter), "^(\$[^ ]+) (.*)$")
                    return

                            {$split[2]}
                            {$split[3]}

                }

            {
            if (string-length($functionReturns) > 0) then

Returns {$functionReturns}

            else (),
            if (string-length($functionDeprecated) > 0) then

Deprecated: {$functionDeprecated}

            else ()
            }

};

(: Render a module or set of modules :)
(: TODO add moduleSees, other standard XQDoc comments :)
declare function local:render-module($moduleURIs as xs:string+, $functionName as xs:string?, $showlinks as xs:boolean) as element()+ {
    for $moduleURI in $moduleURIs
	let $moduleDocs := /xq:xqdoc[xq:module/xq:uri eq $moduleURI]
	let $moduleName := if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then 'fn' else $moduleDocs/xq:module/xq:name/text()
	let $moduleDescription := $moduleDocs/xq:module/xq:comment/xq:description/node()
	order by $moduleURI
	return

{
                  if ($showlinks) then
                     {$moduleName}
                  else
                     $moduleName
               }

{$moduleURI}

{$moduleDescription}

{
	           (: Decide whether to render a single function or to render them all :)
	           if ($functionName) then
	               for $functionNode in $moduleDocs/xq:functions/xq:function[xq:name eq $functionName]
                   return local:render-function($functionNode, $showlinks)
               else
    	           for $functionNode in $moduleDocs/xq:functions/xq:function
    	           return local:render-function($functionNode, $showlinks)
	       }

};

(:
 : URL handling functions
 :)

(: Constructs a URL from a module URI :)
declare function local:moduleURI-to-URL($moduleURI as xs:string) as xs:string {
    if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then
        concat($basepath, 'fn')
    else
        concat($basepath, /xq:xqdoc/xq:module[xq:uri eq $moduleURI]/xq:name/text())
};

(: Constructs a URL from a module :)
declare function local:module-to-URL($module as xs:string) as xs:string {
    concat($basepath, $module)
};

(: Constructs a URL from a function :)
declare function local:function-to-URL($moduleURI as xs:string, $function as xs:string) {
    concat(local:moduleURI-to-URL($moduleURI), '/', $function)
};

(: Derives the module name from the module URI :)
declare function local:moduleURI-to-module($moduleURI as xs:string) as xs:string {
    if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then
        'fn'
    else
        /xq:xqdoc/xq:module[xq:uri eq $moduleURI]/xq:name/text()
};

(: Lists all modules :)
declare function local:list-modules($moduleURIs) {
    (

Reload documentation
        (click here if you enabled/disabled additional modules)

    ,

(eXist version: {util:system-property("product-version")},
        build: {util:system-property("product-build")}, functions: {count(//xq:function)}.)
        Modules have to be enabled in conf.xml to appear here.

    ,

Expand All or select a single module:

    ,

Name	Description	Namespace URI

{
            for $moduleURI in $moduleURIs
            let $moduleDocs := /xq:xqdoc[xq:module/xq:uri eq $moduleURI]
        	let $moduleName :=
        	   if ($moduleURI eq 'http://www.w3.org/2005/xpath-functions') then
        	       (: note: the xq:name for the xpath functions module is empty
        	        : since it's the default function namespace, but we need a name
        	        : for the link, so we just use 'fn' :)
        	       'fn'
               else $moduleDocs/xq:module/xq:name/text()
        	let $moduleDescription := $moduleDocs/xq:module/xq:comment/xq:description/node()
        	order by $moduleURI
            return

                    {$moduleName}
                    {$moduleDescription}
                    {$moduleURI}

        }

    )
};

(: Breadcrumbs for the page :)
declare function local:breadcrumbs($module, $function, $viewall) {

        Modules
        {
        if ($viewall) then
            ' > All Modules and Functions'
        else if ($module and not($function)) then
            (
            ' > '
            ,
            {$module}
            )
        else if ($module and $function) then
            (
            ' > '
            ,
            {$module}
            ,
            ' > '
            ,
            {$function}
            )
        else
            ' > Home'
        }

};

(: Footer-like 'return to home' link :)
declare function local:return-to-main() as element() {

        Return to list of all modules

};

(: Business logic :)
declare function local:main() {
    (: Get URL parameters :)
    let $module := request:get-parameter('module', ())
    let $function := request:get-parameter('function', ())
    let $showlinks := request:get-parameter('showlinks', 1) cast as xs:boolean
    let $q := request:get-parameter('q', ())

    (: Catch a request for 'all', i.e. the complete listing :)
    let $viewall := $module eq 'all'

    (: Derive module URIs based on URL parameter $module :)
    let $allModuleURIs := /xq:xqdoc/xq:module/xq:uri
    let $matchingModuleURIs := if ($module) then
        if ($module = 'fn') then
            'http://www.w3.org/2005/xpath-functions'
        else
            $allModuleURIs[following-sibling::xq:name eq $module]
        else ()
    let $moduleURIs := if ($matchingModuleURIs) then $matchingModuleURIs else $allModuleURIs

    return
        (
        (: Show documentation for all modules:)
        if ($viewall) then
            (
            local:breadcrumbs($module, $function, $viewall)
            ,
            local:render-module($moduleURIs, (), $showlinks)
            ,
            local:return-to-main()
            )
        (: Show just the list of modules :)
        else if (not($module)) then
            (
            local:breadcrumbs($module, $function, $viewall)
            ,
            local:list-modules($moduleURIs)
            )
        (: Show a single module :)
        else if ($module and $matchingModuleURIs) then
            if (count($matchingModuleURIs) gt 1) then
                (: TODO: Add handling for resolving modules with the same 'name' :)
                (
                local:breadcrumbs($module, $function, $viewall)
                ,
                local:render-module($moduleURIs, $function, $showlinks)
                ,
                local:return-to-main()
                )
            else
                (
                local:breadcrumbs($module, $function, $viewall)
                ,
                local:render-module($moduleURIs, $function, $showlinks)
                ,
                local:return-to-main()
                )
        (: Handle cases where there are no exact matching modules :)
        else
            (: else if ($module and not($matchingModules)) :)
            (: TODO add a fuzzy search :)
            (
            local:breadcrumbs((), (), $viewall)
            ,

Sorry, there are no modules that match "{$module}."  Please choose from the list below:

            ,
            local:list-modules($moduleURIs)
            )
        )

};

(: Module body :)
<book>
    <bookinfo>
        <graphic fileref="logo.jpg"/>
        <productname>Open Source Native XML Database</productname>
        <title>eXist Function Modules</title>
        <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
		<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>

    </bookinfo>

        <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../sidebar.xml"/>

    <chapter>
        <title>A RESTful browser for eXist Function Modules</title>
        { local:main() }
    </chapter>
</book>

xquery version "1.0";

(: $Id$ :)

(:~
    Main XQuery script for the RESTful function docs application.

    The parameters passed in from controller.xql are:
        basepath: Used as base path for URLs
        module:   Module name
        function: Function name

    The controller.xql intercepts URLs like
        http://exist-db.org/exist/functions/xmldb/login
    and parses and passes these parameters transparently to the script:
        basepath: /exist/functions/
        module:   xmldb
        function: login
:)

(: eXist module namespaces :)
declare namespace request="http://exist-db.org/xquery/request";
declare namespace text="http://exist-db.org/xquery/text";
declare namespace util="http://exist-db.org/xquery/util";

(: Document namespaces :)
declare namespace xq="http://www.xqdoc.org/1.0";

declare option exist:serialize "method=xhtml media-type=text/html indent=yes";

(: App root URL, passed in from controller.xql.  Used as base path for URLs. :)
declare variable $basepath := request:get-parameter('basepath', ());

(: Render a function or a set of functions :)
declare function local:render-function( $functionNode as element(xq:function)+, $showlinks as xs:boolean) as element() {
    let $parentModule := $functionNode/ancestor::xq:xqdoc/xq:module/xq:uri/text()
    let $parentModuleName := $functionNode/ancestor::xq:xqdoc/xq:module/xq:name/text()
    let $functionName := $functionNode/xq:name/text()
    let $functionSignature := $functionNode/xq:signature/text()
    let $functionDeprecated := $functionNode/xq:comment/xq:deprecated/text()
    let $functionDescription := $functionNode/xq:comment/xq:description/text()
    let $functionParagraphs := tokenize($functionDescription, "\n")
    let $functionVersion := $functionNode/xq:comment/xq:version
    let $functionParameters := $functionNode/xq:comment/xq:param
    let $functionReturns := $functionNode/xq:comment/xq:return/text()
    let $authors := $functionNode/xq:comment/xq:author
    let $sinces := $functionNode/xq:comment/xq:since
    return

{
                if ($showlinks) then
                    {$functionName}
                else $functionName
            }

{if (not(starts-with($functionSignature, $parentModuleName))) then concat($parentModuleName, ':', $functionSignature) else $functionSignature}

{
                for $desc in $functionParagraphs
                return

{$desc}

            }

{
                for $author in $authors
                return
                    {$author}
            }

{$functionVersion}

{
                for $since in $sinces
                return
                    {$since}
            }

{
                    for $parameter in $functionParameters
                    let $split := text:groups($parameter, "^(\$[^ ]+) (.*)$")
                    return

                            {$split[2]}
                            {$split[3]}

                }

            {
            if (string-length($functionReturns) > 0)
            then

Returns {$functionReturns}

            else (),
            if (string-length($functionDeprecated) > 0)
            then

Deprecated: {$functionDeprecated}

            else ()
            }

};

(: Render a module or set of modules :)
declare function local:render-module($moduleURIs as xs:string+, $functionName as xs:string?, $showlinks as xs:boolean) as element()+ {
    for $moduleURI in $moduleURIs
	let $moduleDocs := /xq:xqdoc[xq:module/xq:uri eq $moduleURI]
	let $moduleName := if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then 'fn' else $moduleDocs/xq:module/xq:name/text()
	let $moduleDescription := $moduleDocs/xq:module/xq:comment/xq:description/text()
	order by $moduleURI
	return

{
                  if ($showlinks) then
                     {$moduleName}
                  else
                     $moduleName
               }

{$moduleURI}

{$moduleDescription}

{
	           (: Decide whether to render a single function or to render them all :)
	           if ($functionName) then
	               for $functionNode in $moduleDocs/xq:functions/xq:function[xq:name eq $functionName]
                   return local:render-function($functionNode, $showlinks)
               else
    	           for $functionNode in $moduleDocs/xq:functions/xq:function
    	           return local:render-function($functionNode, $showlinks)
	       }

};

(:
 : URL handling functions
 :)

(: Constructs a URL from a module URI :)
declare function local:moduleURI-to-URL($moduleURI as xs:string) as xs:string {
    if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then
        concat($basepath, 'fn')
    else
        concat($basepath, /xq:xqdoc/xq:module[xq:uri eq $moduleURI]/xq:name/text())
};

(: Constructs a URL from a module :)
declare function local:module-to-URL($module as xs:string) as xs:string {
    concat($basepath, $module)
};

(: Constructs a URL from a function :)
declare function local:function-to-URL($moduleURI as xs:string, $function as xs:string) {
    concat(local:moduleURI-to-URL($moduleURI), '/', $function)
};

(: Derives the module name from the module URI :)
declare function local:moduleURI-to-module($moduleURI as xs:string) as xs:string {
    if ($moduleURI = 'http://www.w3.org/2005/xpath-functions') then
        'fn'
    else
        /xq:xqdoc/xq:module[xq:uri eq $moduleURI]/xq:name/text()
};

(: Lists all modules :)
declare function local:list-modules($moduleURIs) {
    (

Reload documentation
        (click here if you enabled/disabled additional modules)

    ,

(eXist version: {util:system-property("product-version")},
        build: {util:system-property("product-build")}, functions: {count(//xq:function)}.)
        Modules have to be enabled in conf.xml to appear here.

    ,

Expand All or select a single module:

    ,

Name	Description	Namespace URI

{
            for $moduleURI in $moduleURIs
            let $moduleDocs := /xq:xqdoc[xq:module/xq:uri eq $moduleURI]
        	let $moduleName :=
        	   if ($moduleURI eq 'http://www.w3.org/2005/xpath-functions') then
        	       (: note: the xq:name for the xpath functions module is empty
        	        : since it's the default function namespace, but we need a name
        	        : for the link, so we just use 'fn' :)
        	       'fn'
               else $moduleDocs/xq:module/xq:name/text()
        	let $moduleDescription := $moduleDocs/xq:module/xq:comment/xq:description/text()
        	order by $moduleURI
            return

                    {$moduleName}
                    {$moduleDescription}
                    {$moduleURI}

        }

    )
};

(: Breadcrumbs for the page :)
declare function local:breadcrumbs($module, $function, $viewall) {

        Modules
        {
        if ($viewall) then
            ' > All Modules and Functions'
        else if ($module and not($function)) then
            (
            ' > '
            ,
            {$module}
            )
        else if ($module and $function) then
            (
            ' > '
            ,
            {$module}
            ,
            ' > '
            ,
            {$function}
            )
        else
            ' > Home'
        }

};

(: Footer-like 'return to home' link :)
declare function local:return-to-main() as element() {

        Return to list of all modules

};

(: Business logic :)
declare function local:main() {
    (: Get URL parameters :)
    let $module := request:get-parameter('module', ())
    let $function := request:get-parameter('function', ())
    let $showlinks := request:get-parameter('showlinks', 1) cast as xs:boolean
    let $q := request:get-parameter('q', ())

    (: Catch a request for 'all', i.e. the complete listing :)
    let $viewall := $module eq 'all'

    (: Derive module URIs based on URL parameter $module :)
    let $allModuleURIs := /xq:xqdoc/xq:module/xq:uri
    let $matchingModuleURIs := if ($module) then
        if ($module = 'fn') then
            'http://www.w3.org/2005/xpath-functions'
        else
            $allModuleURIs[following-sibling::xq:name eq $module]
        else ()
    let $moduleURIs := if ($matchingModuleURIs) then $matchingModuleURIs else $allModuleURIs

    return
        (
        (: Show documentation for all modules:)
        if ($viewall) then
            (
            local:breadcrumbs($module, $function, $viewall)
            ,
            local:render-module($moduleURIs, (), $showlinks)
            ,
            local:return-to-main()
            )
        (: Show just the list of modules :)
        else if (not($module)) then
            (
            local:breadcrumbs($module, $function, $viewall)
            ,
            local:list-modules($moduleURIs)
            )
        (: Show a single module :)
        else if ($module and $matchingModuleURIs) then
            if (count($matchingModuleURIs) gt 1) then
                (: TODO: Add handling for resolving modules with the same 'name' :)
                (
                local:breadcrumbs($module, $function, $viewall)
                ,
                local:render-module($moduleURIs, $function, $showlinks)
                ,
                local:return-to-main()
                )
            else
                (
                local:breadcrumbs($module, $function, $viewall)
                ,
                local:render-module($moduleURIs, $function, $showlinks)
                ,
                local:return-to-main()
                )
        (: Handle cases where there are no exact matching modules :)
        else
            (: else if ($module and not($matchingModules)) :)
            (: TODO add a fuzzy search :)
            (
            local:breadcrumbs((), (), $viewall)
            ,

Sorry, there are no modules that match "{$module}."  Please choose from the list below:

            ,
            local:list-modules($moduleURIs)
            )
        )

};

(: Module body :)
<book>
    <bookinfo>
        <graphic fileref="logo.jpg"/>
        <productname>Open Source Native XML Database</productname>
        <title>eXist Function Modules</title>
        <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
		<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>

    </bookinfo>

        <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../sidebar.xml"/>

    <chapter>
        <title>A RESTful browser for eXist Function Modules</title>
        { local:main() }
    </chapter>
</book>


cleanup UI for FHIR queries

cleanup UI for FHIR queries

module namespace page = 'http://basex.org/modules/web-page';

(:Import other namespaces.  :)
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace fadpt = "https://github.com/openhie/openinfoman/adapter/fhir";
import module namespace request = "http://exquery.org/ns/request";

declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare namespace   xforms = "http://www.w3.org/2002/xforms";
declare namespace fhir = "http://hl7.org/fhir";

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}")
  %output:method("xhtml")
  function page:show_endpoints($search_name)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $extensions :=   $function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter' and  @type='fhir']
  return
    if (not(fadpt:is_fhir_function($search_name)))
      (:not a read fhir entity query. should 404 or whatever is required by FHIR :)
    then ('Not a FHIR Compatible stored functions' )
    else
      let
	$contents :=

FHIR Documents

              {
  		for $doc_name in csd_dm:registered_documents($csd_webconf:db)
		return

		  {string($doc_name)}

	      }

       return csd_webconf:wrapper($contents)

};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}")
  %output:method("xhtml")
  function page:show_endpoints($search_name,$doc_name)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $read :=  ($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]
  let $entity := string($read/@type)
  let $base_url := concat($csd_webconf:baseurl, "CSD/adapter/fhir/",$search_name, "/", $doc_name, "/", $entity)
  let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
  let $org_opts :=
    for $org in $doc/csd:CSD/csd:organizationDirectory/csd:organization
    return <option value="{$org/@urn}">{($org/csd:primaryName[1])/text()}</option>
  let $fac_opts :=
    for $fac in $doc/csd:CSD/csd:facilityDirectory/csd:facility
    return <option value="{$fac/@urn}">{($fac/csd:primaryName[1])/text()}</option>

  return
    if (not(fadpt:is_fhir_function($search_name)) or not($read)  )
      (:not a read practitioner query. should 404 or whatever is required by FHIR :)
    then ('Not a FHIR Compatible stored function'    )
    else
      let $headers :=
	(
	<link rel="stylesheet" type="text/css" media="screen"   href="{$csd_webconf:baseurl}static/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css"/>
	,
	 )

      let $contents :=

{$entity} in {$doc_name}

Resource Endpoint:
{$base_url}

	    Search
	     XML
	    / JSON

Query by entity details

	    <form method='get' action="{$base_url}/_search">
	      Common Name
	      <input  size="35"    name='name.text' type="text" value=""/>

	      Format
	      <select name="_format">
	        <option value="xml">XML</option>
	        <option value="json">JSON</option>
	      </select>

	      Organization
	      <select name="organization.reference">
	        <option value="">Select A Value</option>
		{$org_opts}
	      </select>

	      Facility
	      <select name="location.reference">
	        <option value="">Select A Value</option>
		{$fac_opts}
	      </select>

	      <input type='submit' />
	    </form>

	    History
	     XML
	    / JSON

Query by last modified time

	    <form method='get' action="{$base_url}/_history">
	      Format
	      <select name="_format">
	        <option value="xml">XML</option>
	        <option value="json">JSON</option>
	      </select>

	      Updated
	      <input  size="35" id="datetimepicker_xml"    name='_since' type="text" value=""/>

	      <input type='submit' />
	    </form>

      return csd_webconf:wrapper($contents,$headers)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/{$id}")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:read_entity($search_name,$doc_name,$entityType,$format,$id)
{

  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $careServicesRequest :=
      <csd:careServicesRequest >
	<csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	  <csd:requestParams >
	    <id>{$id}</id>
	  </csd:requestParams>
	</csd:function>
      </csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))[1] (:make sure there is only one:)
    let $resource := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then
        (
        <rest:response>
	  <output:serialization-parameters>
	    <output:media-type value='application/json'/>
	  </output:serialization-parameters>
	</rest:response>
	,$resource
        )
      else
	$resource
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/_search")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:search_entity2($search_name,$doc_name,$entityType,$format)
{
  page:search_entity($search_name,$doc_name,$entityType,$format)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:search_entity($search_name,$doc_name,$entityType,$format)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $requestParams :=
      <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	<csd:requestParams >
	  {page:search_global_parameters() }
	  {
	    switch ($entityType)
	    case "Practitioner" return  page:search_practitioner_parameters()
	    case "Location" return () (: page:search_location_parameters() :)
	    case "Organization" return () (: page:search_organization_parameters() :)
	    default return ()
	  }
	</csd:requestParams>
      </csd:function>

    let $careServicesRequest :=   <csd:careServicesRequest >{$requestParams}</csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))
    let $resources := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then fadpt:create_feed_from_entities_JSON($resources,$requestParams)
      else fadpt:create_feed_from_entities($resources,$requestParams)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/_history")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:history_entity($search_name,$doc_name,$entityType,$format)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $requestParams :=
      <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	<csd:requestParams >
	  {page:history_global_parameters() }
	</csd:requestParams>
      </csd:function>

    let $careServicesRequest :=   <csd:careServicesRequest >{$requestParams}</csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))
    let $resources := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then fadpt:create_feed_from_entities_JSON($resources,$requestParams)
      else fadpt:create_feed_from_entities($resources,$requestParams)

};

declare function page:search_global_parameters()
{
  let $params := request:parameter-names()
  return
    (
      if ("_id" = $params)
      then <fhir:_id>{request:parameter("_id")}</fhir:_id>
      else ()
      ,
      if ("_count" = $params)
      then <fhir:_count>{request:parameter("_count")}</fhir:_count>
      else ()
      ,
      if ("page" = $params)
      then <page>{request:parameter("_pageOffset")}</page>
      else ()
    )
};

declare function page:search_practitioner_parameters(){
  let $params := request:parameter-names()
  return
    (
      if ("name.text" = $params)
      then <fhir:name><fhir:text>{request:parameter("name.text")}</fhir:text></fhir:name>
      else (),
      if ("organization.reference" = $params)
      then <fhir:organization value="{request:parameter('organization.reference')}"/>
      else (),
      if ("location.reference" = $params)
      then <fhir:location value="{request:parameter('location.reference')}"/>
      else ()

  )

};

declare function page:history_global_parameters()
{
  let $params := request:parameter-names()
  return
    (
      if ("_since" = $params)
      then <fhir:_since>{request:parameter("_since")}</fhir:_since>
      else ()
      ,
      if ("_count" = $params)
      then <fhir:_count>{request:parameter("_count")}</fhir:_count>
      else ()
      ,
      if ("page" = $params)
      then <page>{request:parameter("_pageOffset")}</page>
      else ()
    )
};

module namespace page = 'http://basex.org/modules/web-page';

(:Import other namespaces.  :)
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace fadpt = "https://github.com/openhie/openinfoman/adapter/fhir";
import module namespace request = "http://exquery.org/ns/request";

declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare namespace   xforms = "http://www.w3.org/2002/xforms";
declare namespace fhir = "http://hl7.org/fhir";

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}")
  %output:method("xhtml")
  function page:show_endpoints($search_name)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $extensions :=   $function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter' and  @type='fhir']
  return
    if (not(fadpt:is_fhir_function($search_name)))
      (:not a read fhir entity query. should 404 or whatever is required by FHIR :)
    then ('Not a FHIR Compatible stored functions' )
    else
      let
	$contents :=

FHIR Documents

              {
  		for $doc_name in csd_dm:registered_documents($csd_webconf:db)
		return

		  {string($doc_name)}

	      }

       return csd_webconf:wrapper($contents)

};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}")
  %output:method("xhtml")
  function page:show_endpoints($search_name,$doc_name)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $read :=  ($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]
  let $entity := string($read/@type)
  let $base_url := concat($csd_webconf:baseurl, "CSD/adapter/fhir/",$search_name, "/", $doc_name, "/", $entity)
  let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
  let $org_opts :=
    for $org in $doc/csd:CSD/csd:organizationDirectory/csd:organization
    return <option value="{$org/@urn}">{($org/csd:primaryName[1])/text()}</option>
  let $fac_opts :=
    for $fac in $doc/csd:CSD/csd:facilityDirectory/csd:facility
    return <option value="{$fac/@urn}">{($fac/csd:primaryName[1])/text()}</option>

  return
    if (not(fadpt:is_fhir_function($search_name)) or not($read)  )
      (:not a read practitioner query. should 404 or whatever is required by FHIR :)
    then ('Not a FHIR Compatible stored function'    )
    else
      let $headers :=
	(
	<link rel="stylesheet" type="text/css" media="screen"   href="{$csd_webconf:baseurl}static/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css"/>
	,
	 )

      let $contents :=

{$entity} in {$doc_name}

Resource Endpoint:
{$base_url}

	    Search
	     XML
	    / JSON

Query by last modified time (XML)

	    <form method='get' action="{$base_url}/_search">
	      Common Name
	      <input  size="35"    name='name.text' type="text" value=""/>

	      Organization
	      <select name="organization.reference">
	        <option value="">Select A Value</option>
		{$org_opts}
	      </select>

	      Facility
	      <select name="location.reference">
	        <option value="">Select A Value</option>
		{$fac_opts}
	      </select>

	      <input type='submit' />
	    </form>

Query by last modified time (JSON)

	    <form method='get' action="{$base_url}/_search">
	      Common Name
	      <input  size="35"    name='name.text' type="text" value=""/>

	      Organization
	      <select name="organization.reference">
	        <option value="">Select A Value</option>
		{$org_opts}
	      </select>

	      Facility
	      <select name="location.reference">
	        <option value="">Select A Value</option>
		{$fac_opts}
	      </select>

	      <input type='hidden' name='_format' value='json'/>
	      <input type='submit' />
	    </form>

	    History
	     XML
	    / JSON

Query by last modified time (XML)

	    <form method='get' action="{$base_url}/_history">
	      Updated
	      <input  size="35" id="datetimepicker_xml"    name='_since' type="text" value=""/>

	      <input type='submit' />
	    </form>

Query by last modified time (JSON)

	    <form method='get' action="{$base_url}/_history">
	      Updated
	      <input  size="35" id="datetimepicker_json"    name='_since' type="text" value=""/>

	      <input type='hidden' name='_format' value='json'/>
	      <input type='submit' />
	    </form>

      return csd_webconf:wrapper($contents,$headers)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/{$id}")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:read_entity($search_name,$doc_name,$entityType,$format,$id)
{

  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $careServicesRequest :=
      <csd:careServicesRequest >
	<csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	  <csd:requestParams >
	    <id>{$id}</id>
	  </csd:requestParams>
	</csd:function>
      </csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))[1] (:make sure there is only one:)
    let $resource := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then
        (
        <rest:response>
	  <output:serialization-parameters>
	    <output:media-type value='application/json'/>
	  </output:serialization-parameters>
	</rest:response>
	,$resource
        )
      else
	$resource
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/_search")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:search_entity2($search_name,$doc_name,$entityType,$format)
{
  page:search_entity($search_name,$doc_name,$entityType,$format)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:search_entity($search_name,$doc_name,$entityType,$format)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $requestParams :=
      <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	<csd:requestParams >
	  {page:search_global_parameters() }
	  {
	    switch ($entityType)
	    case "Practitioner" return  page:search_practitioner_parameters()
	    case "Location" return () (: page:search_location_parameters() :)
	    case "Organization" return () (: page:search_organization_parameters() :)
	    default return ()
	  }
	</csd:requestParams>
      </csd:function>

    let $careServicesRequest :=   <csd:careServicesRequest >{$requestParams}</csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))
    let $resources := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then fadpt:create_feed_from_entities_JSON($resources,$requestParams)
      else fadpt:create_feed_from_entities($resources,$requestParams)
};

declare
  %rest:path("/CSD/adapter/fhir/{$search_name}/{$doc_name}/{$entityType}/_history")
  %rest:query-param("_format","{$format}","application/xml+fhir")
  function page:history_entity($search_name,$doc_name,$entityType,$format)
{
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $fEntityType :=   string(($function/csd:extension[@urn='urn:openhie.org:openinfoman:adapter:fhir:read' ])[1]/@type)
  return
    if (not(fadpt:is_fhir_function($search_name)) or not($fEntityType = $entityType))
    (:not a valid read query. should 404 or whatever is required by FHIR :)
  then ()
  else
    let $doc := csd_dm:open_document($csd_webconf:db,$doc_name)
    let $requestParams :=
      <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{$csd_webconf:baseurl}">
	<csd:requestParams >
	  {page:history_global_parameters() }
	</csd:requestParams>
      </csd:function>

    let $careServicesRequest :=   <csd:careServicesRequest >{$requestParams}</csd:careServicesRequest>
    let $entities := (csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest))
    let $resources := fadpt:format_entities($doc,$entities,$entityType,$format)
    return
      if ($format = ('application/json+fhir' ,  'application/json' ,'json'))
      then fadpt:create_feed_from_entities_JSON($resources,$requestParams)
      else fadpt:create_feed_from_entities($resources,$requestParams)

};

declare function page:search_global_parameters()
{
  let $params := request:parameter-names()
  return
    (
      if ("_id" = $params)
      then <fhir:_id>{request:parameter("_id")}</fhir:_id>
      else ()
      ,
      if ("_count" = $params)
      then <fhir:_count>{request:parameter("_count")}</fhir:_count>
      else ()
      ,
      if ("page" = $params)
      then <page>{request:parameter("_pageOffset")}</page>
      else ()
    )
};

declare function page:search_practitioner_parameters(){
  let $params := request:parameter-names()
  return
    (
      if ("name.text" = $params)
      then <fhir:name><fhir:text>{request:parameter("name.text")}</fhir:text></fhir:name>
      else (),
      if ("organization.reference" = $params)
      then <fhir:organization value="{request:parameter('organization.reference')}"/>
      else (),
      if ("location.reference" = $params)
      then <fhir:location value="{request:parameter('location.reference')}"/>
      else ()

  )

};

declare function page:history_global_parameters()
{
  let $params := request:parameter-names()
  return
    (
      if ("_since" = $params)
      then <fhir:_since>{request:parameter("_since")}</fhir:_since>
      else ()
      ,
      if ("_count" = $params)
      then <fhir:_count>{request:parameter("_count")}</fhir:_count>
      else ()
      ,
      if ("page" = $params)
      then <page>{request:parameter("_pageOffset")}</page>
      else ()
    )
};


Added support for manually added subtopics.

svn path=/trunk/eXist-1.0/; revision=3753

<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:atom="http://www.w3.org/2005/Atom">
   {
     "
",
     /atom:feed/atom:title,
     "
",
     /atom:feed/atom:id,
     "
",
     /atom:feed/atom:updated,
     "
",
     /atom:feed/atom:entry[atom:category[@scheme='http://www.smallx.com/Ontology/Atopic/2006/1/0/topic/relation' and @term='subtopic']]
   }
   {
      let $current := substring-before(base-uri(/atom:feed),'/.feed.atom'),
           $current-path := substring-after($current,'/db')
         return (
            <link rel="alternate" href="/atom/content{substring-after($current,'/db')}" type="application/atom+xml"/>,
           "
",
            let $parts := tokenize($current-path,'/')
               for $i in (1 to count($parts)-1)
                   let $apath := string-join(subsequence($parts,1,$i),'/'),
                       $feed := document(concat($apath,'/.feed.atom'))/atom:feed
                     return if (not($feed/atom:category[@scheme='http://www.smallx.com/Ontology/Atopic/2006/1/0/display' and @term='false']))
                       then (<entry>
                            {
                                "
",
                                $feed/atom:id,
                                "
",
                                $feed/atom:title,
                                "
",
                                $feed/atom:updated,
                                "
",
                                <category scheme="http://www.smallx.com/Ontology/Atopic/2006/1/0/topic/relation" term="ancestor"/>,
                                "
",
                                <link rel="alternate" href="/atom/content/{$apath}" type="application/atom+xml"/>,
                                "
",
                                <summary>
                                     {
                                         $feed/atom:subtitle/@type,
                                         $feed/atom:subtitle/node()
                                     }
                                </summary>,
                                "
"
                             }
                            </entry>,
                            "
"
                            )
                       else (),
            for $i in (collection($current)/atom:feed)
               let $path :=  substring-before(base-uri($i),'/.feed.atom'),
                   $prefix := concat($current,'/')
                  return if ($current!=$path and not(contains(substring-after($path,$prefix),'/'))
                             and not($i/atom:category[@scheme='http://www.smallx.com/Ontology/Atopic/2006/1/0/display' and @term='false']))
                     then (<entry>
                            {
                                "
",
                                $i/atom:id,
                                "
",
                                $i/atom:title,
                                "
",
                                $i/atom:updated,
                                "
",
                                <category scheme="http://www.smallx.com/Ontology/Atopic/2006/1/0/topic/relation" term="subtopic"/>,
                                "
",
                                <link rel="alternate" href="/atom/content{substring-after($path,'/db')}" type="application/atom+xml"/>,
                                "
",
                                <summary>
                                     {
                                         $i/atom:subtitle/@type,
                                         $i/atom:subtitle/node()
                                     }
                                </summary>,
                                "
"
                             }
                            </entry>,
                            "
"
                            )
                     else ()
         )
   }
</feed>

<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:atom="http://www.w3.org/2005/Atom">
   {
     "
",
     /atom:feed/atom:title,
     "
",
     /atom:feed/atom:id,
     "
",
     /atom:feed/atom:updated,
     "
"
   }
   {
      let $current := substring-before(base-uri(/atom:feed),'/.feed.atom'),
           $current-path := substring-after($current,'/db')
         return (
            <link rel="alternate" href="/atom/content{substring-after($current,'/db')}" type="application/atom+xml"/>,
           "
",
            let $parts := tokenize($current-path,'/')
               for $i in (1 to count($parts)-1)
                   let $apath := string-join(subsequence($parts,1,$i),'/'),
                       $feed := document(concat($apath,'/.feed.atom'))/atom:feed
                     return if (not($feed/atom:category[@scheme='http://www.smallx.com/Ontology/Atopic/2006/1/0/display' and @term='false']))
                       then (<entry>
                            {
                                "
",
                                $feed/atom:id,
                                "
",
                                $feed/atom:title,
                                "
",
                                $feed/atom:updated,
                                "
",
                                <category scheme="http://www.smallx.com/Ontology/Atopic/2006/1/0/topic/relation" term="ancestor"/>,
                                "
",
                                <link rel="alternate" href="/atom/content/{$apath}" type="application/atom+xml"/>,
                                "
",
                                <summary>
                                     {
                                         $feed/atom:subtitle/@type,
                                         $feed/atom:subtitle/node()
                                     }
                                </summary>,
                                "
"
                             }
                            </entry>,
                            "
"
                            )
                       else (),
            for $i in (collection($current)/atom:feed)
               let $path :=  substring-before(base-uri($i),'/.feed.atom'),
                   $prefix := concat($current,'/')
                  return if ($current!=$path and not(contains(substring-after($path,$prefix),'/'))
                             and not($i/atom:category[@scheme='http://www.smallx.com/Ontology/Atopic/2006/1/0/display' and @term='false']))
                     then (<entry>
                            {
                                "
",
                                $i/atom:id,
                                "
",
                                $i/atom:title,
                                "
",
                                $i/atom:updated,
                                "
",
                                <category scheme="http://www.smallx.com/Ontology/Atopic/2006/1/0/topic/relation" term="subtopic"/>,
                                "
",
                                <link rel="alternate" href="/atom/content{substring-after($path,'/db')}" type="application/atom+xml"/>,
                                "
",
                                <summary>
                                     {
                                         $i/atom:subtitle/@type,
                                         $i/atom:subtitle/node()
                                     }
                                </summary>,
                                "
"
                             }
                            </entry>,
                            "
"
                            )
                     else ()
         )
   }
</feed>