xquery version "1.0"; declare namespace session="http://exist-db.org/xquery/session"; declare namespace request="http://exist-db.org/xquery/request"; declare namespace util="http://exist-db.org/xquery/util"; declare namespace i18n="http://apache.org/cocoon/i18n/2.1"; import module namespace ristenutil="http://www.risten.no/shared/util" at "../xquery/ristenutil.xqm"; (: Map query field parameter to xpath selection :) declare function local:query-field($field as xs:string) as xs:string { if ($field = "head") then "common/head" else if ($field = "def") then "senses/sense/def" else "." }; (: Create filter expression from query term, field and mode, and add a classification filter if specified :) declare function local:filter-expr($term as xs:string, $field as xs:string, $mode as xs:string) as xs:string { let $class := request:get-parameter("class", "all") let $c := if ($class = 'all') then ".//@top &= '*'" else if (contains($class, '-') ) then concat(".//@botm &= '", substring-after($class, '-'), "'" ) else if ( string-length($class) = 1) then concat(".//@top &= '", $class, "'" ) else concat(".//@mid &= '", $class, "'" ) let $f := local:query-field($field), $t := concat("'", $term, "'"), $t2 := replace($term,"\?",".?"), $t3 := replace($t2,"\*",".*"), $t4 := replace($t3,"\(","\("), $t5 := replace($t4,"\)","\)"), $ttrad := concat("'^", $t5, "$'") let $termsearch := if ($mode = "trad") then concat("matches(", $f, ", ", $ttrad, ")") else if ($mode = "near") then concat("near(", $f, ", ", $t, ")") else if ($mode = "exact") then concat($f, " = ", $t) else concat($f, " &= ", $t) return (: Removed the condition $term = '*', since querying the entire db seems acceptably fast - orig. condition was: $term = '*' or $term = '' :) if ($term = '' ) then $c else if ( $class = 'all') then $termsearch else concat($termsearch, " and ", $c) }; (: Map order parameter to xpath for order by clause :) (: Since the ordering element is not selectable, this function does not make any sense any more, but I'll keep it for now just in case. :) declare function local:order-expr($field as xs:string) as xs:string { if ($field = "head") then "common/head" else "common/qa, $r/common/head" }; (: Build the list of documents to search based on language selection:) declare function local:doc-expr($docpref as xs:string, $srchlang as xs:string) as xs:string { let $termpref := "terms-", $fileext := ".xml", $docs := if ($srchlang = "all") then concat ( "'", $docpref, $termpref, "lat", $fileext,"',", "'", $docpref, $termpref, "sme", $fileext,"',", "'", $docpref, $termpref, "sma", $fileext,"',", "'", $docpref, $termpref, "smj", $fileext,"',", "'", $docpref, $termpref, "nor", $fileext,"'" ) else for $lang in tokenize($srchlang, " ") (: Does not return multiple values yet, don't know why - the search form has been changed similarly to only allow single selections: all languages or one. :) return concat("'",$docpref,'/',$termpref,$lang,$fileext,"'") return $docs }; (: Assemble the query string :) declare function local:build-query($docpref as xs:string, $srchlang as xs:string+, $class as xs:string, $term as xs:string, $orderby as xs:string) as xs:string { let $field := request:get-parameter("field", "any"), $mode := request:get-parameter("mode", "all"), $expr := local:filter-expr($term, $field, $mode), $t := session:set-attribute("query", $expr) return if ($srchlang = "all") then concat("for $r in xcollection('", $docpref, "')//entry[", $expr, "] order by $r/", local:order-expr($orderby), " collation '?lang=sme-SE' return $r") else (: The next line is commented out since it does not express the intention: the possibility to search a selected list of languages. The HTML form is artificially limited to select only one language until we are ready to build a proper search expression for a number of languages. :) (: for $lang in $srchlang :) let $doc := ristenutil:get-doc($srchlang), $query := concat("for $r in document('", $doc, "')//entry[", $expr, "] order by $r/", local:order-expr($orderby), " collation '?lang=sme-SE' return $r") return $query }; (: Present an overview of query results :) declare function local:displayHitlist($hits as node()+) as element() { let $count := count($hits), $max := request:get-parameter("howmany", "10") cast as xs:int, $start := request:get-parameter("start", "1") cast as xs:int, $end := if ($start + $max - 1 < $count) then $start + $max - 1 else $count let $c1 := request:get-parameter("class", "all"), $c2 := session:get-attribute("class"), $class := if ( $c1 ) then $c1 else $c2, $topc := substring($class, 1, 1), $midc := if (string-length($class) > 1 and $class != 'all') then substring($class, 1, 5) else "", $botmc := if (contains($class, '-') ) then substring-after($class, '-') else "" let $coll := tokenize(util:collection-name(item-at($hits, 1)), "/") [last()] return { for $p in $start to $end let $current := item-at($hits, $p) let $id := $current/@id let $head := $current/common/head return for $s in $current/senses/sense let $status := $s/@status (: Get collection path for current item, and extract the last part of the path = collection ID :) (: let $coll := tokenize(util:collection-name($s) ,'/') [last()] :) order by $status return (: Pseudo: return if either all classes, or if the lowest class given matches: :) if ($class = 'all' or ($botmc != "" and $botmc = $s//@botm) or ($botmc = "" and $midc != "" and $midc = $s//@mid) or ($botmc = "" and $midc = "" and $topc = $s//@top) ) then {$head} else () } }; (: Main function - retrieves some request and session attributes, forks further processing to other defined functions depending on the retrieved values :) declare function local:main() as element()+ { let $term := request:get-parameter("term", "test*"), $class := request:get-parameter("class", "all") (: DEBUG ONLY: :) , $srchlang := request:get-parameter("showlang","all"), $docpref := request:get-parameter("srchcoll","all"), $coll := request:get-parameter("coll","all"), $params := request:get-parameter-names() (: let $coll := for $r in /termmeta util:collection-name($r) :) return

Parameters: {$params}
Term: {$term}
Selection: {$coll}
Search collection: {$docpref}

(: if ($docpref = "all") then for $r in /termmeta let $coll := util:collection-name($r) let $query := local:build-query($coll, $srchlang, $class, $term, "head" :) (: return local:displayResult($query, $term, $class) :) (: DEBUG version: :) (: return local:displayResult($query, $term, $class, $srchlang, $testdocs) else let $query := local:build-query($docpref, tokenize($srchlang, "m"), $class, $term, "head" :) (: return local:displayResult($query, $term, $class) :) (: DEBUG version: :) (: return local:displayResult($query, $term, $class, $srchlang, $testdocs :) }; declare function local:displayResult($query as xs:string, $term as xs:string, $class as xs:string (: Uncomment for DEBUGing: :) , $srchlang as xs:string, $testdocs as xs:string ) as element()+ { let $previous := session:get-attribute("results"), $queryOld := session:get-attribute("query"), $session := session:get-attribute-names() return if(string-length($term) = 0 and string-length($class) = 0) then if (exists($previous)) then local:displayHitlist($previous) else

Your query has timed out. Please hit «Find» or enter a new search query.

else let $hits := util:eval( $query ), $s := session:set-attribute("results", $hits), $t := session:set-attribute("class", $class) return if (empty($hits)) then (

NoHit «{$term}»!

(: DEBUG only - output some extra info ,

Your document string: {$testdocs}
Your $lang string: {$srchlang}
Your $class string: {$class}
Your session attributes: {$session}
Your query filter/old query:
{$queryOld}
Your complete search query:
{$query}

:) ) else ( (: DEBUG only - output some extra info :) (:

Your document string: {$testdocs}
Your $lang string: {$srchlang}
Your $class string: {$class}
Your session attributes: {$session}
Your query filter/old query:
{$queryOld}
Your complete search query:
{$query}

, :)

UrSrchTrm: «{$term}»

, local:displayHitlist($hits) ) }; let $coll := tokenize(request:get-parameter("srchcoll","all"),'/')[last()] return
{ let $start := util:system-time() return ( local:main(),

SearchTime { round-half-to-even( seconds-from-duration( util:system-time()-$start) , 3)}

) }