[biblio app] minor changes. save.xq checks if element exists before insterting input before element. body files have block-form applied. new-instance follows tab order of top level elements. Revisions to body files, mainly 01 to 03 and 16 to 18.

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

xquery version "1.0";

(: XQuery script to save a new MODS record from an incoming HTTP POST :)

import module namespace style = "http://exist-db.org/mods-style" at "../../../modules/style.xqm";

declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace xforms="http://www.w3.org/2002/xforms";
declare namespace ev="http://www.w3.org/2001/xml-events";
declare namespace mods="http://www.loc.gov/mods/v3";

let $title := 'MODS Record Save'

(: this service takes an incoming POST and saves the appropriate records :)
(: note that in this version, the incoming @ID is required :)
(: the user must have write and update access to the data collection :)

let $app-collection := $style:db-path-to-app
let $data-collection := $style:db-path-to-app-data

(: this is where the form "POSTS" documents to this XQuery using the POST method of a submission :)
let $item := request:get-data()

(: check to see if we have an indentifier in the incoming post :)
let $incoming-id := $item/@ID

(: if we do not have an ID then throw an error :)
return
if ( string-length($incoming-id) = 0 )
   then
        <error>
          <message class="warning">ERROR! Attempted to save a record with no ID specified.</message>
        </error>
   else

(: else we are doing an update to an existing file :)

let $file-to-update := concat($incoming-id, '.xml')
let $file-path := concat($data-collection, '/', $file-to-update)

(: uncomment the following line in for testing if you have not run the security setup tools :)
let $login := xmldb:login($style:db-path-to-app-data, 'admin', 'admin123')

(: this is the document on disk to be updated :)
let $doc := doc($file-path)/mods:mods

(: If the incoming has any part then we update it in the document

Note that is has the side effect of adding the mods prefix in the data files.  Semantically this
means the same thing but I don't know of a way to tell eXist to always use a default namespace
when doing an update.  :)

(: TODO figure out some way to pass the element name to an XQuery function and then do an eval on the update :)

(: This checks to see if we have a titleInfo in the saved document.
If we do then it first deletes the titleInfo in the saved document.
Next it goes through each titleInfo in the incoming record and inserts it in the saved document.
If name (the "next" element in the canonical order) occurs in the saved document, the titleInfo is inserted before name, maintaining order in the document.
If name does not occur, titleInfo is inserted at the end of the saved document.:)

let $titleInfo :=
   if ($item/mods:titleInfo)
     then
        (
        update delete $doc/mods:titleInfo,
            if ($doc/mods:name)
            then
                update insert $item/mods:titleInfo preceding $doc/mods:name
            else
                update insert $item/mods:titleInfo into $doc
         )
   else ()

let $name :=
   if ($item/mods:name)
      then
        (
        update delete $doc/mods:name,
              if ($doc/mods:originInfo)
              then
                 update insert $item/mods:name preceding $doc/mods:originInfo
              else
                 update insert $item/mods:name into $doc
         )
      else ()

let $originInfo :=
   if ($item/mods:originInfo)
      then
        (
        update delete $doc/mods:originInfo,
              if ($doc/mods:part)
              then
                 update insert $item/mods:originInfo preceding $doc/mods:part
              else
                 update insert $item/mods:originInfo into $doc
         )
      else ()

let $part :=
   if ($item/mods:part)
      then
        (
        update delete $doc/mods:part,
              if ($doc/mods:physicalDescription)
              then
                 update insert $item/mods:part preceding $doc/mods:physicalDescription
              else
                 update insert $item/mods:part into $doc
         )
      else ()

let $physicalDescription :=
   if ($item/mods:physicalDescription)
      then
        (
        update delete $doc/mods:physicalDescription,
              if ($doc/mods:targetAudience)
              then
                 update insert $item/mods:physicalDescription preceding $doc/mods:targetAudience
              else
                 update insert $item/mods:physicalDescription into $doc
         )
      else ()

let $targetAudience :=
   if ($item/mods:targetAudience)
      then
        (
        update delete $doc/mods:targetAudience,
              if ($doc/mods:language)
              then
                 update insert $item/mods:targetAudience preceding $doc/mods:language
              else
                 update insert $item/mods:targetAudience into $doc
         )
      else ()

let $language :=
   if ($item/mods:language)
      then
        (
        update delete $doc/mods:language,
              if ($doc/mods:typeOfResource)
              then
                 update insert $item/mods:language preceding $doc/mods:typeOfResource
              else
                 update insert $item/mods:language into $doc
         )
      else ()

let $typeOfResource :=
   if ($item/mods:typeOfResource)
      then
        (
        update delete $doc/mods:typeOfResource,
              if ($doc/mods:genre)
              then
                 update insert $item/mods:typeOfResource preceding $doc/mods:genre
              else
                 update insert $item/mods:typeOfResource into $doc
         )
      else ()

let $genre :=
   if ($item/mods:genre)
      then
        (
        update delete $doc/mods:genre,
              if ($doc/mods:subject)
              then
                 update insert $item/mods:genre preceding $doc/mods:subject
              else
                 update insert $item/mods:genre into $doc
         )
      else ()

let $subject :=
   if ($item/mods:subject)
      then
        (
        update delete $doc/mods:subject,
              if ($doc/mods:classification)
              then
                 update insert $item/mods:subject preceding $doc/mods:classification
              else
                 update insert $item/mods:subject into $doc
         )
      else ()

let $classification :=
   if ($item/mods:classification)
      then
        (
        update delete $doc/mods:classification,
              if ($doc/mods:abstract)
              then
                 update insert $item/mods:classification preceding $doc/mods:abstract
              else
                 update insert $item/mods:classification into $doc
         )
      else ()

let $abstract :=
   if ($item/mods:abstract)
      then
        (
        update delete $doc/mods:abstract,
              if ($doc/mods:tableOfContents)
              then
                 update insert $item/mods:abstract preceding $doc/mods:tableOfContents
              else
                 update insert $item/mods:abstract into $doc
         )
      else ()

let $tableOfContents :=
   if ($item/mods:tableOfContents)
      then
        (
        update delete $doc/mods:tableOfContents,
              if ($doc/mods:note)
              then
                 update insert $item/mods:tableOfContents preceding $doc/mods:note
              else
                 update insert $item/mods:tableOfContents into $doc
         )
      else ()

let $note :=
   if ($item/mods:note)
      then
        (
        update delete $doc/mods:note,
              if ($doc/mods:relatedItem)
              then
                 update insert $item/mods:note preceding $doc/mods:relatedItem
              else
                 update insert $item/mods:note into $doc
         )
      else ()

let $relatedItem :=
   if ($item/mods:relatedItem)
      then
        (
        update delete $doc/mods:relatedItem,
              if ($doc/mods:identifier)
              then
                 update insert $item/mods:relatedItem preceding $doc/mods:identifier
              else
                 update insert $item/mods:relatedItem into $doc
         )
      else ()

let $identifier :=
   if ($item/mods:identifier)
      then
        (
        update delete $doc/mods:identifier,
              if ($doc/mods:recordInfo)
              then
                 update insert $item/mods:identifier preceding $doc/mods:recordInfo
              else
                 update insert $item/mods:identifier into $doc
         )
      else ()

let $recordInfo :=
   if ($item/mods:recordInfo)
      then
        (
        update delete $doc/mods:recordInfo,
              if ($doc/mods:accessCondition)
              then
                 update insert $item/mods:recordInfo preceding $doc/mods:location
              else
                 update insert $item/mods:recordInfo into $doc
         )
      else ()

let $location :=
   if ($item/mods:location)
      then
        (
        update delete $doc/mods:location,
              if ($doc/mods:location)
              then
                 update insert $item/mods:location preceding $doc/mods:accessCondition
              else
                 update insert $item/mods:location into $doc
         )
      else ()

let $accessCondition :=
   if ($item/mods:accessCondition)
      then
        (
        update delete $doc/mods:accessCondition,
                 update insert $item/mods:accessCondition into $doc
         )
      else ()

return
<results>
  <message>Update Status = OK titles = {count($item/mods:titleInfo)}</message>
</results>

xquery version "1.0";

(: XQuery script to save a new MODS record from an incomming HTTP POST :)

import module namespace style = "http://exist-db.org/mods-style" at "../../../modules/style.xqm";

declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace xforms="http://www.w3.org/2002/xforms";
declare namespace ev="http://www.w3.org/2001/xml-events";
declare namespace mods="http://www.loc.gov/mods/v3";

let $title := 'MODS Record Save'

(: this service takes an incomming POST and saves the appropriate records :)
(: note that in this version, the incomming @ID is required :)
(: the user must have write and update access to the data collection :)

let $app-collection := $style:db-path-to-app
let $data-collection := $style:db-path-to-app-data

(: this is where the form "POSTS" documents to this XQuery using the POST method of a submission :)
let $item := request:get-data()

(: check to see if we have an indentifier in the incomming post :)
let $incomming-id := $item/@ID

(: if we do not have an ID then throw an error :)
return
if ( string-length($incomming-id) = 0 )
   then
        <error>
          <message class="warning">ERROR! Attempted to save a record with no ID specified.</message>
        </error>
   else

(: else we are doing an update to an existing file :)

let $file-to-update := concat($incomming-id, '.xml')
let $file-path := concat($data-collection, '/', $file-to-update)

(: uncomment the following line in for testing if you have not run the security setup tools :)
let $login := xmldb:login($style:db-path-to-app-data, 'admin', 'admin123')

(: this is the document on disk to be updated :)
let $doc := doc($file-path)/mods:mods

(: If the incoming has any part then we update it in the document

Note that is has the side effect of adding the mods prefix in the data files.  Semantically this
means the same thing but I don't know of a way to tell eXist to always use a default namespace
when doing an update.  :)

(: TODO figure out some way to pass the element name to an XQuery function and then do an eval on the update :)

(: this checks to see if we have a titleInfo in the save.  If we do then it goes through each one and
   it that is in the data it does a replace, else it does an insert. :)

let $titleInfo :=
   (: test to see if the incomming item has a title :)
   if ($item/mods:titleInfo)
     then
        (
            (: first delete all current on-disk titles :)
            update delete $doc/mods:titleInfo,

            (: now we insert all the net titles :)
            for $new-title-info at $count in $item/mods:titleInfo
               return
                  (: if we have an existing title then we just append after the previous, else we place it before the next item :)
                  if ($doc/mods:titleInfo)
                  then
                     update insert $new-title-info following $doc/mods:titleInfo[$count - 1]
                  else
                     update insert $new-title-info preceding $doc/mods:name
         )
   else ()

let $name :=
   if ($item/mods:name)
      then
        (
        update delete $doc/mods:name,
        for $new-name-info at $count in $item/mods:name
           return
              if ($doc/mods:name)
              then
                 update insert $new-name-info following $doc/mods:name[$count - 1]
              else
                 update insert $new-name-info preceding $doc/mods:originInfo
         )
      else ()

let $originInfo :=
   if ($item/mods:originInfo)
      then
        (
        update delete $doc/mods:originInfo,
        for $new-item at $count in $item/mods:originInfo
           return
              if ($doc/mods:originInfo)
              then
                 update insert $new-item following $doc/mods:originInfo[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:physicalDescription
         )
      else ()

let $physicalDescription :=
   if ($item/mods:physicalDescription)
      then
        (
        update delete $doc/mods:physicalDescription,
        for $new-item at $count in $item/mods:physicalDescription
           return
              if ($doc/mods:physicalDescription)
              then
                 update insert $new-item following $doc/mods:physicalDescription[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:targetAudience
         )
      else ()

let $targetAudience :=
   if ($item/mods:targetAudience)
      then
        (
        update delete $doc/mods:targetAudience,
        for $new-item at $count in $item/mods:targetAudience
           return
              if ($doc/mods:targetAudience)
              then
                 update insert $new-item following $doc/mods:targetAudience[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:language
         )
      else ()

let $language :=
   if ($item/mods:language)
      then
        (
        update delete $doc/mods:language,
        for $new-item at $count in $item/mods:language
           return
              if ($doc/mods:language)
              then
                 update insert $new-item following $doc/mods:language[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:typeOfResource
         )
      else ()

let $typeOfResource :=
   if ($item/mods:typeOfResource)
      then
        (
        update delete $doc/mods:typeOfResource,
        for $new-item at $count in $item/mods:typeOfResource
           return
              if ($doc/mods:typeOfResource)
              then
                 update insert $new-item following $doc/mods:typeOfResource[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:genre
         )
      else ()

let $genre :=
   if ($item/mods:genre)
      then
        (
        update delete $doc/mods:genre,
        for $new-item at $count in $item/mods:genre
           return
              if ($doc/mods:genre)
              then
                 update insert $new-item following $doc/mods:genre[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:subject
         )
      else ()

let $subject :=
   if ($item/mods:subject)
      then
        (
        update delete $doc/mods:subject,
        for $new-item at $count in $item/mods:subject
           return
              if ($doc/mods:subject)
              then
                 update insert $new-item following $doc/mods:subject[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:classification
         )
      else ()

let $classification :=
   if ($item/mods:classification)
      then
        (
        update delete $doc/mods:classification,
        for $new-item at $count in $item/mods:classification
           return
              if ($doc/mods:classification)
              then
                 update insert $new-item following $doc/mods:classification[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:abstract
         )
      else ()

let $abstract :=
   if ($item/mods:abstract)
      then
        (
        update delete $doc/mods:abstract,
        for $new-item at $count in $item/mods:abstract
           return
              if ($doc/mods:abstract)
              then
                 update insert $new-item following $doc/mods:abstract[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:table-of-contents
         )
      else ()

let $table-of-contents :=
   if ($item/mods:table-of-contents)
      then
        (
        update delete $doc/mods:table-of-contents,
        for $new-item at $count in $item/mods:table-of-contents
           return
              if ($doc/mods:table-of-contents)
              then
                 update insert $new-item following $doc/mods:table-of-contents[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:note
         )
      else ()

let $note :=
   if ($item/mods:note)
      then
        (
        update delete $doc/mods:note,
        for $new-item at $count in $item/mods:note
           return
              if ($doc/mods:note)
              then
                 update insert $new-item following $doc/mods:note[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:related
         )
      else ()

let $related :=
   if ($item/mods:related)
      then
        (
        update delete $doc/mods:related,
        for $new-item at $count in $item/mods:related
           return
              if ($doc/mods:related)
              then
                 update insert $new-item following $doc/mods:related[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:identifier
         )
      else ()

let $identifier :=
   if ($item/mods:identifier)
      then
        (
        update delete $doc/mods:identifier,
        for $new-item at $count in $item/mods:identifier
           return
              if ($doc/mods:identifier)
              then
                 update insert $new-item following $doc/mods:identifier[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:record-info
         )
      else ()

let $record-info :=
   if ($item/mods:record-info)
      then
        (
        update delete $doc/mods:record-info,
        for $new-item at $count in $item/mods:record-info
           return
              if ($doc/mods:record-info)
              then
                 update insert $new-item following $doc/mods:record-info[$count - 1]
              else
                 update insert $new-item preceding $doc/mods:access-condition
         )
      else ()

let $access-condition :=
   if ($item/mods:access-condition)
      then
        (
        update delete $doc/mods:access-condition,
        for $new-item at $count in $item/mods:access-condition
           return
              if ($doc/mods:access-condition)
              then
                 update insert $new-item following $doc/mods:access-condition[$count - 1]
              else
                 (: update it into the very end of the document :)
                 update insert $new-item into $doc
         )
      else ()

return
<results>
  <message>Update Status = OK titles = {count($item/mods:titleInfo)}</message>
</results>


[ignore] Reformatted code

[ignore] Reformatted code

xquery version "3.0";

module namespace excepttest="http://exist-db.org/xquery/test/except";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
declare namespace tei="http://www.tei-c.org/ns/1.0";

declare variable $excepttest:DATA :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0" xml:id="sha-mac">
        <text>

                    Act 1

        </text>
    </TEI>;

declare variable $excepttest:DATA2 :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0" xml:id="sha-mac">
        <text>

                    Act 12

        </text>
    </TEI>;

declare variable $excepttest:COLLECTION_NAME := "/exceptTest";
declare variable $excepttest:SUBCOL1_NAME := $excepttest:COLLECTION_NAME||"/col1";
declare variable $excepttest:SUBCOL2_NAME := $excepttest:COLLECTION_NAME||"/col2";

declare variable $excepttest:COLLECTION := collection("/db"||$excepttest:COLLECTION_NAME);
declare variable $excepttest:SUBCOL1 := collection("/db"||$excepttest:SUBCOL1_NAME);
declare variable $excepttest:SUBCOL2 := collection("/db"||$excepttest:SUBCOL2_NAME);

declare
%test:setUp
function excepttest:setup() {

    xmldb:create-collection("/db", $excepttest:COLLECTION_NAME),
    xmldb:create-collection("/db", $excepttest:SUBCOL1_NAME),
    xmldb:create-collection("/db", $excepttest:SUBCOL2_NAME),
    xmldb:store("/db"||$excepttest:SUBCOL1_NAME, "test.xml", $excepttest:DATA),
    xmldb:store("/db"||$excepttest:SUBCOL2_NAME, "test2.xml", $excepttest:DATA2)
};

declare
    %test:tearDown
function excepttest:cleanup() {
    xmldb:remove($excepttest:COLLECTION_NAME)
};

declare
    %test:pending("https://github.com/eXist-db/exist/issues/1348")
    %test:assertEquals("Act 1")
function excepttest:except-wildcard() {
    ($excepttest:COLLECTION/* except $excepttest:SUBCOL2/*)//tei:head/text()
};

declare
    %test:assertEquals("Act 1")
function excepttest:except-node-name() {
    ($excepttest:COLLECTION/tei:TEI except $excepttest:SUBCOL2/tei:TEI)//tei:head/text()
};


Added Error Handling to Require Result XML to have the <ResultList> Tag.

(:
 : Copyright (C) [2013] [The FURTHeR Project]
 :
 : 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 "3.0";
module namespace frt = "http://further.utah.edu/result-translation";

(: Import FURTHeR Module :)
(: import module namespace further = "http://further.utah.edu/xquery-functions-module"
    at "further.xq"; :)
import module namespace further = 'http://further.utah.edu/xquery-functions-module'
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/fqe/further/xq/further.xq';

(: Import FURTHeR Constants Module :)
(: import module namespace const = 'http://further.utah.edu/constants'
    at 'constants.xq'; :)
import module namespace const = 'http://further.utah.edu/constants'
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/fqe/further/xq/constants.xq';

(: ALWAYS Define Namespaces in XQUERY PROLOG! :)
declare namespace fn  = 'http://www.w3.org/2005/xpath-functions';
declare namespace fq = "http://further.utah.edu/core/query";
declare namespace dts = 'http://further.utah.edu/dts';
declare namespace mdr = "http://further.utah.edu/mdr";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace fqe = 'http://further.utah.edu/fqe';
(: DO NOT USE DEFAULT NAMESPACE, it may conflict with the response Namespaces :)

(: Global CONSTANTS, Always Translating FROM FURTHeR Namespace ID :)
declare variable $frt:FURTHER as xs:string := '32769';
declare variable $frt:FURTHeR as xs:string := 'FURTHeR';

(: We are using SNOMED (Namespace ID 30) for ObservationType Values :)
declare variable $frt:SNOMED as xs:string := '30';

(: DTS Terminology Namespace IDs :)
declare variable $frt:OMOP-V2 as xs:string := '32868';
declare variable $frt:ICD-9 as xs:string := '10';
declare variable $frt:LOINC as xs:string := '5102';

(: Empty String Value for Substituting Empty Arguments to Functions :)
declare variable $frt:EMPTY as xs:string := '';

(: Mark Criterias that got Skipped :)
declare variable $frt:SKIP as xs:string := 'S';

(: Yes Value Used for Translation Flag transFlag :)
declare variable $frt:YES as xs:string := 'Y';

(: No Value Used for Translation Flag transFlag :)
declare variable $frt:NO as xs:string := 'N';

(: ERROR Value Used for Translation Flag transFlag :)
declare variable $frt:ERROR as xs:string := 'E';

(: Placeholder in case preTranslation Fails :)
declare variable $frt:ZERO as xs:string := '0';

(: DELIMITER :)
declare variable $frt:DELIMITER as xs:string := '^';

(: MDR Static Property Names CASE SENSITIVE! :)
declare variable $frt:ATTR_TRANS_FUNC as xs:string := 'ATTR_TRANS_FUNC';
declare variable $frt:ATTR_VALUE_TRANS_FUNC as xs:string := 'ATTR_VALUE_TRANS_FUNC';
declare variable $frt:ATTR_VALUE_TRANS_TO_DATA_TYPE as xs:string := 'ATTR_VALUE_TRANS_TO_DATA_TYPE';
declare variable $frt:CODING_SYSTEM as xs:string := 'CODING_SYSTEM';
declare variable $frt:EXT_PERSON as xs:string := 'EXT_PERSON';
declare variable $frt:EXT_ROOT_ID_ATTR as xs:string := 'EXT_ROOT_ID_ATTR';

declare variable $frt:pickMe as xs:string := 'pickMe';
declare variable $frt:skipATTR as xs:string := 'skipAttr';
declare variable $frt:translateCode as xs:string := 'translateCode';
declare variable $frt:ageToBirthYear as xs:string := 'ageToBirthYear';

(: DTS Static Property Names CASE SENSITIVE! :)
declare variable $frt:CodeInSource as xs:string := 'Code in Source';
declare variable $frt:LocalCode as xs:string := 'Local Code';

(:==================================================================:)
(: Main Translate Result Function                                   :)
(: Our Goal here is to construct the Target Central Model           :)
(:==================================================================:)
declare function frt:transResult($inputXML as document-node(),
                                 $extNmspcId as xs:string,
                                 $dataSetId as xs:string)
{

  (: Get the Namespace Name Using the Namespace ID :)
  let $extNmspcName := further:getNamespaceName($extNmspcId)

  (: Must Keep this Order of Processing :)

  (: Create Empty Person Template :)
  let $emptyPerson := frt:createPersonTemplate($extNmspcName)

  (: Initialize Empty Person Template with MDR Properties :)
  let $mdrPerson := frt:initPersonTemplate($emptyPerson,$extNmspcName)

  return

    (: Validate Initialized Template :)
    if ($mdrPerson/*[@extRootObject=$frt:ERROR]) then

		  (: Error Handling :)
		  frt:validateTemplate($mdrPerson,$extNmspcName)

    else (: Continue Processing :)

		  (: Read the Input File from External Result for Processing :)
      (: Returns a document node for the following functions :)
		  let $transResult := frt:process($mdrPerson,$inputXML,$extNmspcId,$dataSetId)

		  (: Error Handling :)
		  let $validated := frt:validate($transResult,$extNmspcName)

		  (: Call cleanup Transformation :)
		  let $cleaned := frt:cleanup($validated)

		  (: Return Final Cleaned Version :)
		  return $cleaned

};

(:==================================================================:)
(: createPersonTemplate = Create Person Template XML Format         :)
(:==================================================================:)
declare function frt:createPersonTemplate($extNmspcName as xs:string)
as document-node()
{

(: Create a Document Type Here! :)
document
{
  <Person centralRootObject="{$frt:EMPTY}" extRootObject="{$frt:EMPTY}">
    <id></id>
    <administrativeGenderNamespaceId>{$frt:SNOMED}</administrativeGenderNamespaceId>
    <administrativeGender extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></administrativeGender>
    <raceNamespaceId>{$frt:SNOMED}</raceNamespaceId>
    <race extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></race>
    <ethnicityNamespaceId>{$frt:SNOMED}</ethnicityNamespaceId>
    <ethnicity extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></ethnicity>
    <dateOfBirth extPath="{$frt:EMPTY}"></dateOfBirth>
    <birthYear extPath="{$frt:EMPTY}"></birthYear>
    <birthMonth extPath="{$frt:EMPTY}"></birthMonth>
    <birthDay extPath="{$frt:EMPTY}"></birthDay>
    <educationLevel extPath="{$frt:EMPTY}"></educationLevel>
    <primaryLanguageNamespaceId>{$frt:SNOMED}</primaryLanguageNamespaceId>
    <primaryLanguage extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></primaryLanguage>
    <maritalStatusNamespaceId>{$frt:SNOMED}</maritalStatusNamespaceId>
    <maritalStatus extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></maritalStatus>
    <religionNamespaceId>{$frt:SNOMED}</religionNamespaceId>
    <religion extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></religion>
    <multipleBirthIndicator extPath="{$frt:EMPTY}"></multipleBirthIndicator>
    <multipleBirthIndicatorOrderNumber extPath="{$frt:EMPTY}"></multipleBirthIndicatorOrderNumber>
    <causeOfDeathNamespaceId>{$frt:SNOMED}</causeOfDeathNamespaceId>
    <causeOfDeath extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></causeOfDeath>
    <dateOfDeath extPath="{$frt:EMPTY}"></dateOfDeath>
    <deathYear extPath="{$frt:EMPTY}"></deathYear>
    <pedigreeQuality extPath="{$frt:EMPTY}"></pedigreeQuality>
  </Person>
}

(: END Function :)
};

(:==================================================================:)
(: initPersonTemplate = Create Person Template XML Format           :)
(:==================================================================:)
declare function frt:initPersonTemplate($emptyPerson as document-node(),
                                        $extNmspcName as xs:string)
as document-node()
{

(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $emptyPerson
modify (

  (: Find the Central Root Object :)
  (: The Name of the Root Element is the Name of the Central Root Object :)
  let $centralRootObject := fn:name($inputCopy/child::node())
  return (

    (: Set the Central Root Object XML Attribute :)
    replace value of node $inputCopy//@centralRootObject with $centralRootObject

    , (: DO MORE STUFF :)

    (: Find the External Root Object to Use as a Reference Point for External XML Doc :)
    let $extRootObject := frt:getExtRootObject($centralRootObject,$extNmspcName)
    return
      replace value of node $inputCopy//@extRootObject with $extRootObject

    , (: DO MORE STUFF :)

    (: Populate the extPath XML Attributes in the Template from MDR :)
    for $centralAttr in $inputCopy//*[@extPath=$frt:EMPTY]
      let $extPath := frt:getExtPath(name($centralAttr),$frt:FURTHeR,$extNmspcName)
      return replace value of node $centralAttr/@extPath with $extPath

    , (: DO MORE STUFF :)

    (: Set DTS Translation Instruction from MDR :)
    for $dtsAttr in $inputCopy//*[@dtsFlag]
      let $dtsFlag := frt:getDTSFlag(name($dtsAttr),$frt:FURTHeR,$extNmspcName)
      return replace value of node $dtsAttr/@dtsFlag with $dtsFlag

  ) (: End Return :)

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: validateTemplate (Error Handling)                                :)
(:==================================================================:)
declare function frt:validateTemplate($inputXML,$srcNmspcName as xs:string)
as document-node()
{

(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $inputXML
modify (

  if ($inputCopy/*[@extRootObject=$frt:ERROR]) then

    (: Get Name of the XML Root Node (Central Root Object) :)
    let $attrName := fn:name($inputCopy/*[@extRootObject=$frt:ERROR])
    return
    (: replace ONLY Works when we are Referring to a Document Type (NOT Element Type) :)
    replace node $inputCopy/*
       with
       <error xmlns="http://further.utah.edu/core/ws">
         MDR_RESULT_TRANSLATION_ERROR
         <message>MDR Association for [ {$srcNmspcName}.{$attrName} ] May be Missing</message>
       </error>

  else ()

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: process = Processing Function                                    :)
(:==================================================================:)
declare function frt:process($mdrPerson,$extXML,$extNmspcId,$dataSetId)
{

  (: Get the Namespace Name Using the Namespace ID :)
  let $extNmspcName := further:getNamespaceName($extNmspcId)

  (: High Level WorkFlow
	  1) Find the rootObject in the External Model by using the extRootObject Attribute Hint
	  2) For each rootObject in the External Model, create a mdrPerson Node and populate it with DTS Translated Data
	  3) Replace the <id> node with getPersonId function
	  4) Place the full result in a <ResultList> node
  :)

  (: Get External Root Object :)
  let $extRootObject := fn:substring-before($mdrPerson//@extRootObject,$frt:DELIMITER)

  (: Loop to Return ALL External Root Objects :)
  return

  if ($extXML[ResultList]) then
	  document{
		  <ResultList>
		    {
		      for $extRoot at $i in $extXML/ResultList/*[fn:name()=$extRootObject]
		      (: debug
		         return $extRootObject :)
		      return frt:transPerson($mdrPerson,$extRoot,$extNmspcId,$dataSetId)
		    }
		  </ResultList>
	  }
  else
    document {
      <error xmlns="http://further.utah.edu/core/ws">
        INVALID_RESULTLIST_ERROR
        <message>Invalid ResultList for Namespace [ {$extNmspcName} ] </message>
      </error>
    }

(: END Function :)
};

(:==================================================================:)
(: transPerson = Translate Single Person                            :)
(:==================================================================:)
declare function frt:transPerson($mdrPerson,$extPerson,$extNmspcId,$dataSetId)
as document-node()
{

(:
1) Get Data from External Input File and Populate our Template
2) Get DTS Translated Data if necessary
3) Replace the <id> node with getPersonId function
:)

(: BEGIN XQUERY TRANSFORMATION :)
copy $transFields := $mdrPerson
modify (

  (: Get Data from External Person :)
  for $field in $transFields//*[@extPath != $frt:EMPTY]
    (: Get the External Field Value using Dynamic Evaluation Function :)
    (: Full Path should be starting from under the rootObject node :)
    (: Create a String to represent the Full Document Path :)
    let $s := concat("$doc",$field/@extPath)
    (: Evaluate the String with a mapping to the document/element :)
    (: Took long time to figure this out, it is amazing when it works! :)
    let $extValue := xquery:eval($s,map {"doc" := $extPerson})
    let $cnt := fn:count($extValue)
    return (
	    if ( $cnt > 1 ) then
		    insert node attribute multiError {$cnt} into $field
	      else
        replace value of node $field with $extValue
    )

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $transDTS := $transFields
modify (

  (: Get Data from External Person :)
  for $field in $transDTS//*[@dtsFlag=$frt:translateCode]

    let $dtsSrcPropVal := $field/text()
    let $tgTerm := $field/@dtsTerm

    (: Call DTS :)
    let $dtsResponse := further:getTranslatedConcept($extNmspcId,
                                                     $frt:LocalCode,
                                                     $dtsSrcPropVal,
                                                     $tgTerm,
                                                     $frt:CodeInSource)
    (: DEBUG DTS URL :)
    (: let $dtsURL := further:getConceptTranslationRestUrl($extNmspcId,
                                                        $frt:LocalCode,
                                                        $dtsSrcPropVal,
                                                        $tgTerm,
                                                        $frt:CodeInSource) :)

    (: Get Translated Value :)
    let $translatedPropVal := further:getConceptPropertyValue($dtsResponse)

    return
      if ($translatedPropVal) then (
        replace value of node $field with $translatedPropVal
        ,
        replace value of node $field/@dtsFlag with $frt:YES
      )
      else
        (: Always return Error if there is no DTS Mapping :)
        replace value of node $field/@dtsFlag with $frt:ERROR

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $transRootId := $transDTS
modify (

  (: Find the External Root Object & Root Object Attr :)
  let $extRootObject := fn:substring-before($transRootId//@extRootObject,$frt:DELIMITER)
  let $extRootObjectAttr := fn:substring-after($transRootId//@extRootObject,$frt:DELIMITER)
  return
    replace node $transRootId//id
       with frt:getPersonId($extNmspcId,$extPerson,$extRootObject,$extRootObjectAttr,$dataSetId)

) (: End Modify :)
return $transRootId

(: END Function :)
};

(:==================================================================:)
(: Validate (Error Handling)                                        :)
(:==================================================================:)
declare function frt:validate($inputXML as document-node(),$srcNmspcName as xs:string)
as document-node()
{
(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $inputXML
modify (

  (: Error out ONLY the FIRST criteria AttributeName :)
  (: This will ensure that the output xml is valid since there is no outter <errors> node at this time :)
  (: It will also prevent us from having a very long list of errors :)
  (: Within the for statement, be sure to use the parentheses after the in clause.
     Therefore, the position predicate[1] will function properly.
     if we take out the parentheses and the [1], we will list the all criterias with error.
     which we may want in the future. :)

  if ($inputCopy/ResultList//*[@dtsFlag=$frt:ERROR]) then (

    (: Return the First Criteria that Errored so we do not have a long list of Errors :)
    for $field in ($inputCopy/ResultList//*[@dtsFlag=$frt:ERROR])[1]
    let $attrName := fn:name($field)
      return
      replace node $inputCopy/*
         with
         <error xmlns="http://further.utah.edu/core/ws">
           DTS_RESULT_TRANSLATION_ERROR
           <message>DTS Mapping for [ {$srcNmspcName}.{$attrName} ] May be Missing</message>
         </error>
  )
  else(
    (: Remove ALL Nodes that have been Marked to be SKIPPED :)
    delete node $inputCopy/ResultList//*[@extPath=$frt:SKIP]
  ) (: End IF-Else Statement :)

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: Cleanup                                                          :)
(:==================================================================:)
declare function frt:cleanup($inputXML)
{

(: BEGIN XQUERY TRANSFORMATION :)
copy $inputCopy1 := $inputXML
modify (

  (: Remove ALL Empty Data Nodes :)
  for $node in $inputCopy1/ResultList//*[@extPath=$frt:EMPTY]
    return delete node $node

  , (: Delete ALL tranFlag Attributes on SUCCESS :)
  delete node $inputCopy1/ResultList//@extRootObject,
  delete node $inputCopy1/ResultList//@centralRootObject,
  delete node $inputCopy1/ResultList//@extPath,
  delete node $inputCopy1/ResultList//@dtsTerm,
  delete node $inputCopy1/ResultList//@dtsFlag

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $inputCopy2 := $inputCopy1
modify (

  (: Remove ALL Empty Namespace Nodes :)
	(: Loop through Each Person rootObject :)
	for $person in $inputCopy2/ResultList/Person

	  (: For ALL Namespace Nodes :)
	  for $nmspcNode in $person//*[fn:contains(fn:name(),'NamespaceId')]

	    (: Get the coresponding data node name :)
	    let $dataNodeName := fn:substring-before(fn:name($nmspcNode),'NamespaceId')

	    return (:insert node attribute debug {$dataNodeName} into $nmspcNode:)
	      (: Remove ALL Namespace Nodes if coresponding dataNode does NOT exist :)
        if (fn:not(fn:exists($person//*[fn:name()=$dataNodeName]))) then
	        delete node $nmspcNode
	      else()

) (: End Modify :)
return $inputCopy2

(: END Function :)
};

(:=====================================================================:)
(: Sanitize SINGLE & DOUBLE Quotes to Prevent XQuery Injection Attacks :)
(:=====================================================================:)
declare function frt:sanitize($inputXML as document-node())
as document-node()
{

(: Ideally, I want to replace all '&' characters with '&'
   However, BaseX does not allow me to have this character in the xml file or output.
   So I am skipping this for now :)

(: Transformation to replace Single Quotes with ''' :)
copy $inputCopy := $inputXML
modify (

  for $node at $i in $inputCopy//*[contains(text(),'''')]
  return
    replace value of node $node with replace($node, '''','&apos;')

) (: End Modify :)

return
(: Starting another Transformation, so the replace node will not conflict :)
(: Transformation to replace Double Quotes with '"' :)
copy $inputCopy2 := $inputCopy
modify (

  for $node at $i in $inputCopy2//*[contains(text(),"""")]
  return
    replace value of node $node with replace($node, """",'&quot;')

) (: End Modify :)
return $inputCopy2

}; (: END OF FUNCTION frt:sanitize :)

(:=====================================================================:)
(: getPersonId = Construct the group of Person ID Tags                 :)
(:=====================================================================:)
declare function frt:getPersonId($extNmspcId,$extPerson,$extRootObject,$extRootObjectAttr,$dataSetId)
{
  (: Get the External ID Value :)
  let $s := concat("$doc/",$extRootObjectAttr)

  (: Evaluate the String with a mapping to the document/element :)
  (: Took long time to figure this out, it is amazing when it works! :)
  let $extIdValue := xquery:eval($s,map {"doc" := $extPerson})

  let $cnt := fn:count($extIdValue)
  return (
	  if ( $cnt > 1 ) then
      <id multiError='{$cnt}'/>
	  else
		  (: Call Identity Resolution Service :)
		  (:
		    REST CAll FORMAT

		    http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/
		    {target_object}/{target_attribute}/{source_namespace_id}/
		    {source_object}/{source_attribute}/{source_id_value}/{queryId}

		    Note:
		    For Result Translation, Target is always the Central Model (FURTHER Model)
		    The Source is the External Data Source Models

		    Examples:
http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/PERSON/FPERSON_ID/32868/PERSON/PERSONID/12345/862c9130-0e89-11e3-bb9f-f23c91aec05e
http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/PERSON/FPERSON_ID/32776/PATIENT/PAT_DE_ID/12345/862c9130-0e89-11e3-bb9f-f23c91aec05e
		  :)

      (: Built the REST URL :)
		  let $baseURL := fn:concat($const:fqeRestServer,'/mpi/rest/id/generate/PERSON/FPERSON_ID/')
		  let $docUrl := fn:concat($baseURL, $extNmspcId, '/', $extRootObject, '/' , $extRootObjectAttr , '/', $extIdValue , '/', $dataSetId)

		  (: Prevent XQuery Injection Attacks :)
		  let $parsedDocUrl := iri-to-uri($docUrl)
		  let $result := doc($parsedDocUrl)

		  (: Strip out the Person ID from the Result :)
		  (: let $resolvedPersonId := $result//fqe:value/text() :)
		  let $resolvedPersonId := $result/fqe:id/fqe:value/text()

		  return (

        (: DEBUG with trace :)
        (: trace($resolvedPersonId, 'ResolvedPersonID'), :)

				<id>
				  <datasetId>{$dataSetId}</datasetId>
		      <id>{$resolvedPersonId}</id>
			  </id>
			  ,
			  <compositeId>{$dataSetId}:{$resolvedPersonId}</compositeId>
		  )

  ) (: End of Return :)

}; (: END OF FUNCTION :)

(:==================================================================:)
(: getLeftAssoc = Get Left Assocation from MDR                      :)
(:==================================================================:)
declare function frt:getLeftAssoc(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  (: EXAMPLE: ${server.dts.ws}/mdr/rest/asset/association/left/translatesTo/genderConceptId :)
  (:          ${server.dts.ws}/mdr/rest/asset/association/left/translatesTo/{sourceAttr} :)
  (:          http://demo.further.utah.edu:9000/mdr/rest/asset/association/left/translatesTo/administrativeGender :)
  let $baseURL := fn:concat($const:fmdrRestServer,'/rest/asset/association/left/translatesTo/')
  let $docUrl := fn:concat( $baseURL, $leftAttrName )

  (: Prevent XQuery Injection Attacks :)
  let $parsedDocUrl := iri-to-uri( $docUrl )
  let $doc := doc($parsedDocUrl)

  (: Return the AssetAssociation for the Correct Namespaces :)
  return

    if (fn:count($doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName]) > 1) then
      $doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName and properties/entry/value=$frt:pickMe]
    else
      $doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName]

};

(:==================================================================:)
(: getExtPath = GET XPath of XML Element in External XML from MDR   :)
(:==================================================================:)
declare function frt:getExtPath(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  let $leftAssoc := frt:getLeftAssoc($leftAttrName,$leftNmspcName,$rightNmspcName)

  (: Extract Out the External XPath Value :)
  for $entry in $leftAssoc/properties/entry[key='RESULT_PATH']
  return
    if ($entry) then $entry/value
    else $frt:EMPTY

};

(:==================================================================:)
(: getDTSFlag = GET DTS Instruction for External XML from MDR       :)
(:==================================================================:)
declare function frt:getDTSFlag(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  let $leftAssoc := frt:getLeftAssoc($leftAttrName,$leftNmspcName,$rightNmspcName)

  (: Extract Out the External XPath Value :)
  for $entry in $leftAssoc/properties/entry[key=$frt:ATTR_VALUE_TRANS_FUNC]
  return
    if ($entry) then $entry/value
    else $frt:EMPTY

};

(:==================================================================:)
(: getExtRootObject = GET External rootObject from MDR              :)
(:==================================================================:)
declare function frt:getExtRootObject(
                 $centralRootObject as xs:string,
                 $extNmspcName as xs:string
                 )
{

  let $leftAssoc := frt:getLeftAssoc($centralRootObject,$frt:FURTHeR,$extNmspcName)

  return

    (: if there is an Association Result :)
    if ($leftAssoc/properties/entry[key=$frt:EXT_ROOT_ID_ATTR]) then

      (: Get the External Root Object:)
      let $extRootObject := $leftAssoc/rightAsset/text()

      (: Get the External Root Object ID Attribute :)
      let $extRootObjectAttr :=
        for $entry in $leftAssoc/properties/entry[key=$frt:EXT_ROOT_ID_ATTR]
          return $entry/value/text()

      (: Return Concatenated String :)
      return concat($extRootObject,$frt:DELIMITER,$extRootObjectAttr)

    else $frt:ERROR

};

(:==================================================================:)
(: printDebug = Print Debug Variable to Query Info Screen           :)
(:==================================================================:)
declare function frt:printDebug($debugVar,$msg as xs:string?)
{
  let $var := $debugVar
  return fn:trace( $var,concat('DEBUG ', $msg, '=') )
};

(:==================================================================:)
(: ageToBirthYear = Translate Age to BirthYear                      :)
(:==================================================================:)
declare function frt:ageToBirthYear($age)
{
  (: Get Current Year :)
  let $curYear := year-from-date(current-date())

  (: Subtract Age from CurrentYear to Get BirthYear :)
  return $curYear - $age
};

(: END OF MODULE :)

(:
 : Copyright (C) [2013] [The FURTHeR Project]
 :
 : 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 "3.0";
module namespace frt = "http://further.utah.edu/result-translation";

(: Import FURTHeR Module :)
(: import module namespace further = "http://further.utah.edu/xquery-functions-module"
    at "further.xq"; :)
import module namespace further = 'http://further.utah.edu/xquery-functions-module'
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/fqe/further/xq/further.xq';

(: Import FURTHeR Constants Module :)
(: import module namespace const = 'http://further.utah.edu/constants'
    at 'constants.xq'; :)
import module namespace const = 'http://further.utah.edu/constants'
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/fqe/further/xq/constants.xq';

(: ALWAYS Define Namespaces in XQUERY PROLOG! :)
declare namespace fn  = 'http://www.w3.org/2005/xpath-functions';
declare namespace fq = "http://further.utah.edu/core/query";
declare namespace dts = 'http://further.utah.edu/dts';
declare namespace mdr = "http://further.utah.edu/mdr";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace fqe = 'http://further.utah.edu/fqe';
(: DO NOT USE DEFAULT NAMESPACE, it may conflict with the response Namespaces :)

(: Global CONSTANTS, Always Translating FROM FURTHeR Namespace ID :)
declare variable $frt:FURTHER as xs:string := '32769';
declare variable $frt:FURTHeR as xs:string := 'FURTHeR';

(: We are using SNOMED (Namespace ID 30) for ObservationType Values :)
declare variable $frt:SNOMED as xs:string := '30';

(: DTS Terminology Namespace IDs :)
declare variable $frt:OMOP-V2 as xs:string := '32868';
declare variable $frt:ICD-9 as xs:string := '10';
declare variable $frt:LOINC as xs:string := '5102';

(: Empty String Value for Substituting Empty Arguments to Functions :)
declare variable $frt:EMPTY as xs:string := '';

(: Mark Criterias that got Skipped :)
declare variable $frt:SKIP as xs:string := 'S';

(: Yes Value Used for Translation Flag transFlag :)
declare variable $frt:YES as xs:string := 'Y';

(: No Value Used for Translation Flag transFlag :)
declare variable $frt:NO as xs:string := 'N';

(: ERROR Value Used for Translation Flag transFlag :)
declare variable $frt:ERROR as xs:string := 'E';

(: Placeholder in case preTranslation Fails :)
declare variable $frt:ZERO as xs:string := '0';

(: DELIMITER :)
declare variable $frt:DELIMITER as xs:string := '^';

(: MDR Static Property Names CASE SENSITIVE! :)
declare variable $frt:ATTR_TRANS_FUNC as xs:string := 'ATTR_TRANS_FUNC';
declare variable $frt:ATTR_VALUE_TRANS_FUNC as xs:string := 'ATTR_VALUE_TRANS_FUNC';
declare variable $frt:ATTR_VALUE_TRANS_TO_DATA_TYPE as xs:string := 'ATTR_VALUE_TRANS_TO_DATA_TYPE';
declare variable $frt:CODING_SYSTEM as xs:string := 'CODING_SYSTEM';
declare variable $frt:EXT_PERSON as xs:string := 'EXT_PERSON';
declare variable $frt:EXT_ROOT_ID_ATTR as xs:string := 'EXT_ROOT_ID_ATTR';

declare variable $frt:pickMe as xs:string := 'pickMe';
declare variable $frt:skipATTR as xs:string := 'skipAttr';
declare variable $frt:translateCode as xs:string := 'translateCode';
declare variable $frt:ageToBirthYear as xs:string := 'ageToBirthYear';

(: DTS Static Property Names CASE SENSITIVE! :)
declare variable $frt:CodeInSource as xs:string := 'Code in Source';
declare variable $frt:LocalCode as xs:string := 'Local Code';

(:==================================================================:)
(: Main Translate Result Function                                   :)
(: Our Goal here is to construct the Target Central Model           :)
(:==================================================================:)
declare function frt:transResult($inputXML as document-node(),
                                 $extNmspcId as xs:string,
                                 $dataSetId as xs:string)
{

  (: Get the Namespace Name Using the Namespace ID :)
  let $extNmspcName := further:getNamespaceName($extNmspcId)

  (: Must Keep this Order of Processing :)

  (: Create Empty Person Template :)
  let $emptyPerson := frt:createPersonTemplate($extNmspcName)

  (: Initialize Empty Person Template with MDR Properties :)
  let $mdrPerson := frt:initPersonTemplate($emptyPerson,$extNmspcName)

  return

    (: Validate Initialized Template :)
    if ($mdrPerson/*[@extRootObject=$frt:ERROR]) then

		  (: Error Handling :)
		  frt:validateTemplate($mdrPerson,$extNmspcName)

    else (: Continue Processing :)

		  (: Read the Input File from External Result for Processing :)
      (: Returns a document node for the following functions :)
		  let $transResult := frt:process($mdrPerson,$inputXML,$extNmspcId,$dataSetId)

		  (: Error Handling :)
		  let $validated := frt:validate($transResult,$extNmspcName)

		  (: Call cleanup Transformation :)
		  let $cleaned := frt:cleanup($validated)

		  (: Return Final Cleaned Version :)
		  return $cleaned

};

(:==================================================================:)
(: createPersonTemplate = Create Person Template XML Format         :)
(:==================================================================:)
declare function frt:createPersonTemplate($extNmspcName as xs:string)
as document-node()
{

(: Create a Document Type Here! :)
document
{
  <Person centralRootObject="{$frt:EMPTY}" extRootObject="{$frt:EMPTY}">
    <id></id>
    <administrativeGenderNamespaceId>{$frt:SNOMED}</administrativeGenderNamespaceId>
    <administrativeGender extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></administrativeGender>
    <raceNamespaceId>{$frt:SNOMED}</raceNamespaceId>
    <race extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></race>
    <ethnicityNamespaceId>{$frt:SNOMED}</ethnicityNamespaceId>
    <ethnicity extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></ethnicity>
    <dateOfBirth extPath="{$frt:EMPTY}"></dateOfBirth>
    <birthYear extPath="{$frt:EMPTY}"></birthYear>
    <birthMonth extPath="{$frt:EMPTY}"></birthMonth>
    <birthDay extPath="{$frt:EMPTY}"></birthDay>
    <educationLevel extPath="{$frt:EMPTY}"></educationLevel>
    <primaryLanguageNamespaceId>{$frt:SNOMED}</primaryLanguageNamespaceId>
    <primaryLanguage extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></primaryLanguage>
    <maritalStatusNamespaceId>{$frt:SNOMED}</maritalStatusNamespaceId>
    <maritalStatus extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></maritalStatus>
    <religionNamespaceId>{$frt:SNOMED}</religionNamespaceId>
    <religion extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></religion>
    <multipleBirthIndicator extPath="{$frt:EMPTY}"></multipleBirthIndicator>
    <multipleBirthIndicatorOrderNumber extPath="{$frt:EMPTY}"></multipleBirthIndicatorOrderNumber>
    <causeOfDeathNamespaceId>{$frt:SNOMED}</causeOfDeathNamespaceId>
    <causeOfDeath extPath="{$frt:EMPTY}" dtsTerm="{$frt:SNOMED}" dtsFlag="{$frt:EMPTY}"></causeOfDeath>
    <dateOfDeath extPath="{$frt:EMPTY}"></dateOfDeath>
    <deathYear extPath="{$frt:EMPTY}"></deathYear>
    <pedigreeQuality extPath="{$frt:EMPTY}"></pedigreeQuality>
  </Person>
}

(: END Function :)
};

(:==================================================================:)
(: initPersonTemplate = Create Person Template XML Format           :)
(:==================================================================:)
declare function frt:initPersonTemplate($emptyPerson as document-node(),
                                        $extNmspcName as xs:string)
as document-node()
{

(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $emptyPerson
modify (

  (: Find the Central Root Object :)
  (: The Name of the Root Element is the Name of the Central Root Object :)
  let $centralRootObject := fn:name($inputCopy/child::node())
  return (

    (: Set the Central Root Object XML Attribute :)
    replace value of node $inputCopy//@centralRootObject with $centralRootObject

    , (: DO MORE STUFF :)

    (: Find the External Root Object to Use as a Reference Point for External XML Doc :)
    let $extRootObject := frt:getExtRootObject($centralRootObject,$extNmspcName)
    return
      replace value of node $inputCopy//@extRootObject with $extRootObject

    , (: DO MORE STUFF :)

    (: Populate the extPath XML Attributes in the Template from MDR :)
    for $centralAttr in $inputCopy//*[@extPath=$frt:EMPTY]
      let $extPath := frt:getExtPath(name($centralAttr),$frt:FURTHeR,$extNmspcName)
      return replace value of node $centralAttr/@extPath with $extPath

    , (: DO MORE STUFF :)

    (: Set DTS Translation Instruction from MDR :)
    for $dtsAttr in $inputCopy//*[@dtsFlag]
      let $dtsFlag := frt:getDTSFlag(name($dtsAttr),$frt:FURTHeR,$extNmspcName)
      return replace value of node $dtsAttr/@dtsFlag with $dtsFlag

  ) (: End Return :)

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: validateTemplate (Error Handling)                                :)
(:==================================================================:)
declare function frt:validateTemplate($inputXML,$srcNmspcName as xs:string)
as document-node()
{

(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $inputXML
modify (

  if ($inputCopy/*[@extRootObject=$frt:ERROR]) then

    (: Get Name of the XML Root Node (Central Root Object) :)
    let $attrName := fn:name($inputCopy/*[@extRootObject=$frt:ERROR])
    return
    (: replace ONLY Works when we are Referring to a Document Type (NOT Element Type) :)
    replace node $inputCopy/*
       with
       <error xmlns="http://further.utah.edu/core/ws">
         MDR_RESULT_TRANSLATION_ERROR
         <message>MDR Association for [ {$srcNmspcName}.{$attrName} ] May be Missing</message>
       </error>

  else ()

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: process = Processing Function                                    :)
(:==================================================================:)
declare function frt:process($mdrPerson,$extXML,$extNmspcId,$dataSetId)
{

  (: High Level WorkFlow
	  1) Find the rootObject in the External Model by using the extRootObject Attribute Hint
	  2) For each rootObject in the External Model, create a mdrPerson Node and populate it with DTS Translated Data
	  3) Replace the <id> node with getPersonId function
	  4) Place the full result in a <ResultList> node
  :)

  (: Get External Root Object :)
  let $extRootObject := fn:substring-before($mdrPerson//@extRootObject,$frt:DELIMITER)

  (: Loop to Return ALL External Root Objects :)
  return
  document{
  <ResultList>
    {
      for $extRoot at $i in $extXML/ResultList/*[fn:name()=$extRootObject]
      (: debug
         return $extRootObject :)
      return frt:transPerson($mdrPerson,$extRoot,$extNmspcId,$dataSetId)
    }
  </ResultList>
  }

(: END Function :)
};

(:==================================================================:)
(: transPerson = Translate Single Person                            :)
(:==================================================================:)
declare function frt:transPerson($mdrPerson,$extPerson,$extNmspcId,$dataSetId)
as document-node()
{

(:
1) Get Data from External Input File and Populate our Template
2) Get DTS Translated Data if necessary
3) Replace the <id> node with getPersonId function
:)

(: BEGIN XQUERY TRANSFORMATION :)
copy $transFields := $mdrPerson
modify (

  (: Get Data from External Person :)
  for $field in $transFields//*[@extPath != $frt:EMPTY]
    (: Get the External Field Value using Dynamic Evaluation Function :)
    (: Full Path should be starting from under the rootObject node :)
    (: Create a String to represent the Full Document Path :)
    let $s := concat("$doc",$field/@extPath)
    (: Evaluate the String with a mapping to the document/element :)
    (: Took long time to figure this out, it is amazing when it works! :)
    let $extValue := xquery:eval($s,map {"doc" := $extPerson})
    let $cnt := fn:count($extValue)
    return (
	    if ( $cnt > 1 ) then
		    insert node attribute multiError {$cnt} into $field
	      else
        replace value of node $field with $extValue
    )

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $transDTS := $transFields
modify (

  (: Get Data from External Person :)
  for $field in $transDTS//*[@dtsFlag=$frt:translateCode]

    let $dtsSrcPropVal := $field/text()
    let $tgTerm := $field/@dtsTerm

    (: Call DTS :)
    let $dtsResponse := further:getTranslatedConcept($extNmspcId,
                                                     $frt:LocalCode,
                                                     $dtsSrcPropVal,
                                                     $tgTerm,
                                                     $frt:CodeInSource)
    (: DEBUG DTS URL :)
    (: let $dtsURL := further:getConceptTranslationRestUrl($extNmspcId,
                                                        $frt:LocalCode,
                                                        $dtsSrcPropVal,
                                                        $tgTerm,
                                                        $frt:CodeInSource) :)

    (: Get Translated Value :)
    let $translatedPropVal := further:getConceptPropertyValue($dtsResponse)

    return
      if ($translatedPropVal) then (
        replace value of node $field with $translatedPropVal
        ,
        replace value of node $field/@dtsFlag with $frt:YES
      )
      else
        (: Always return Error if there is no DTS Mapping :)
        replace value of node $field/@dtsFlag with $frt:ERROR

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $transRootId := $transDTS
modify (

  (: Find the External Root Object & Root Object Attr :)
  let $extRootObject := fn:substring-before($transRootId//@extRootObject,$frt:DELIMITER)
  let $extRootObjectAttr := fn:substring-after($transRootId//@extRootObject,$frt:DELIMITER)
  return
    replace node $transRootId//id
       with frt:getPersonId($extNmspcId,$extPerson,$extRootObject,$extRootObjectAttr,$dataSetId)

) (: End Modify :)
return $transRootId

(: END Function :)
};

(:==================================================================:)
(: Validate (Error Handling)                                        :)
(:==================================================================:)
declare function frt:validate($inputXML as document-node(),$srcNmspcName as xs:string)
as document-node()
{
(: BEGIN XQUERY TRANSFORMATION :)
(: Make a copy of the entire Document :)
copy $inputCopy := $inputXML
modify (

  (: Error out ONLY the FIRST criteria AttributeName :)
  (: This will ensure that the output xml is valid since there is no outter <errors> node at this time :)
  (: It will also prevent us from having a very long list of errors :)
  (: Within the for statement, be sure to use the parentheses after the in clause.
     Therefore, the position predicate[1] will function properly.
     if we take out the parentheses and the [1], we will list the all criterias with error.
     which we may want in the future. :)

  if ($inputCopy//*[@dtsFlag=$frt:ERROR]) then (

    (: Return the First Criteria that Errored so we do not have a long list of Errors :)
    for $field in ($inputCopy//*[@dtsFlag=$frt:ERROR])[1]
    let $attrName := fn:name($field)
      return
      replace node $inputCopy/*
         with
         <error xmlns="http://further.utah.edu/core/ws">
           DTS_RESULT_TRANSLATION_ERROR
           <message>DTS Mapping for [ {$srcNmspcName}.{$attrName} ] May be Missing</message>
         </error>
  )
  else(
    (: Remove ALL Nodes that have been Marked to be SKIPPED :)
    delete node $inputCopy//*[@extPath=$frt:SKIP]
  ) (: End IF-Else Statement :)

) (: End Modify :)
return $inputCopy

(: END Function :)
};

(:==================================================================:)
(: Cleanup                                                          :)
(:==================================================================:)
declare function frt:cleanup($inputXML)
{

(: BEGIN XQUERY TRANSFORMATION :)
copy $inputCopy1 := $inputXML
modify (

  (: Remove ALL Empty Data Nodes :)
  for $node in $inputCopy1//*[@extPath=$frt:EMPTY]
    return delete node $node

  , (: Delete ALL tranFlag Attributes on SUCCESS :)
  delete node $inputCopy1//@extRootObject,
  delete node $inputCopy1//@centralRootObject,
  delete node $inputCopy1//@extPath,
  delete node $inputCopy1//@dtsTerm,
  delete node $inputCopy1//@dtsFlag

) (: End Modify :)
return

(: BEGIN XQUERY TRANSFORMATION :)
copy $inputCopy2 := $inputCopy1
modify (

  (: Remove ALL Empty Namespace Nodes :)
	(: Loop through Each Person rootObject :)
	for $person in $inputCopy2/ResultList/Person

	  (: For ALL Namespace Nodes :)
	  for $nmspcNode in $person//*[fn:contains(fn:name(),'NamespaceId')]

	    (: Get the coresponding data node name :)
	    let $dataNodeName := fn:substring-before(fn:name($nmspcNode),'NamespaceId')

	    return (:insert node attribute debug {$dataNodeName} into $nmspcNode:)
	      (: Remove ALL Namespace Nodes if coresponding dataNode does NOT exist :)
        if (fn:not(fn:exists($person//*[fn:name()=$dataNodeName]))) then
	        delete node $nmspcNode
	      else()

) (: End Modify :)
return $inputCopy2

(: END Function :)
};

(:=====================================================================:)
(: Sanitize SINGLE & DOUBLE Quotes to Prevent XQuery Injection Attacks :)
(:=====================================================================:)
declare function frt:sanitize($inputXML as document-node())
as document-node()
{

(: Ideally, I want to replace all '&' characters with '&'
   However, BaseX does not allow me to have this character in the xml file or output.
   So I am skipping this for now :)

(: Transformation to replace Single Quotes with ''' :)
copy $inputCopy := $inputXML
modify (

  for $node at $i in $inputCopy//*[contains(text(),'''')]
  return
    replace value of node $node with replace($node, '''','&apos;')

) (: End Modify :)

return
(: Starting another Transformation, so the replace node will not conflict :)
(: Transformation to replace Double Quotes with '"' :)
copy $inputCopy2 := $inputCopy
modify (

  for $node at $i in $inputCopy2//*[contains(text(),"""")]
  return
    replace value of node $node with replace($node, """",'&quot;')

) (: End Modify :)
return $inputCopy2

}; (: END OF FUNCTION frt:sanitize :)

(:=====================================================================:)
(: getPersonId = Construct the group of Person ID Tags                 :)
(:=====================================================================:)
declare function frt:getPersonId($extNmspcId,$extPerson,$extRootObject,$extRootObjectAttr,$dataSetId)
{
  (: Get the External ID Value :)
  let $s := concat("$doc/",$extRootObjectAttr)

  (: Evaluate the String with a mapping to the document/element :)
  (: Took long time to figure this out, it is amazing when it works! :)
  let $extIdValue := xquery:eval($s,map {"doc" := $extPerson})

  let $cnt := fn:count($extIdValue)
  return (
	  if ( $cnt > 1 ) then
      <id multiError='{$cnt}'/>
	  else
		  (: Call Identity Resolution Service :)
		  (:
		    REST CAll FORMAT

		    http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/
		    {target_object}/{target_attribute}/{source_namespace_id}/
		    {source_object}/{source_attribute}/{source_id_value}/{queryId}

		    Note:
		    For Result Translation, Target is always the Central Model (FURTHER Model)
		    The Source is the External Data Source Models

		    Examples:
http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/PERSON/FPERSON_ID/32868/PERSON/PERSONID/12345/862c9130-0e89-11e3-bb9f-f23c91aec05e
http://demo.further.utah.edu:9000/fqe/mpi/rest/id/generate/PERSON/FPERSON_ID/32776/PATIENT/PAT_DE_ID/12345/862c9130-0e89-11e3-bb9f-f23c91aec05e
		  :)

      (: Built the REST URL :)
		  let $baseURL := fn:concat($const:fqeRestServer,'/mpi/rest/id/generate/PERSON/FPERSON_ID/')
		  let $docUrl := fn:concat($baseURL, $extNmspcId, '/', $extRootObject, '/' , $extRootObjectAttr , '/', $extIdValue , '/', $dataSetId)

		  (: Prevent XQuery Injection Attacks :)
		  let $parsedDocUrl := iri-to-uri($docUrl)
		  let $result := doc($parsedDocUrl)

		  (: Strip out the Person ID from the Result :)
		  (: let $resolvedPersonId := $result//fqe:value/text() :)
		  let $resolvedPersonId := $result/fqe:id/fqe:value/text()

		  return (

        (: DEBUG with trace :)
        (: trace($resolvedPersonId, 'ResolvedPersonID'), :)

				<id>
				  <datasetId>{$dataSetId}</datasetId>
		      <id>{$resolvedPersonId}</id>
			  </id>
			  ,
			  <compositeId>{$dataSetId}:{$resolvedPersonId}</compositeId>
		  )

  ) (: End of Return :)

}; (: END OF FUNCTION :)

(:==================================================================:)
(: getLeftAssoc = Get Left Assocation from MDR                      :)
(:==================================================================:)
declare function frt:getLeftAssoc(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  (: EXAMPLE: ${server.dts.ws}/mdr/rest/asset/association/left/translatesTo/genderConceptId :)
  (:          ${server.dts.ws}/mdr/rest/asset/association/left/translatesTo/{sourceAttr} :)
  (:          http://demo.further.utah.edu:9000/mdr/rest/asset/association/left/translatesTo/administrativeGender :)
  let $baseURL := fn:concat($const:fmdrRestServer,'/rest/asset/association/left/translatesTo/')
  let $docUrl := fn:concat( $baseURL, $leftAttrName )

  (: Prevent XQuery Injection Attacks :)
  let $parsedDocUrl := iri-to-uri( $docUrl )
  let $doc := doc($parsedDocUrl)

  (: Return the AssetAssociation for the Correct Namespaces :)
  return

    if (fn:count($doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName]) > 1) then
      $doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName and properties/entry/value=$frt:pickMe]
    else
      $doc//assetAssociation[rightNamespace=$rightNmspcName and leftNamespace=$leftNmspcName]

};

(:==================================================================:)
(: getExtPath = GET XPath of XML Element in External XML from MDR   :)
(:==================================================================:)
declare function frt:getExtPath(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  let $leftAssoc := frt:getLeftAssoc($leftAttrName,$leftNmspcName,$rightNmspcName)

  (: Extract Out the External XPath Value :)
  for $entry in $leftAssoc/properties/entry[key='RESULT_PATH']
  return
    if ($entry) then $entry/value
    else $frt:EMPTY

};

(:==================================================================:)
(: getDTSFlag = GET DTS Instruction for External XML from MDR       :)
(:==================================================================:)
declare function frt:getDTSFlag(
                 $leftAttrName as xs:string,
                 $leftNmspcName as xs:string,
                 $rightNmspcName as xs:string)
{
  let $leftAssoc := frt:getLeftAssoc($leftAttrName,$leftNmspcName,$rightNmspcName)

  (: Extract Out the External XPath Value :)
  for $entry in $leftAssoc/properties/entry[key=$frt:ATTR_VALUE_TRANS_FUNC]
  return
    if ($entry) then $entry/value
    else $frt:EMPTY

};

(:==================================================================:)
(: getExtRootObject = GET External rootObject from MDR              :)
(:==================================================================:)
declare function frt:getExtRootObject(
                 $centralRootObject as xs:string,
                 $extNmspcName as xs:string
                 )
{

  let $leftAssoc := frt:getLeftAssoc($centralRootObject,$frt:FURTHeR,$extNmspcName)

  return

    (: if there is an Association Result :)
    if ($leftAssoc/properties/entry[key=$frt:EXT_ROOT_ID_ATTR]) then

      (: Get the External Root Object:)
      let $extRootObject := $leftAssoc/rightAsset/text()

      (: Get the External Root Object ID Attribute :)
      let $extRootObjectAttr :=
        for $entry in $leftAssoc/properties/entry[key=$frt:EXT_ROOT_ID_ATTR]
          return $entry/value/text()

      (: Return Concatenated String :)
      return concat($extRootObject,$frt:DELIMITER,$extRootObjectAttr)

    else $frt:ERROR

};

(:==================================================================:)
(: printDebug = Print Debug Variable to Query Info Screen           :)
(:==================================================================:)
declare function frt:printDebug($debugVar,$msg as xs:string?)
{
  let $var := $debugVar
  return fn:trace( $var,concat('DEBUG ', $msg, '=') )
};

(:==================================================================:)
(: ageToBirthYear = Translate Age to BirthYear                      :)
(:==================================================================:)
declare function frt:ageToBirthYear($age)
{
  (: Get Current Year :)
  let $curYear := year-from-date(current-date())

  (: Subtract Age from CurrentYear to Get BirthYear :)
  return $curYear - $age
};

(: END OF MODULE :)


File is no longer used.

File is no longer used.

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

xquery version "1.0";

(: $Id$ :)
declare namespace f="http://exist-db.org/xquery/local-functions";
declare namespace dc="http://purl.org/dc/elements/1.1/";

import module namespace xdb="http://exist-db.org/xquery/xmldb";

declare option exist:serialize "media-type=text/xml";

let $col := xdb:create-collection("/db", "rss")
let $rssUri := xs:anyURI("http://wiki.exist-db.org/exec/rss?snip=start")
let $stored := util:catch("java.lang.Exception",
                   xdb:store($col, "news.rss", $rssUri, "text/xml"),
                   ()
               )
return
    if ($stored) then

        {
            for $item in doc($stored)//item
            return (

                    {substring($item/dc:date, 1, 10)}

,

                {$item/title/text()}
            )
        }

    else

Failed to load news from Wiki...