removing useless code

removing useless code

(:
  Copyright 2012-2016 MarkLogic Corporation

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
:)
xquery version "1.0-ml";

module namespace flow = "http://marklogic.com/data-hub/flow-lib";

import module namespace debug = "http://marklogic.com/data-hub/debug-lib"
  at "/com.marklogic.hub/lib/debug-lib.xqy";

import module namespace hul = "http://marklogic.com/data-hub/hub-utils-lib"
  at "/com.marklogic.hub/lib/hub-utils-lib.xqy";

import module namespace functx = "http://www.functx.com"
  at "/MarkLogic/functx/functx-1.0-nodoc-2007-01.xqy";

declare namespace hub = "http://marklogic.com/data-hub";

declare namespace envelope = "http://marklogic.com/data-hub/envelope";

declare option xdmp:mapping "false";

(: xml describing the default writer :)
declare variable $DEFAULT-WRITER :=
  element hub:writer {
    attribute type { "xquery" },
    attribute module { "/com.marklogic.hub/writers/default.xqy" }
  };

(: xml describing the default content plugin :)
declare variable $DEFAULT-CONTENT-PLUGIN :=
  element hub:plugin {
    attribute dest { "content" },
    attribute type { "xquery" },
    attribute module { "/com.marklogic.hub/plugins/raw.xqy" }
  };

(: xml describing a no-op plugin. used when no plugin is given :)
declare variable $NO-OP-PLUGIN :=
  element hub:plugin {
    attribute type { "null" }
  };

(: the directory where entities live :)
declare variable $ENTITIES-DIR := "/entities/";

declare variable $PLUGIN-NS := "http://marklogic.com/data-hub/plugins/";

declare variable $TYPE-XQUERY := "xquery";

declare variable $TYPE-JAVASCRIPT := "javascript";

declare variable $TYPE-XSLT := "xslt";

declare variable $TYPE-XML := "xml";

declare variable $TYPE-JSON := "json";

(:
 : Determines the type of flow given a filename
 :
 : @param $filename - name of the module plugin file
 : @return - a type (xquery, xml, sjs, ...)
 :)
declare %private function flow:get-type($filename) as xs:string?
{
  let $ext as xs:string := hul:get-file-extension($filename)
  return
    if ($ext = hul:get-xqy-extensions()) then
      $TYPE-XQUERY
    else if ($ext = hul:get-sjs-extensions()) then
      $TYPE-JAVASCRIPT
    else if ($ext = hul:get-xslt-extensions()) then
      $TYPE-XSLT
    else if ($ext = "xml") then
      $TYPE-XML
    else if ($ext = "json") then
      $TYPE-JSON
    else
      fn:error(xs:QName("INVALID_PLUGIN"), $filename)
};

(:~
 : Returns xml describing a collector
 :)
declare %private function flow:get-collector(
  $flow-name as xs:string,
  $uris as xs:string*) as element(hub:collector)
{
  let $uri := $uris[1]
  let $filename as xs:string := hul:get-file-from-uri($uri)
  let $type := flow:get-type($filename)
  return
    element hub:collector {
      attribute type { $type },
      attribute module { $uri }
    }
};

(:~
 : Returns xml describing a plugin
 :)
declare %private function flow:get-plugin(
  $flow-name as xs:string,
  $uris as xs:string*,
  $destination as xs:string) as element(hub:plugin)*
{
  for $uri in $uris
  let $filename as xs:string := hul:get-file-from-uri($uri)
  let $type := flow:get-type($filename)
  return
    element hub:plugin {
      attribute dest { $destination },
      attribute type { $type },
      attribute module { $uri }
    }
};

(:~
 : Returns xml describing a content plugin
 :)
declare %private function flow:get-content(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "content")
  return
    if ($plugin) then $plugin
    else
      $DEFAULT-CONTENT-PLUGIN
};

(:~
 : Returns xml describing a headers plugin
 :)
declare %private function flow:get-headers(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "headers")
  return
    if ($plugin) then $plugin
    else
      $NO-OP-PLUGIN
};

(:~
 : Returns xml describing a triples plugin
 :)
declare %private function flow:get-triples(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "triples")
  return
    if ($plugin) then $plugin
    else
      $NO-OP-PLUGIN
};

(:~
 : Returns xml describing a writer
 :)
declare %private function flow:get-writer(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  if ($uris) then
    for $uri in $uris
    let $filename as xs:string := hul:get-file-from-uri($uri)
    let $type := flow:get-type($filename)
    let $_ :=
      if (debug:on()) then
        debug:log((
          "$flow-name: " || $flow-name,
          "$uri: " || $uri,
          "$filename: " || $filename,
          "$type: " || $type
        ))
      else ()
    return
      element hub:writer {
        attribute type { $type },
        attribute module { $uri }
      }
  else
    $DEFAULT-WRITER
};

(:~
 : Returns a flow by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity that owns the flow
 : @param $flow-name - name of the flow to retrieve
 : @return - xml describing the flow
 :)
declare function flow:get-flow(
  $entity-name as xs:string,
  $flow-name as xs:string,
  $flow-type as xs:string?) as element(hub:flow)
{
  let $uris :=
    hul:run-in-modules(function() {
      let $type :=
        if ($flow-type) then $flow-type
        else "*"
      return
        cts:uri-match($ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/*")
    })
  return
    flow:get-flow($entity-name, $flow-name, $flow-type, $uris)
};

(:~
 : Returns a flow by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity that owns the flow
 : @param $flow-name - name of the flow to retrieve
 : @param $uris - uris used to build the entity xml
 : @return - xml describing the flow
 :)
declare %private function flow:get-flow(
  $entity-name as xs:string,
  $flow-name as xs:string,
  $flow-type as xs:string?,
  $uris as xs:string*) as element(hub:flow)
{
  let $_ := xdmp:log(("entity: " || $entity-name, "flow: " || $flow-name, "flow-type: " || $flow-type, "uris:", $uris))
  let $real-flow-type := fn:replace($uris[1], $ENTITIES-DIR || $entity-name || "/([^/]+)/" || $flow-name || ".*$", "$1")
  let $map := map:map()
  let $_ :=
    for $dir in $uris
    let $type :=
      if ($flow-type) then $flow-type
      else "[^/]+"
    let $dir-name := fn:replace($dir, $ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/([^/]+)/$", "$1")
    let $child-uris := $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/" || $dir-name || "/([^/]+)$")]
    return
      switch ($dir-name)
        case "collector" return
          map:put($map, "collector", flow:get-collector($flow-name, $child-uris))
        case "content" return
          map:put($map, "content", flow:get-content($flow-name, $child-uris))
        case "headers" return
          map:put($map, "headers", flow:get-headers($flow-name, $child-uris))
        case "triples" return
          map:put($map, "triples", flow:get-triples($flow-name, $child-uris))
        case "writer" return
          map:put($map, "writer", flow:get-writer($flow-name, $child-uris))
        default return
          ()
  let $flow := hul:run-in-modules(function() {
    let $uri := $ENTITIES-DIR || $entity-name || "/" || $real-flow-type || "/" || $flow-name || "/" || $flow-name || ".xml"
    return
      fn:doc($uri)/hub:flow
  })
  return
    <flow xmlns="http://marklogic.com/data-hub">
      <name>{$flow-name}</name>
      <entity>{$entity-name}</entity>
      <complexity>{ ($flow/hub:complexity/fn:data(), "simple")[1] }</complexity>
      <data-format>{ $flow/hub:data-format/fn:data() }</data-format>
      <type>{$real-flow-type}</type>
      {map:get($map, "collector")}
      <plugins>
      {
        if ($flow/hub:plugins/*) then
          $flow/hub:plugins/*
        else
        (
          (map:get($map, "content"), $DEFAULT-CONTENT-PLUGIN)[1],
          (map:get($map, "headers"), $NO-OP-PLUGIN)[1],
          (map:get($map, "triples"), $NO-OP-PLUGIN)[1]
        )
      }
      </plugins>
      {
        (map:get($map, "writer"), $DEFAULT-WRITER)[1]
      }
    </flow>
};

(:~
 : Returns the flows that belong to the given entity in the database
 :
 : @param $entity-name - the name of the entity containing the flows
 : @return - xml describing the flows
 :)
declare function flow:get-flows(
  $entity-name as xs:string) as element(hub:flows)
{
  let $uris := hul:run-in-modules(function() {
    cts:uri-match($ENTITIES-DIR || "*")
  })
  let $flows :=
    for $flow in $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/(input|conformance)/[^/]+/$")]
    let $name := fn:replace($flow, $ENTITIES-DIR || $entity-name || "/(input|conformance)/([^/]+)/$", "$2")
    return
      flow:get-flow($entity-name, $name, (), $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/(input|conformance)/" || $name || "/.+")])
  return
    <flows xmlns="http://marklogic.com/data-hub">
    {
      $flows
    }
    </flows>
};

(:~
 : Returns a entity by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity to retrieve
 : @return - xml describing the entity
 :)
declare function flow:get-entity(
  $entity-name as xs:string)
{
  let $uris :=
    hul:run-in-modules(function() {
      cts:uri-match($ENTITIES-DIR || $entity-name || "/*")
    })
  return
    flow:get-entity($entity-name, $uris)
};

(:~
 : Returns a entity by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity to retrieve
 : @param $uris - uris used to build the entity xml
 : @return - xml describing the entity
 :)
declare %private function flow:get-entity(
  $entity-name as xs:string,
  $uris as xs:string*)
  as element(hub:entity)
{
  <entity xmlns="http://marklogic.com/data-hub">
    <name>{$entity-name}</name>
    {
      flow:get-flows($entity-name)
    }
  </entity>
};

(:~
 : Returns the entities in the database
 :
 : @return - xml describing the entities
 :)
declare function flow:get-entities() as element(hub:entities)
{
  let $uris := hul:run-in-modules(function() {
    cts:uri-match($ENTITIES-DIR || "*")
  })
  let $entities :=
    for $flow in $uris[fn:matches(., $ENTITIES-DIR || "[^/]+/$")]
    let $name := fn:replace($flow, $ENTITIES-DIR || "([^/]+)/$", "$1")
    return
      flow:get-entity($name, $uris[fn:matches(., $ENTITIES-DIR || $name || "/.+")])
  return
    <entities xmlns="http://marklogic.com/data-hub">
    {
      $entities
    }
    </entities>
};

(:~
 : Runs a collector
 :
 : @param $module-uri - the uri of the collector module
 : @param $options - a map of options passed in by the client
 : @return - a sequence of strings
 :)
declare function flow:run-collector(
  $module-uri as xs:string,
  $options as map:map) as xs:string*
{
  let $module-name := hul:get-module-name($module-uri)
  let $filename as xs:string := hul:get-file-from-uri($module-uri)
  let $type := flow:get-type($filename)
  let $ns :=
    if ($type eq $TYPE-JAVASCRIPT) then ()
    else
      $PLUGIN-NS || fn:lower-case($module-name)
  let $func := xdmp:function(fn:QName($ns, "collect"), $module-uri)
  return
    $func($options)
};

(:~
 : Runs a given flow
 :
 : @param $flow - xml describing the flow
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $options - a map of options passed in by the client
 : @return - nothing
 :)
declare function flow:run-flow(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $options as map:map) as empty-sequence()
{
  flow:run-flow($flow, $identifier, (), $options)
};

declare function flow:run-plugins(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $content as item()?,
  $options as map:map
)
{
  let $content :=
    map:new((
      map:entry("identifier", $identifier),
      if ($content) then
        map:entry("content", $content)
      else ()
    ))
  let $data-format := $flow/hub:data-format
  let $_ :=
    for $plugin in $flow/hub:plugins/hub:plugin
    let $destination := $plugin/@dest
    let $resp :=
      flow:run-plugin(
        $plugin,
        $data-format,
        $identifier,
        map:get($content, "content"),
        map:get($content, "headers"),
        map:get($content, "triple"),
        $options)
    return
      if (fn:empty($destination))
      then ()
      else map:put($content, $destination, $resp)
  return
    flow:make-envelope($content, $data-format)
};

declare function flow:run-flow(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $content as item()?,
  $options as map:map) as empty-sequence()
{
  let $envelope := flow:run-plugins($flow, $identifier, $content, $options)
  let $_ :=
    xdmp:invoke-function(function() {
      for $writer in $flow/hub:writer
      return
        flow:run-writer($writer, $identifier, $envelope, $options)
    },
    map:new((
      map:entry("isolation", "different-transaction"),
      map:entry("database", xdmp:database("data-hub-FINAL")),
      map:entry("transactionMode", "update-auto-commit")
    )))

  return
    ()
};

(:~
 : Construct an envelope
 :
 : @param $map - a map with all the stuff in it
 : @return - the newly constructed envelope
 :)
declare function flow:make-envelope($map as map:map, $data-format as xs:string)
{
  xdmp:log(("map:", $map)),
  if ($data-format eq "application/json") then
    xdmp:to-json($map)/node()
  else
    <envelope xmlns="http://marklogic.com/data-hub/envelope">
      <headers>{map:get($map, "headers")}</headers>
      <triples>{map:get($map, "triples")}</triples>
      <content>{map:get($map, "content")}</content>
    </envelope>
};

(:~
 : Run a given plugin
 :
 : @param $plugin - xml describing the plugin to run
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $content - the output of the content plugin
 : @param $headers - the output of the headers plugin
 : @param $triples - the output of the triples plugin
 : @param $options - a map of options passed in by the client
 : @return - the output of the plugin. It varies.
 :)
declare function flow:run-plugin(
  $plugin as element(hub:plugin),
  $data-format as xs:string,
  $identifier as xs:string,
  $content as item()?,
  $headers as item()*,
  $triples as sem:triple*,
  $options as map:map)
{
  let $module-uri := $plugin/@module
  return
    if (fn:empty($module-uri)) then ()
    else
      let $destination := $plugin/@dest
      let $module-name := hul:get-module-name($module-uri)
      let $filename as xs:string := hul:get-file-from-uri($module-uri)
      let $type := flow:get-type($filename)
      let $ns :=
        if ($type eq $TYPE-JAVASCRIPT) then ()
        else
          $PLUGIN-NS || fn:lower-case($module-name)
      let $func-name :=
        if ($type eq $TYPE-JAVASCRIPT) then
          "create" || functx:capitalize-first($destination)
        else
          "create-" || $destination
      let $func := xdmp:function(fn:QName($ns, $func-name), $module-uri)
      let $resp := $func($identifier, $content, $headers, $triples, $options)
      return
        typeswitch($resp)
          case document-node() return
            if (fn:count($resp/node()) > 1) then
              fn:error("Too Many Nodes!. Return just 1 node")
            else
              $resp/node()
          case json:array return
            if ($data-format = 'application/xml') then
              json:array-values($resp)
            else
              $resp
          default return
            $resp
};

(:~
 : Run a given writer
 :
 : @param $writer - xml describing the writer to run
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $envelope - the envelope
 : @param $options - a map of options passed in by the client
 : @return - the output of the writer. It varies.
 :)
declare function flow:run-writer(
  $writer as element(hub:writer),
  $identifier as xs:string,
  $envelope as item(),
  $options as map:map)
{
  let $module-uri as xs:string := $writer/@module
  let $module-name := hul:get-module-name($module-uri)
  let $ns := $PLUGIN-NS || fn:lower-case($module-name)
  let $func := xdmp:function(fn:QName($ns, "write"), $module-uri)
  return
    $func($identifier, $envelope, $options)
};

declare function flow:make-error-json($ex) {
  map:new((
    map:entry("msg", $ex/error:format-string/fn:data()),
    let $f := $ex/error:stack/error:frame[1]
    return
      (
        map:entry("uri", $f/error:uri/fn:data()),
        map:entry("line", $f/error:line/fn:data()),
        map:entry("column", $f/error:column/fn:data())
      )
  ))
};

declare function flow:validate-entities()
{
  let $errors := json:array()
  let $options := map:map()
  let $_ :=
    for $entity in flow:get-entities()/hub:entity
    for $flow in $entity/hub:flows/hub:flow
    let $data-format := $flow/hub:data-format
    (: validate collector :)
    let $_ :=
      let $collector := $flow/hub:collector
      return
        if ($collector) then
          try {
            flow:run-collector($collector/@module, $options)
          }
          catch($ex) {
            json:array-push($errors, flow:make-error-json($ex))
          }
        else ()
    (: validate plugins :)
    let $_ :=
      for $plugin in $flow/hub:plugins/hub:plugin
      let $destination := $plugin/@dest
      return
        try {
          flow:run-plugin(
            $plugin,
            $data-format,
            "123",
            (),
            (),
            (),
            $options)
        }
        catch($ex) {
          json:array-push($errors, flow:make-error-json($ex))
        }
    return
      ()
  return
    map:new(
      map:entry("errors", $errors)
    )
};

(:
  Copyright 2012-2016 MarkLogic Corporation

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
:)
xquery version "1.0-ml";

module namespace flow = "http://marklogic.com/data-hub/flow-lib";

import module namespace debug = "http://marklogic.com/data-hub/debug-lib"
  at "/com.marklogic.hub/lib/debug-lib.xqy";

import module namespace hul = "http://marklogic.com/data-hub/hub-utils-lib"
  at "/com.marklogic.hub/lib/hub-utils-lib.xqy";

import module namespace functx = "http://www.functx.com"
  at "/MarkLogic/functx/functx-1.0-nodoc-2007-01.xqy";

declare namespace hub = "http://marklogic.com/data-hub";

declare namespace envelope = "http://marklogic.com/data-hub/envelope";

declare option xdmp:mapping "false";

(: xml describing the default writer :)
declare variable $DEFAULT-WRITER :=
  element hub:writer {
    attribute type { "xquery" },
    attribute module { "/com.marklogic.hub/writers/default.xqy" }
  };

(: xml describing the default content plugin :)
declare variable $DEFAULT-CONTENT-PLUGIN :=
  element hub:plugin {
    attribute dest { "content" },
    attribute type { "xquery" },
    attribute module { "/com.marklogic.hub/plugins/raw.xqy" }
  };

(: xml describing a no-op plugin. used when no plugin is given :)
declare variable $NO-OP-PLUGIN :=
  element hub:plugin {
    attribute type { "null" }
  };

(: the directory where entities live :)
declare variable $ENTITIES-DIR := "/entities/";

declare variable $PLUGIN-NS := "http://marklogic.com/data-hub/plugins/";

declare variable $TYPE-XQUERY := "xquery";

declare variable $TYPE-JAVASCRIPT := "javascript";

declare variable $TYPE-XSLT := "xslt";

declare variable $TYPE-XML := "xml";

declare variable $TYPE-JSON := "json";

(:
 : Determines the type of flow given a filename
 :
 : @param $filename - name of the module plugin file
 : @return - a type (xquery, xml, sjs, ...)
 :)
declare %private function flow:get-type($filename) as xs:string?
{
  let $ext as xs:string := hul:get-file-extension($filename)
  return
    if ($ext = hul:get-xqy-extensions()) then
      $TYPE-XQUERY
    else if ($ext = hul:get-sjs-extensions()) then
      $TYPE-JAVASCRIPT
    else if ($ext = hul:get-xslt-extensions()) then
      $TYPE-XSLT
    else if ($ext = "xml") then
      $TYPE-XML
    else if ($ext = "json") then
      $TYPE-JSON
    else
      fn:error(xs:QName("INVALID_PLUGIN"), $filename)
};

(:~
 : Returns xml describing a collector
 :)
declare %private function flow:get-collector(
  $flow-name as xs:string,
  $uris as xs:string*) as element(hub:collector)
{
  let $uri := $uris[1]
  let $filename as xs:string := hul:get-file-from-uri($uri)
  let $type := flow:get-type($filename)
  return
    element hub:collector {
      attribute type { $type },
      attribute module { $uri }
    }
};

(:~
 : Returns xml describing a plugin
 :)
declare %private function flow:get-plugin(
  $flow-name as xs:string,
  $uris as xs:string*,
  $destination as xs:string) as element(hub:plugin)*
{
  for $uri in $uris
  let $filename as xs:string := hul:get-file-from-uri($uri)
  let $type := flow:get-type($filename)
  return
    element hub:plugin {
      attribute dest { $destination },
      attribute type { $type },
      attribute module { $uri }
    }
};

(:~
 : Returns xml describing a content plugin
 :)
declare %private function flow:get-content(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "content")
  return
    if ($plugin) then $plugin
    else
      $DEFAULT-CONTENT-PLUGIN
};

(:~
 : Returns xml describing a headers plugin
 :)
declare %private function flow:get-headers(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "headers")
  return
    if ($plugin) then $plugin
    else
      $NO-OP-PLUGIN
};

(:~
 : Returns xml describing a triples plugin
 :)
declare %private function flow:get-triples(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  let $plugin := flow:get-plugin($flow-name, $uris, "triples")
  return
    if ($plugin) then $plugin
    else
      $NO-OP-PLUGIN
};

(:~
 : Returns xml describing a writer
 :)
declare %private function flow:get-writer(
  $flow-name as xs:string,
  $uris as xs:string*)
{
  if ($uris) then
    for $uri in $uris
    let $filename as xs:string := hul:get-file-from-uri($uri)
    let $type := flow:get-type($filename)
    let $_ :=
      if (debug:on()) then
        debug:log((
          "$flow-name: " || $flow-name,
          "$uri: " || $uri,
          "$filename: " || $filename,
          "$type: " || $type
        ))
      else ()
    return
      element hub:writer {
        attribute type { $type },
        attribute module { $uri }
      }
  else
    $DEFAULT-WRITER
};

(:~
 : Returns a flow by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity that owns the flow
 : @param $flow-name - name of the flow to retrieve
 : @return - xml describing the flow
 :)
declare function flow:get-flow(
  $entity-name as xs:string,
  $flow-name as xs:string,
  $flow-type as xs:string?) as element(hub:flow)
{
  let $uris :=
    hul:run-in-modules(function() {
      let $type :=
        if ($flow-type) then $flow-type
        else "*"
      return
        cts:uri-match($ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/*")
    })
  return
    flow:get-flow($entity-name, $flow-name, $flow-type, $uris)
};

(:~
 : Returns a flow by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity that owns the flow
 : @param $flow-name - name of the flow to retrieve
 : @param $uris - uris used to build the entity xml
 : @return - xml describing the flow
 :)
declare %private function flow:get-flow(
  $entity-name as xs:string,
  $flow-name as xs:string,
  $flow-type as xs:string?,
  $uris as xs:string*) as element(hub:flow)
{
  let $_ := xdmp:log(("entity: " || $entity-name, "flow: " || $flow-name, "flow-type: " || $flow-type, "uris:", $uris))
  let $real-flow-type := fn:replace($uris[1], $ENTITIES-DIR || $entity-name || "/([^/]+)/" || $flow-name || ".*$", "$1")
  let $map := map:map()
  let $_ :=
    for $dir in $uris
    let $type :=
      if ($flow-type) then $flow-type
      else "[^/]+"
    let $dir-name := fn:replace($dir, $ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/([^/]+)/$", "$1")
    let $child-uris := $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/" || $type || "/" || $flow-name || "/" || $dir-name || "/([^/]+)$")]
    return
      switch ($dir-name)
        case "collector" return
          map:put($map, "collector", flow:get-collector($flow-name, $child-uris))
        case "content" return
          map:put($map, "content", flow:get-content($flow-name, $child-uris))
        case "headers" return
          map:put($map, "headers", flow:get-headers($flow-name, $child-uris))
        case "triples" return
          map:put($map, "triples", flow:get-triples($flow-name, $child-uris))
        case "writer" return
          map:put($map, "writer", flow:get-writer($flow-name, $child-uris))
        default return
          ()
  let $flow := hul:run-in-modules(function() {
    let $uri := $ENTITIES-DIR || $entity-name || "/" || $real-flow-type || "/" || $flow-name || "/" || $flow-name || ".xml"
    return
      fn:doc($uri)/hub:flow
  })
  return
    <flow xmlns="http://marklogic.com/data-hub">
      <name>{$flow-name}</name>
      <entity>{$entity-name}</entity>
      <complexity>{ ($flow/hub:complexity/fn:data(), "simple")[1] }</complexity>
      <data-format>{ $flow/hub:data-format/fn:data() }</data-format>
      <type>{$real-flow-type}</type>
      {map:get($map, "collector")}
      <plugins>
      {
        if ($flow/hub:plugins/*) then
          $flow/hub:plugins/*
        else
        (
          (map:get($map, "content"), $DEFAULT-CONTENT-PLUGIN)[1],
          (map:get($map, "headers"), $NO-OP-PLUGIN)[1],
          (map:get($map, "triples"), $NO-OP-PLUGIN)[1]
        )
      }
      </plugins>
      {
        (map:get($map, "writer"), $DEFAULT-WRITER)[1]
      }
    </flow>
};

(:~
 : Returns the flows that belong to the given entity in the database
 :
 : @param $entity-name - the name of the entity containing the flows
 : @return - xml describing the flows
 :)
declare function flow:get-flows(
  $entity-name as xs:string) as element(hub:flows)
{
  let $uris := hul:run-in-modules(function() {
    cts:uri-match($ENTITIES-DIR || "*")
  })
  let $flows :=
    for $flow in $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/(input|conformance)/[^/]+/$")]
    let $name := fn:replace($flow, $ENTITIES-DIR || $entity-name || "/(input|conformance)/([^/]+)/$", "$2")
    return
      flow:get-flow($entity-name, $name, (), $uris[fn:matches(., $ENTITIES-DIR || $entity-name || "/(input|conformance)/" || $name || "/.+")])
  return
    <flows xmlns="http://marklogic.com/data-hub">
    {
      $flows
    }
    </flows>
};

(:~
 : Returns a entity by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity to retrieve
 : @return - xml describing the entity
 :)
declare function flow:get-entity(
  $entity-name as xs:string)
{
  let $uris :=
    hul:run-in-modules(function() {
      cts:uri-match($ENTITIES-DIR || $entity-name || "/*")
    })
  return
    flow:get-entity($entity-name, $uris)
};

(:~
 : Returns a entity by name. This xml is dynamically constructed
 : by looking in the modules database.
 :
 : @param $entity-name - name of the entity to retrieve
 : @param $uris - uris used to build the entity xml
 : @return - xml describing the entity
 :)
declare %private function flow:get-entity(
  $entity-name as xs:string,
  $uris as xs:string*)
  as element(hub:entity)
{
  <entity xmlns="http://marklogic.com/data-hub">
    <name>{$entity-name}</name>
    {
      flow:get-flows($entity-name)
    }
  </entity>
};

(:~
 : Returns the entities in the database
 :
 : @return - xml describing the entities
 :)
declare function flow:get-entities() as element(hub:entities)
{
  let $uris := hul:run-in-modules(function() {
    cts:uri-match($ENTITIES-DIR || "*")
  })
  let $entities :=
    for $flow in $uris[fn:matches(., $ENTITIES-DIR || "[^/]+/$")]
    let $name := fn:replace($flow, $ENTITIES-DIR || "([^/]+)/$", "$1")
    return
      flow:get-entity($name, $uris[fn:matches(., $ENTITIES-DIR || $name || "/.+")])
  return
    <entities xmlns="http://marklogic.com/data-hub">
    {
      $entities
    }
    </entities>
};

(:~
 : Runs a collector
 :
 : @param $module-uri - the uri of the collector module
 : @param $options - a map of options passed in by the client
 : @return - a sequence of strings
 :)
declare function flow:run-collector(
  $module-uri as xs:string,
  $options as map:map) as xs:string*
{
  let $module-name := hul:get-module-name($module-uri)
  let $filename as xs:string := hul:get-file-from-uri($module-uri)
  let $type := flow:get-type($filename)
  let $ns :=
    if ($type eq $TYPE-JAVASCRIPT) then ()
    else
      $PLUGIN-NS || fn:lower-case($module-name)
  let $func := xdmp:function(fn:QName($ns, "collect"), $module-uri)
  return
    $func($options)
};

(:~
 : Runs a given flow
 :
 : @param $flow - xml describing the flow
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $options - a map of options passed in by the client
 : @return - nothing
 :)
declare function flow:run-flow(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $options as map:map) as empty-sequence()
{
  flow:run-flow($flow, $identifier, (), $options)
};

declare function flow:run-plugins(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $content as item()?,
  $options as map:map
)
{
  let $content :=
    map:new((
      map:entry("identifier", $identifier),
      if ($content) then
        map:entry("content", $content)
      else ()
    ))
  let $data-format := $flow/hub:data-format
  let $_ :=
    for $plugin in $flow/hub:plugins/hub:plugin
    let $destination := $plugin/@dest
    let $resp :=
      flow:run-plugin(
        $plugin,
        $data-format,
        $identifier,
        map:get($content, "content"),
        map:get($content, "headers"),
        map:get($content, "triple"),
        $options)
    return
      if (fn:empty($destination))
      then ()
      else map:put($content, $destination, $resp)
  return
    flow:make-envelope($content, $data-format)
};

declare function flow:run-flow(
  $flow as element(hub:flow),
  $identifier as xs:string,
  $content as item()?,
  $options as map:map) as empty-sequence()
{
  let $envelope := flow:run-plugins($flow, $identifier, $content, $options)
  let $_ :=
    xdmp:invoke-function(function() {
      for $writer in $flow/hub:writer
      return
        flow:run-writer($writer, $identifier, $envelope, $options)
    },
    map:new((
      map:entry("isolation", "different-transaction"),
      map:entry("database", xdmp:database("data-hub-FINAL")),
      map:entry("transactionMode", "update-auto-commit")
    )))

  return
    ()
};

(:~
 : Construct an envelope
 :
 : @param $map - a map with all the stuff in it
 : @return - the newly constructed envelope
 :)
declare function flow:make-envelope($map as map:map, $data-format as xs:string)
{
  xdmp:log(("map:", $map)),
  if ($data-format eq "application/json") then
    xdmp:to-json($map)/node()
  else
    <envelope xmlns="http://marklogic.com/data-hub/envelope">
      <headers>{map:get($map, "headers")}</headers>
      <triples>{map:get($map, "triples")}</triples>
      <content>{map:get($map, "content")}</content>
    </envelope>
};

(:~
 : Run a given plugin
 :
 : @param $plugin - xml describing the plugin to run
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $content - the output of the content plugin
 : @param $headers - the output of the headers plugin
 : @param $triples - the output of the triples plugin
 : @param $options - a map of options passed in by the client
 : @return - the output of the plugin. It varies.
 :)
declare function flow:run-plugin(
  $plugin as element(hub:plugin),
  $data-format as xs:string,
  $identifier as xs:string,
  $content as item()?,
  $headers as item()*,
  $triples as sem:triple*,
  $options as map:map)
{
  let $module-uri := $plugin/@module
  return
    if (fn:empty($module-uri)) then ()
    else
      let $destination := $plugin/@dest
      let $module-name := hul:get-module-name($module-uri)
      let $filename as xs:string := hul:get-file-from-uri($module-uri)
      let $type := flow:get-type($filename)
      let $ns :=
        if ($type eq $TYPE-JAVASCRIPT) then ()
        else
          $PLUGIN-NS || fn:lower-case($module-name)
      let $func-name :=
        if ($type eq $TYPE-JAVASCRIPT) then
          "create" || functx:capitalize-first($destination)
        else
          "create-" || $destination
      let $func := xdmp:function(fn:QName($ns, $func-name), $module-uri)
      let $resp := $func($identifier, $content, $headers, $triples, $options)
      return
        typeswitch($resp)
          case document-node() return
            if (fn:count($resp/node()) > 1) then
              fn:error("Too Many Nodes!. Return just 1 node")
            else
              $resp/node()
          case json:array return
            if ($data-format = 'application/xml') then
              json:array-values($resp)
            else
              $resp
          default return
            $resp
};

(:~
 : Run a given writer
 :
 : @param $writer - xml describing the writer to run
 : @param $idenifier - the identifier to send to the flow steps (URI in corb lingo)
 : @param $envelope - the envelope
 : @param $options - a map of options passed in by the client
 : @return - the output of the writer. It varies.
 :)
declare function flow:run-writer(
  $writer as element(hub:writer),
  $identifier as xs:string,
  $envelope as item(),
  $options as map:map)
{
  let $module-uri as xs:string := $writer/@module
  let $module-name := hul:get-module-name($module-uri)
  let $ns := $PLUGIN-NS || fn:lower-case($module-name)
  let $func := xdmp:function(fn:QName($ns, "write"), $module-uri)
  return
    $func($identifier, $envelope, $options)
};

declare function flow:make-error-json($ex) {
  map:new((
    map:entry("msg", $ex/error:format-string/fn:data()),
    let $f := $ex/error:stack/error:frame[1]
    return
      (
        map:entry("uri", $f/error:uri/fn:data()),
        map:entry("line", $f/error:line/fn:data()),
        map:entry("column", $f/error:column/fn:data())
      )
  ))
};

declare function flow:validate-entities()
{
  let $errors := json:array()
  let $identifier := "123"
  let $content :=
    map:new((
      map:entry("identifier", $identifier),
      map:entry("content", <x/>)
    ))
  let $options := map:map()
  let $_ :=
    for $entity in flow:get-entities()/hub:entity
    for $flow in $entity/hub:flows/hub:flow
    let $data-format := $flow/hub:data-format
    (: validate collector :)
    let $_ :=
      let $collector := $flow/hub:collector
      return
        if ($collector) then
          try {
            flow:run-collector($collector/@module, $options)
          }
          catch($ex) {
            json:array-push($errors, flow:make-error-json($ex))
          }
        else ()
    (: validate plugins :)
    let $_ :=
      for $plugin in $flow/hub:plugins/hub:plugin
      let $destination := $plugin/@dest
      return
        try {
          flow:run-plugin(
            $plugin,
            $data-format,
            $identifier,
            map:get($content, "content"),
            map:get($content, "headers"),
            map:get($content, "triple"),
            $options)
        }
        catch($ex) {
          json:array-push($errors, flow:make-error-json($ex))
        }
    return
      ()
  return
    map:new(
      map:entry("errors", $errors)
    )
};


Keep lookup search box near lookup search button

xquery version "1.0" encoding "utf-8";

module namespace calli = "http://callimachusproject.org/rdf/2009/framework#";

declare copy-namespaces preserve, inherit;
declare default element namespace "http://www.w3.org/1999/xhtml";

declare variable $calli:realm external;

(: template nodes :)
declare variable $calli:html-element := /html;

declare function calli:head-nodes() as node()* {
    $calli:html-element/head/node()
};
declare function calli:body-attributes() as attribute(*)* {
    $calli:html-element/body/@*
};
declare function calli:body-nodes() as node()* {
    $calli:html-element/body/node()
};
declare function calli:head-links($a as element(), $divider as element()) as element()* {
    let $links := $calli:html-element/head/link[@title and @href]
    return if ($links) then
        (
            for $link in $links
            return calli:add-href($a, $link, $link/@title),
            $divider
        )
    else
        $links
};
declare function calli:add-href($a as element(), $link as element(), $label as xs:string) {
    if (local-name($a)='a') then
        element {node-name($a)} {
            $a/@*[name()!='class'],
            for $attr in $link/@*[name()!='id']
            return if ($a/@*[name()=name($attr)]) then ()
            else $attr,
            if ($a/@class and $link/@class) then attribute class {concat($a/@class,' ',$link/@class)}
            else if ($a/@class) then $a/@class
            else (),
            $label
        }
    else if ($a/self::*) then
        element {node-name($a)} {
            $a/@*,
            for $node in $a/node()
            return calli:add-href($node, $link, $label)
        }
    else
        $a

};

(: static markup functions :)
declare function calli:styles-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {resolve-uri('../styles/callimachus.less?less')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:scripts-src($script as element()) as element() {
    element {node-name($script)} {
        attribute src {resolve-uri('../../scripts.js')},
        $script/@*[name()!='src'],
        $script/node()
    }
};
declare function calli:lookup-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {concat($calli:realm, '?q')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:lookup-form($placeholder as xs:string) as element(form) {
    <form class="navbar-form" role="search" method="GET" action="{$calli:realm}">

            <input type="text" name="q" class="form-control pull-right" placeholder="{$placeholder}" />

                <button class="btn btn-default" type="submit">

                    Search
                </button>

    </form>
};
declare function calli:callimachus-about-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://callimachusproject.org/'},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-getting-started-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../../getting-started-with-callimachus')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-feedback-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://groups.google.com/group/callimachus-discuss'},
        $a/@*[name()!='href'],
        $a/node()
    }
};

declare function calli:breadcrumb-links($breadcrumb as element(), $divider as item(), $active as element()) as element(nav) {
    {$breadcrumb}{$divider}{$active}
};
declare function calli:breadcrumb-links($breadcrumb as item()*, $active as element()) as element(nav) {
    {$breadcrumb}{$active}
};
declare function calli:activate-nav($nav as node()*) as element(nav) {
    {$nav}
};
declare function calli:lastmod-time($time as element()) as element(div) {

{$time}

};
declare function calli:error-alert($div as element()) as element(div) {

{$div}

};
declare function calli:generator-p($p as element()) as element() {
    element { node-name($p) } {
        $p/@*,
        $p/node(),

    }
};

(: navigation links :)
declare function calli:home-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:folder-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:changes-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?changes')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:view-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?view"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:edit-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?edit"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:discussion-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?discussion"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:describe-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?describe"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:history-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?history"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:whatlinkshere-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?whatlinkshere"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:relatedchanges-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?relatedchanges"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:permissions-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?permissions"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:introspect-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?introspect"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:login-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?login')},
        attribute id {"login-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};
declare function calli:profile-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?profile')},
        attribute id {"profile-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};
declare function calli:logout-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?logout')},
        attribute id {"logout-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};

(: deprecated since 1.3 :)
declare function calli:body-sidebar($div as element()) as element()? {
    ()
};
declare function calli:body-hgroup() as element()? {
    ()
};

(: deprecated since 1.2 :)
declare function calli:breadcrumb-nav($breadcrumb as element()) as element(nav) {
    {$breadcrumb}
};

(: deprecated since 1.0.1 :)
declare function calli:styles() as element() {calli:styles-href(<link rel="stylesheet" />)};
declare function calli:scripts() as element() {calli:scripts-src(

xquery version "1.0" encoding "utf-8";

module namespace calli = "http://callimachusproject.org/rdf/2009/framework#";

declare copy-namespaces preserve, inherit;
declare default element namespace "http://www.w3.org/1999/xhtml";

declare variable $calli:realm external;

(: template nodes :)
declare variable $calli:html-element := /html;

declare function calli:head-nodes() as node()* {
    $calli:html-element/head/node()
};
declare function calli:body-attributes() as attribute(*)* {
    $calli:html-element/body/@*
};
declare function calli:body-nodes() as node()* {
    $calli:html-element/body/node()
};
declare function calli:head-links($a as element(), $divider as element()) as element()* {
    let $links := $calli:html-element/head/link[@title and @href]
    return if ($links) then
        (
            for $link in $links
            return calli:add-href($a, $link, $link/@title),
            $divider
        )
    else
        $links
};
declare function calli:add-href($a as element(), $link as element(), $label as xs:string) {
    if (local-name($a)='a') then
        element {node-name($a)} {
            $a/@*[name()!='class'],
            for $attr in $link/@*[name()!='id']
            return if ($a/@*[name()=name($attr)]) then ()
            else $attr,
            if ($a/@class and $link/@class) then attribute class {concat($a/@class,' ',$link/@class)}
            else if ($a/@class) then $a/@class
            else (),
            $label
        }
    else if ($a/self::*) then
        element {node-name($a)} {
            $a/@*,
            for $node in $a/node()
            return calli:add-href($node, $link, $label)
        }
    else
        $a

};

(: static markup functions :)
declare function calli:styles-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {resolve-uri('../styles/callimachus.less?less')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:scripts-src($script as element()) as element() {
    element {node-name($script)} {
        attribute src {resolve-uri('../../scripts.js')},
        $script/@*[name()!='src'],
        $script/node()
    }
};
declare function calli:lookup-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {concat($calli:realm, '?q')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:lookup-form($placeholder as xs:string) as element(form) {
    <form class="navbar-form" role="search" method="GET" action="{$calli:realm}">

            <input type="text" name="q" class="form-control" placeholder="{$placeholder}" />

                <button class="btn btn-default" type="submit">

                    Search
                </button>

    </form>
};
declare function calli:callimachus-about-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://callimachusproject.org/'},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-getting-started-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../../getting-started-with-callimachus')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-feedback-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://groups.google.com/group/callimachus-discuss'},
        $a/@*[name()!='href'],
        $a/node()
    }
};

declare function calli:breadcrumb-links($breadcrumb as element(), $divider as item(), $active as element()) as element(nav) {
    {$breadcrumb}{$divider}{$active}
};
declare function calli:breadcrumb-links($breadcrumb as item()*, $active as element()) as element(nav) {
    {$breadcrumb}{$active}
};
declare function calli:activate-nav($nav as node()*) as element(nav) {
    {$nav}
};
declare function calli:lastmod-time($time as element()) as element(div) {

{$time}

};
declare function calli:error-alert($div as element()) as element(div) {

{$div}

};
declare function calli:generator-p($p as element()) as element() {
    element { node-name($p) } {
        $p/@*,
        $p/node(),

    }
};

(: navigation links :)
declare function calli:home-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:folder-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:changes-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?changes')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:view-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?view"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:edit-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?edit"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:discussion-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?discussion"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:describe-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?describe"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:history-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?history"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:whatlinkshere-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?whatlinkshere"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:relatedchanges-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?relatedchanges"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:permissions-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?permissions"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:introspect-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?introspect"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:login-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?login')},
        attribute id {"login-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};
declare function calli:profile-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?profile')},
        attribute id {"profile-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};
declare function calli:logout-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?logout')},
        attribute id {"logout-link"},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};

(: deprecated since 1.3 :)
declare function calli:body-sidebar($div as element()) as element()? {
    ()
};
declare function calli:body-hgroup() as element()? {
    ()
};

(: deprecated since 1.2 :)
declare function calli:breadcrumb-nav($breadcrumb as element()) as element(nav) {
    {$breadcrumb}
};

(: deprecated since 1.0.1 :)
declare function calli:styles() as element() {calli:styles-href(<link rel="stylesheet" />)};
declare function calli:scripts() as element() {calli:scripts-src(


Fixed subtopics not having authors.

Fixed subtopics not having authors.

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

declare namespace atom="http://www.w3.org/2005/Atom";
<feed xmlns="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']],
     "
",
     /atom:feed/atom:link
   }
   {
      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 ($feed and 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,
                                "
",
                                $feed/atom:author,
                                "
",
                                <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,
                                "
",
                                $i/atom:author,
                                "
",
                                <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>

declare namespace atom="http://www.w3.org/2005/Atom";
<feed xmlns="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']],
     "
",
     /atom:feed/atom:link
   }
   {
      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 ($feed and 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,
                                "
",
                                $feed/atom:author,
                                "
",
                                <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>


[MOD] Fix URL to websockets wiki

[MOD] Fix URL to websockets wiki

(:~
 : This module contains some basic examples for RESTXQ annotations.
 : @author BaseX Team
 :)
module namespace page = 'http://basex.org/modules/web-page';

(:~
 : Generates a welcome page.
 : @return HTML page
 :)
declare
  %rest:path("")
  %output:method("xhtml")
  %output:omit-xml-declaration("no")
  %output:doctype-public("-//W3C//DTD XHTML 1.0 Transitional//EN")
  %output:doctype-system("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")
function page:start(
) as element(Q{http://www.w3.org/1999/xhtml}html) {

      <title>BaseX HTTP Services</title>
      <link rel="stylesheet" type="text/css" href="static/style.css"/>

BaseX HTTP Services

Welcome to the BaseX HTTP Services. They allow you to:

create web applications and services with
          RESTXQ,

use full-duplex communication with
          WebSockets,

query and modify databases via REST
          (try here), and

browse and update resources via
          WebDAV.

Find more information on the
        Web Application
        page in our documentation.

The following sample applications give you a glimpse of how applications
        can be written with BaseX:

DBA: Database Administration

The Database Administration interface is completely
        written in RESTXQ.

        The source code helps to understand how complex
        web applications can be built with XQuery.

WebSocket Chat

The chat application demonstrates how bidirectional communication
        is realized with BaseX.

        For a better experience when testing the chat,
        consider the following steps:

 Create different database users first (e.g. via the DBA).

 Open two different browsers and log in with different users.

};


try to make the merge adapter work with both GET and POST

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

import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_mcs = "https://github.com/openhie/openinfoman/csd_mcs";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";

declare   namespace   csd = "urn:ihe:iti:csd:2013";

declare function page:is_merge($search_name) {
  let $ufunction := csr_proc:get_updating_function_definition($search_name)
  let $ext := $ufunction//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter' and @type='merge']
  return (count($ext) > 0)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/merge")
  %output:method("xhtml")
  %rest:GET
  function page:show_endpoints($search_name,$doc_name)
{
    if (not(page:is_merge($search_name)) )
      then concat('Not a stored function for a merge: ' , $search_name    )
    else
      let $action := csd_webui:generateURL(("/CSD/csr",$doc_name,"careServicesRequest",$search_name, "adapter/merge"))
      let $ufunction := csr_proc:get_updating_function_definition($search_name)
      let $contents :=

Merge into {$doc_name}

Merge Cached Service Directoriesn

{$ufunction/csd:description}

	      <form method='POST' action="{$action}">
		{
		  let $docs := csd_dm:registered_documents()
		  return

		    {
		      for $doc in $docs
		      where not($doc = $doc_name)
		      return (<input type='checkbox'  name="merge" value="{$doc}">{$doc}</input>,
)
		    }

		    <input type='submit' value='Merge'/>

		}
	      </form>

      return csd_webui:wrapper($contents)
};

declare updating
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/merge")
(:  %output:method("xhtml") :)
  %rest:query-param("merge", "{$merge}")
  function page:perform_merge($search_name,$doc_name,$merge)
{
  let $doc :=  csd_dm:open_document($doc_name)
  let $function := csr_proc:get_function_definition($search_name)
  let $action := concat("/CSD/csr/",$doc_name,"/careServicesRequest/",$search_name, "/adapter/merge")
  let $requestParams :=
    <csd:requestParams function="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
      <documents >
	{
          for $name in $merge
	  where not ($name = $doc_name)
	  return  <document resource="{$name}"/>
	}
      </documents>
    </csd:requestParams >

    return
      (
	csr_proc:process_updating_CSR_stored_results( $doc,$requestParams)
	,
	() (: csd_webui:redirect_out($action)  :)
      )
};

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

import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_mcs = "https://github.com/openhie/openinfoman/csd_mcs";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";

declare   namespace   csd = "urn:ihe:iti:csd:2013";

declare function page:is_merge($search_name) {
  let $ufunction := csr_proc:get_updating_function_definition($search_name)
  let $ext := $ufunction//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter' and @type='merge']
  return (count($ext) > 0)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/merge")
  %output:method("xhtml")
  %rest:GET
  function page:show_endpoints($search_name,$doc_name)
{
    if (not(page:is_merge($search_name)) )
      then concat('Not a stored function for a merge: ' , $search_name    )
    else
      let $action := csd_webui:generateURL(("/CSD/csr",$doc_name,"careServicesRequest",$search_name, "adapter/merge"))
      let $ufunction := csr_proc:get_updating_function_definition($search_name)
      let $contents :=

Merge into {$doc_name}

Merge Cached Service Directoriesn

{$ufunction/csd:description}

	      <form method='POST' action="{$action}">
		{
		  let $docs := csd_dm:registered_documents()
		  return

		    {
		      for $doc in $docs
		      where not($doc = $doc_name)
		      return (<input type='checkbox'  name="merge" value="{$doc}">{$doc}</input>,
)
		    }

		    <input type='submit' value='Merge'/>

		}
	      </form>

      return csd_webui:wrapper($contents)
};

declare updating
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/merge")
(:  %output:method("xhtml") :)
  %rest:query-param("merge", "{$merge}")
  %rest:POST
  function page:perform_merge($search_name,$doc_name,$merge)
{
  let $doc :=  csd_dm:open_document($doc_name)
  let $function := csr_proc:get_function_definition($search_name)
  let $action := concat("/CSD/csr/",$doc_name,"/careServicesRequest/",$search_name, "/adapter/merge")
  let $requestParams :=
    <csd:requestParams function="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
      <documents >
	{
          for $name in $merge
	  where not ($name = $doc_name)
	  return  <document resource="{$name}"/>
	}
      </documents>
    </csd:requestParams >

    return
      (
	csr_proc:process_updating_CSR_stored_results( $doc,$requestParams)
	,
	() (: csd_webui:redirect_out($action)  :)
      )
};