最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

SOLVED - How to organize general search results in alphabetical order - Xquery, XMLTEI, Tei Publisher? - Stack Overflow

programmeradmin5浏览0评论

I'm coding on a project to digitize historical texts using the XML/TEI language. The texts are published on the tei-publisher plattform. There are two types of search on the platform: faceted search and general search. When searching by facet, the results are presented by article, in alphabetical order. However, when you general search , the results appear in a random order, as shown in the image. I would like the results to appear in alphabetical order and if there are more answers per text, then they should be anized by div

Initially, I was changing this line in the search.xql file, but I noticed that any change I make to this line, the search results remain unchanged.

let $hitsAll :=
                (:If the $query-scope is narrow, query the elements immediately below the lowest div in tei:text and the four major element below tei:teiHeader.:)
                for $hit in query:query-default($request?parameters?field, $request?parameters?query, $request?parameters?doc,()) 
                order by xs:string($hit/title) ascending [I changed this line. I added this command]
                return $hit 

Perhaps I need to make a change to some other file responsible for searches, such as query.xql, navigation.xql or query-tei.xql, but I don't know how to make this change. Any help would be appreciated.

Below are the files I'm using, as well as the structure of the xml file. Thank you very much.

search.xql

xquery version "3.1";

module namespace sapi=";;

import module namespace query="; at "../../query.xql";
import module namespace nav="; at "../../navigation.xql";
import module namespace config="; at "../../config.xqm";
import module namespace tpu="; at "../util.xql";
import module namespace kwic="; at "resource:/exist/xquery/lib/kwic.xql";
import module namespace facets="; at "../../facets.xql";


declare namespace tei=".0";





declare function sapi:autocomplete($request as map(*)) {
    let $q := request:get-parameter("query", ())
    let $type := request:get-parameter("field", "text")
    let $doc := request:get-parameter("doc", ())
    let $items :=
        if ($q) then
            query:autocomplete($doc, $type, $q)
        else
            ()
    return
        array {
            for $item in $items
            group by $item
            return
                map {
                    "text": $item,
                    "value": $item
                }
        }
};

declare function sapi:search($request as map(*)) {
    (:If there is no query string, fill up the map with existing values:)
    if (empty($request?parameters?query))
    then
        sapi:show-hits($request, session:get-attribute($config:session-prefix || ".hits"), session:get-attribute($config:session-prefix || ".docs"))
    else
        (:Otherwise, perform the query.:)
        (: Here the actual query commences. This is split into two parts, the first for a Lucene query and the second for an ngram query. :)
        (:The query passed to a Luecene query in ft:query is an XML element <query> containing one or two <bool>. The <bool> contain the original query and the transliterated query, as indicated by the user in $query-scripts.:)
        let $hitsAll :=
                (:If the $query-scope is narrow, query the elements immediately below the lowest div in tei:text and the four major element below tei:teiHeader.:)
                for $hit in query:query-default($request?parameters?field, $request?parameters?query, $request?parameters?doc,()) (: aqui que é o anizador :)
                order by xs:string($hit/title) ascending
                return $hit 

        let $hitCount := count($hitsAll)
        let $hits := if ($hitCount > 1000) then subsequence($hitsAll, 1, 1000) else $hitsAll
        (:Store the result in the session.:)
        let $store := (
            session:set-attribute($config:session-prefix || ".hits", $hitsAll),
            session:set-attribute($config:session-prefix || ".hitCount", $hitCount),
            session:set-attribute($config:session-prefix || ".search", $request?parameters?query),
            session:set-attribute($config:session-prefix || ".field", $request?parameters?field),
            session:set-attribute($config:session-prefix || ".docs", $request?parameters?doc)
            
 )
        return
            sapi:show-hits($request, $hits, $request?parameters?doc )
};

declare %private function sapi:show-hits($request as map(*), $hits as item()*, $docs as xs:string*) {
    response:set-header("pb-total", xs:string(count($hits))),
    response:set-header("pb-start", xs:string($request?parameters?start)),
    for $hit at $p in subsequence($hits, $request?parameters?start, $request?parameters?per-page)
    let $config := tpu:parse-pi(root($hit), $request?parameters?view)
    let $parent := query:get-parent-section($config, $hit)
    let $parent-id := config:get-identifier($parent)
    let $parent-id := if (exists($docs)) then replace($parent-id, "^.*?([^/]*)$", "$1") else $parent-id
    let $div := query:get-current($config, $parent)
    let $expanded := util:expand($hit, "add-exist-id=all")
    let $docId := config:get-identifier($div)
    return
        <paper-card>
            <header>
                <div class="count">{$request?parameters?start + $p - 1}</div>
                { query:get-breadcrumbs($config, $hit, $parent-id) }
            </header>
            <div class="matches">
            {
                for $match in subsequence($expanded//exist:match, 1, 5)
                let $matchId := $match/../@exist:id
                let $docLink :=
                    if ($config?view = "page") then
                        (: first check if there's a pb in the expanded section before the match :)
                        let $pbBefore := $match/preceding::tei:pb[1]
                        return
                            if ($pbBefore) then
                                $pbBefore/@exist:id
                            else
                                (: no: locate the element containing the match in the source document :)
                                let $contextNode := util:node-by-id($hit, $matchId)
                                (: and get the pb preceding it :)
                                let $page := $contextNode/preceding::tei:pb[1]
                                return
                                    if ($page) then
                                        util:node-id($page)
                                    else
                                        util:node-id($div)
                    else
                        (: Check if the document has sections, otherwise don't pass root :)
                        if (nav:get-section-for-node($config, $div)) then util:node-id($div) else ()
                let $config := <config width="60" table="no" link="{$docId}?{if ($docLink) then 'root=' || $docLink || '&amp;' else ()}action=search&amp;view={$config?view}&amp;odd={$config?odd}#{$matchId}"/>
                return
                    kwic:get-summary($expanded, $match, $config)
            }
            </div>
        </paper-card>
};

declare function sapi:facets($request as map(*)) {
    
    let $hits := session:get-attribute($config:session-prefix || ".hits")
    where count($hits) > 0
    return
        <div>
        {
            for $config in $config:facets?*
            return
                facets:display($config, $hits)
        }
        </div>
};

declare function sapi:list-facets($request as map(*)) {
    let $type := $request?parameters?type
    let $lang := tokenize($request?parameters?language, '-')[1]
    let $facetConfig := filter($config:facets?*, function($facetCfg) {
        $facetCfg?dimension = $type
    })
    let $hits := session:get-attribute($config:session-prefix || ".hits")
    let $facets := ft:facets($hits, $type, ())
    let $matches := 
        for $key in if (exists($request?parameters?value)) then $request?parameters?value else map:keys($facets)
        let $label := facets:translate($facetConfig, $lang, $key)
        return 
            map {
                "text": $label,
                "freq": $facets($key),
                "value": $key
            } 
           
    let $filtered := filter($matches, function($item) {
        matches($item?text, '(?:^|\W)' || $request?parameters?query, 'i')
    })
    return
        array { $filtered }
};

query.xql

(:
 :  Copyright (C) 2017 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see </>.
 :)
xquery version "3.1";

module namespace query=";;

import module namespace tei-query="; at "query-tei.xql";
import module namespace docbook-query="; at "query-db.xql";
import module namespace jats-query="; at "query-jats.xql";
import module namespace config="; at "config.xqm";
import module namespace nav="; at "navigation.xql";
declare namespace tei=".0";

declare variable $query:QUERY_OPTIONS := map {
    "leading-wildcard": "yes",
    "filter-rewrite": "yes"
};

declare function query:field-prefix($elem as element()) {
    switch (namespace-uri($elem))
        case ".0" return
            ""
        case "; return
            "dbk."
        default return
            "jats."
};

declare %private function query:sort($items as element()*, $sortBy as xs:string?) {
    let $items :=
        if (exists($config:data-exclude)) then
            $items except $config:data-exclude
        else
            $items
    return
        if ($sortBy) then
            nav:sort($sortBy, $items)
        else
            $items
};

declare %private function query:dispatch($config as map(*), $function as xs:string, $args as array(*)) {
    let $fn := function-lookup(xs:QName($config?type || "-query:" || $function), array:size($args))
    return
        if (exists($fn)) then
            apply($fn, $args)
        else
            ()
};

(:~
 : Query the data set.
 :
 : @param $fields a sequence of field names describing the type of content to query,
 :  e.g. "heading" or "text"
 : @param $query the query string
 : @param $target-texts a sequence of identifiers for texts to query. May be empty.
 :)
declare function query:query-default($fields as xs:string+, $query as xs:string,
    $target-texts as xs:string*, $sortBy as xs:string*) {
    tei-query:query-default($fields, $query, $target-texts, $sortBy),
    docbook-query:query-default($fields, $query, $target-texts, $sortBy),
    jats-query:query-default($fields, $query, $target-texts, $sortBy)
};



(: declare function query:query-default($fields as xs:string+, $query as xs:string,
 $target-texts as xs:string*, $sortBy as xs:string*) {
 let $sortBy := xs:integer($sortBy)
 return (
  tei-query:query-default($fields, $query, $target-texts, $sortBy),
  docbook-query:query-default($fields, $query, $target-texts, $sortBy),
  jats-query:query-default($fields, $query, $target-texts, $sortBy)
 )
}; :)

declare function query:options($sortBy as xs:string*) {
    query:options($sortBy, ())
};

declare function query:options($sortBy as xs:string*, $field as xs:string?) {
    map:merge((
        $query:QUERY_OPTIONS,
        map {
            "facets":
                map:merge((
                    for $param in request:get-parameter-names()[starts-with(., 'facet-')]
                    let $dimension := substring-after($param, 'facet-')
                    return
                        map {
                            $dimension: request:get-parameter($param, ())
                        }
                ))
        },
        if ($sortBy) then
            map { "fields": ($sortBy, $config:default-fields, $field) }
        else
            map { "fields": ($config:default-fields, $field) }
    ))
};

declare function query:query-metadata($root as xs:string?, $field as xs:string?, $query as xs:string?, $sort as xs:string) {
    let $results := (
        tei-query:query-metadata($root, $field, $query, $sort) |
        docbook-query:query-metadata($root, $field, $query, $sort) |
        jats-query:query-metadata($root, $field, $query, $sort)
    )
    let $mode := 
        if ((empty($query) or $query = '') and empty(request:get-parameter-names()[starts-with(., 'facet-')])) then 
            "browse"
        else 
            "search"
    return map {
        "all": $results,
        "mode": $mode
    }
};

declare function query:get-parent-section($config as map(*), $node as node()) {
    query:dispatch($config, "get-parent-section", [$node])
};

declare function query:get-breadcrumbs($config as map(*), $hit as node(), $parent-id as xs:string) {
    query:dispatch($config, "get-breadcrumbs", [$config, $hit, $parent-id])
};

declare function query:expand($config as map(*), $data as node()) {
    query:dispatch($config, "expand", [$data])
};

declare function query:get-current($config as map(*), $div as node()?) {
    query:dispatch($config, "get-current", [$config, $div])
};

declare function query:autocomplete($doc as xs:string?, $fields as xs:string+, $q as xs:string) {
    tei-query:autocomplete($doc, $fields, $q),
    docbook-query:autocomplete($doc, $fields, $q),
    jats-query:autocomplete($doc, $fields, $q)
};

navigation.xql

(:
 :
 :  Copyright (C) 2017 TEI Publisher Project
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see </>.
 :)
xquery version "3.1";

module namespace nav=";;

import module namespace config="; at "config.xqm";
import module namespace tei-nav="; at "navigation-tei.xql";
import module namespace jats-nav="; at "navigation-jats.xql";
import module namespace docbook-nav="; at "navigation-dbk.xql";

declare %private function nav:dispatch($config as map(*), $function as xs:string, $args as array(*)) {
    let $fn := function-lookup(xs:QName($config?type || "-nav:" || $function), array:size($args))
    return
        if (exists($fn)) then
            apply($fn, $args)
        else
            ()
};

declare function nav:get-root($root as xs:string?, $options as map(*)?) {
    tei-nav:get-root($root, $options),
    docbook-nav:get-root($root, $options),
    jats-nav:get-root($root, $options)
};

declare function nav:get-header($config as map(*), $node as element()) {
    nav:dispatch($config, "get-header", [$config, $node])
};

declare function nav:get-section-for-node($config as map(*), $node as element()) {
    nav:dispatch($config, "get-section-for-node", [$config, $node])
};

declare function nav:get-section($config as map(*), $doc as node()) {
    nav:dispatch($config, "get-section", [$config, $doc])
};

declare function nav:get-metadata($root as element(), $field as xs:string) {
    nav:get-metadata(map { "type": config:document-type($root) }, $root, $field)
};

declare function nav:get-metadata($config as map(*), $root as element(), $field as xs:string) {
    nav:dispatch($config, "get-metadata", [$config, $root, $field])
};

declare function nav:get-document-title($config as map(*), $root as element()) {
    nav:dispatch($config, "get-document-title", [$config, $root])
};

declare function nav:get-subsections($config as map(*), $root as node()) {
    nav:dispatch($config, "get-subsections", [$config, $root])
};

declare function nav:get-section-heading($config as map(*), $section as node()) {
    nav:dispatch($config, "get-section-heading", [$config, $section])
};

declare function nav:get-first-page-start($config as map(*), $data as node()) {
    nav:dispatch($config, "get-first-page-start", [$config, $data])
};

declare function nav:sort($sortBy as xs:string, $items as element()*) {
    if (empty($items)) then
        ()
    else
        nav:dispatch(map { "type": config:document-type(head($items)) }, "sort", [$sortBy, $items])
};

declare function nav:get-content($config as map(*), $div as element()) {
    nav:dispatch($config, "get-content", [$config, $div])
};

declare function nav:get-next($config as map(*), $div as element(), $view as xs:string) {
    nav:dispatch($config, "get-next", [$config, $div, $view])
};

declare function nav:get-previous($config as map(*), $div as element(), $view as xs:string) {
    nav:dispatch($config, "get-previous", [$config, $div, $view])
};

declare function nav:filler($config as map(*), $div as element()?) {
    nav:dispatch($config, "filler", [$config, $div])
};

declare function nav:is-filler($config as map(*), $div) {
    nav:dispatch($config, "is-filler", [$config, $div])
};

declare function nav:output-footnotes($footnotes as element()*) {
    <div class="popovers">
    {
        $footnotes/self::pb-popover
    }
    </div>,
    <div class="footnotes">
    {
        $footnotes[not(self::pb-popover)]
    }
    </div>
};

query-tei.xql

(:
 :
 :  Copyright (C) 2017 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see </>.
 :)
xquery version "3.1";

module namespace teis=";;

declare namespace tei=".0";

import module namespace config="; at "config.xqm";
import module namespace nav="; at "navigation-tei.xql";
import module namespace query="; at "query.xql";

declare function teis:query-default($fields as xs:string+, $query as xs:string, $target-texts as xs:string*,
    $sortBy as xs:string*) {
    if(string($query)) then
        for $field in $fields
        return
            switch ($field)
                case "head" return
                    if (exists($target-texts)) then
                        for $text in $target-texts
                        return
                            $config:data-root ! doc(. || "/" || $text)//tei:head[ft:query(., $query, query:options($sortBy))]
                    else
                        collection($config:data-root)//tei:head[ft:query(., $query, query:options($sortBy))]
                default return
                    if (exists($target-texts)) then
                        for $text in $target-texts
                        let $divisions := $config:data-root ! doc(. || "/" || $text)//tei:div[ft:query(., $query, query:options($sortBy))]
                        return
                            if (empty($divisions)) then
                                $config:data-root ! doc(. || "/" || $text)//tei:text[ft:query(., $query, query:options($sortBy))]
                            else
                                $divisions
                    else
                        let $divisions := collection($config:data-root)//tei:div[ft:query(., $query, query:options($sortBy))]
                        return
                            if (empty($divisions)) then
                                collection($config:data-root)//tei:text[ft:query(., $query, query:options($sortBy))]
                            else
                                $divisions
    else ()
    
    
};

declare function teis:query-metadata($path as xs:string?, $field as xs:string?, $query as xs:string?, $sort as xs:string) {
    let $queryExpr := 
        if ($field = "file" or empty($query) or $query = '') then 
            "file:*" 
        else
            ($field, "text")[1] || ":" || $query
    let $options := query:options($sort, ($field, "text")[1])
    let $result :=
        $config:data-default ! (
            collection(. || "/" || $path)//tei:text[ft:query(., $queryExpr, $options)]
        )
    return
        query:sort($result, $sort)
};

declare function teis:autocomplete($doc as xs:string?, $fields as xs:string+, $q as xs:string) {
    let $lower-case-q := lower-case($q)
    for $field in $fields
    return
        switch ($field)
            case "author" return
                collection($config:data-root)/ft:index-keys-for-field("author", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
            case "file" return
                collection($config:data-root)/ft:index-keys-for-field("file", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
            case "text" return
                if ($doc) then (
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:div"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index"),
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:text"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                ) else (
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:div"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index"),
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:text"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                )
            case "head" return
                if ($doc) then
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:head"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                else
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:head"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
            default return
                collection($config:data-root)/ft:index-keys-for-field("title", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
};

declare function teis:get-parent-section($node as node()) {
    ($node/self::tei:text, $node/ancestor-or-self::tei:div[1], $node)[1]
};

declare function teis:get-breadcrumbs($config as map(*), $hit as node(), $parent-id as xs:string) {
    let $work := root($hit)/*
    let $work-title := nav:get-document-title($config, $work)/string()
    return
        <div class="breadcrumbs">
            <a class="breadcrumb" href="{$parent-id}">{$work-title}</a>
            {
                for $parentDiv in $hit/ancestor-or-self::tei:div[tei:head]
                let $id := util:node-id(
                    if ($config?view = "page") then ($parentDiv/preceding::tei:pb[1], $parentDiv)[1] else $parentDiv
                )
                return
                    <a class="breadcrumb" href="{$parent-id || "?action=search&amp;root=" || $id || "&amp;view=" || $config?view || "&amp;odd=" || $config?odd}">
                    {$parentDiv/tei:head/string()}
                    </a>
            }
        </div>
};

(:~
 : Expand the given element and highlight query matches by re-running the query
 : on it.
 :)
declare function teis:expand($data as node()) {
    let $query := session:get-attribute($config:session-prefix || ".search")
    let $field := session:get-attribute($config:session-prefix || ".field")
    let $div :=
        if ($data instance of element(tei:pb)) then
            let $nextPage := $data/following::tei:pb[1]
            return
                if ($nextPage) then
                    if ($field = "text") then
                        (
                            ($data/ancestor::tei:div intersect $nextPage/ancestor::tei:div)[last()],
                            $data/ancestor::tei:text
                        )[1]
                    else
                        $data/ancestor::tei:text
                else
                    (: if there's only one pb in the document, it's whole
                      text part should be returned :)
                    if (count($data/ancestor::tei:text//tei:pb) = 1) then
                        ($data/ancestor::tei:text)
                    else
                      ($data/ancestor::tei:div, $data/ancestor::tei:text)[1]
        else
            $data
    let $result := teis:query-default-view($div, $query, $field)
    let $expanded :=
        if (exists($result)) then
            util:expand($result, "add-exist-id=all")
        else
            $div
    return
        if ($data instance of element(tei:pb)) then
            $expanded//tei:pb[@exist:id = util:node-id($data)]
        else
            $expanded
};


declare function teis:query-default-view($context as element()*, $query as xs:string, $fields as xs:string+) {
    for $field in $fields
    return
        switch ($field)
            case "head" return
                $context[./descendant-or-self::tei:head[ft:query(., $query, $query:QUERY_OPTIONS)]]
            default return
                $context[./descendant-or-self::tei:div[ft:query(., $query, $query:QUERY_OPTIONS)]] |
                $context[./descendant-or-self::tei:text[ft:query(., $query, $query:QUERY_OPTIONS)]]
};

declare function teis:get-current($config as map(*), $div as node()?) {
    if (empty($div)) then
        ()
    else
        if ($div instance of element(tei:teiHeader)) then
            $div
        else
            (nav:filler($config, $div), $div)[1]
};

xml-file:

<TEI xmlns=".0" xml:id="DCH_Abogados" rendition="tei:teisimple"
    xml:lang="es">
    <teiHeader xml:lang="en">
        <fileDesc>
            <titleStmt>
                <title>Abogados (DCH)</title>
...

<body>
            <div n="1">
                <head>1. Introducción</head>
                <p>Para las <name type="place">Indias</name>, la definición de <term xml:lang="es">
                    abogado</term>, sus cualidades y requisitos, venía resuelta por la larga
                    tradición del <rs xml:lang="la">ius commune</rs>

the results appear in random order

The entire platform project is in this repository []. My specific project has a few changes, but in general it is very similar to the matri code.

I'm coding on a project to digitize historical texts using the XML/TEI language. The texts are published on the tei-publisher plattform. There are two types of search on the platform: faceted search and general search. When searching by facet, the results are presented by article, in alphabetical order. However, when you general search , the results appear in a random order, as shown in the image. I would like the results to appear in alphabetical order and if there are more answers per text, then they should be anized by div

Initially, I was changing this line in the search.xql file, but I noticed that any change I make to this line, the search results remain unchanged.

let $hitsAll :=
                (:If the $query-scope is narrow, query the elements immediately below the lowest div in tei:text and the four major element below tei:teiHeader.:)
                for $hit in query:query-default($request?parameters?field, $request?parameters?query, $request?parameters?doc,()) 
                order by xs:string($hit/title) ascending [I changed this line. I added this command]
                return $hit 

Perhaps I need to make a change to some other file responsible for searches, such as query.xql, navigation.xql or query-tei.xql, but I don't know how to make this change. Any help would be appreciated.

Below are the files I'm using, as well as the structure of the xml file. Thank you very much.

search.xql

xquery version "3.1";

module namespace sapi="http://teipublisher/api/search";

import module namespace query="http://www.tei-c./tei-simple/query" at "../../query.xql";
import module namespace nav="http://www.tei-c./tei-simple/navigation" at "../../navigation.xql";
import module namespace config="http://www.tei-c./tei-simple/config" at "../../config.xqm";
import module namespace tpu="http://www.tei-c./tei-publisher/util" at "../util.xql";
import module namespace kwic="http://exist-db./xquery/kwic" at "resource:/exist/xquery/lib/kwic.xql";
import module namespace facets="http://teipublisher/facets" at "../../facets.xql";


declare namespace tei="http://www.tei-c./ns/1.0";





declare function sapi:autocomplete($request as map(*)) {
    let $q := request:get-parameter("query", ())
    let $type := request:get-parameter("field", "text")
    let $doc := request:get-parameter("doc", ())
    let $items :=
        if ($q) then
            query:autocomplete($doc, $type, $q)
        else
            ()
    return
        array {
            for $item in $items
            group by $item
            return
                map {
                    "text": $item,
                    "value": $item
                }
        }
};

declare function sapi:search($request as map(*)) {
    (:If there is no query string, fill up the map with existing values:)
    if (empty($request?parameters?query))
    then
        sapi:show-hits($request, session:get-attribute($config:session-prefix || ".hits"), session:get-attribute($config:session-prefix || ".docs"))
    else
        (:Otherwise, perform the query.:)
        (: Here the actual query commences. This is split into two parts, the first for a Lucene query and the second for an ngram query. :)
        (:The query passed to a Luecene query in ft:query is an XML element <query> containing one or two <bool>. The <bool> contain the original query and the transliterated query, as indicated by the user in $query-scripts.:)
        let $hitsAll :=
                (:If the $query-scope is narrow, query the elements immediately below the lowest div in tei:text and the four major element below tei:teiHeader.:)
                for $hit in query:query-default($request?parameters?field, $request?parameters?query, $request?parameters?doc,()) (: aqui que é o anizador :)
                order by xs:string($hit/title) ascending
                return $hit 

        let $hitCount := count($hitsAll)
        let $hits := if ($hitCount > 1000) then subsequence($hitsAll, 1, 1000) else $hitsAll
        (:Store the result in the session.:)
        let $store := (
            session:set-attribute($config:session-prefix || ".hits", $hitsAll),
            session:set-attribute($config:session-prefix || ".hitCount", $hitCount),
            session:set-attribute($config:session-prefix || ".search", $request?parameters?query),
            session:set-attribute($config:session-prefix || ".field", $request?parameters?field),
            session:set-attribute($config:session-prefix || ".docs", $request?parameters?doc)
            
 )
        return
            sapi:show-hits($request, $hits, $request?parameters?doc )
};

declare %private function sapi:show-hits($request as map(*), $hits as item()*, $docs as xs:string*) {
    response:set-header("pb-total", xs:string(count($hits))),
    response:set-header("pb-start", xs:string($request?parameters?start)),
    for $hit at $p in subsequence($hits, $request?parameters?start, $request?parameters?per-page)
    let $config := tpu:parse-pi(root($hit), $request?parameters?view)
    let $parent := query:get-parent-section($config, $hit)
    let $parent-id := config:get-identifier($parent)
    let $parent-id := if (exists($docs)) then replace($parent-id, "^.*?([^/]*)$", "$1") else $parent-id
    let $div := query:get-current($config, $parent)
    let $expanded := util:expand($hit, "add-exist-id=all")
    let $docId := config:get-identifier($div)
    return
        <paper-card>
            <header>
                <div class="count">{$request?parameters?start + $p - 1}</div>
                { query:get-breadcrumbs($config, $hit, $parent-id) }
            </header>
            <div class="matches">
            {
                for $match in subsequence($expanded//exist:match, 1, 5)
                let $matchId := $match/../@exist:id
                let $docLink :=
                    if ($config?view = "page") then
                        (: first check if there's a pb in the expanded section before the match :)
                        let $pbBefore := $match/preceding::tei:pb[1]
                        return
                            if ($pbBefore) then
                                $pbBefore/@exist:id
                            else
                                (: no: locate the element containing the match in the source document :)
                                let $contextNode := util:node-by-id($hit, $matchId)
                                (: and get the pb preceding it :)
                                let $page := $contextNode/preceding::tei:pb[1]
                                return
                                    if ($page) then
                                        util:node-id($page)
                                    else
                                        util:node-id($div)
                    else
                        (: Check if the document has sections, otherwise don't pass root :)
                        if (nav:get-section-for-node($config, $div)) then util:node-id($div) else ()
                let $config := <config width="60" table="no" link="{$docId}?{if ($docLink) then 'root=' || $docLink || '&amp;' else ()}action=search&amp;view={$config?view}&amp;odd={$config?odd}#{$matchId}"/>
                return
                    kwic:get-summary($expanded, $match, $config)
            }
            </div>
        </paper-card>
};

declare function sapi:facets($request as map(*)) {
    
    let $hits := session:get-attribute($config:session-prefix || ".hits")
    where count($hits) > 0
    return
        <div>
        {
            for $config in $config:facets?*
            return
                facets:display($config, $hits)
        }
        </div>
};

declare function sapi:list-facets($request as map(*)) {
    let $type := $request?parameters?type
    let $lang := tokenize($request?parameters?language, '-')[1]
    let $facetConfig := filter($config:facets?*, function($facetCfg) {
        $facetCfg?dimension = $type
    })
    let $hits := session:get-attribute($config:session-prefix || ".hits")
    let $facets := ft:facets($hits, $type, ())
    let $matches := 
        for $key in if (exists($request?parameters?value)) then $request?parameters?value else map:keys($facets)
        let $label := facets:translate($facetConfig, $lang, $key)
        return 
            map {
                "text": $label,
                "freq": $facets($key),
                "value": $key
            } 
           
    let $filtered := filter($matches, function($item) {
        matches($item?text, '(?:^|\W)' || $request?parameters?query, 'i')
    })
    return
        array { $filtered }
};

query.xql

(:
 :  Copyright (C) 2017 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see <http://www.gnu./licenses/>.
 :)
xquery version "3.1";

module namespace query="http://www.tei-c./tei-simple/query";

import module namespace tei-query="http://www.tei-c./tei-simple/query/tei" at "query-tei.xql";
import module namespace docbook-query="http://www.tei-c./tei-simple/query/docbook" at "query-db.xql";
import module namespace jats-query="http://www.tei-c./tei-simple/query/jats" at "query-jats.xql";
import module namespace config="http://www.tei-c./tei-simple/config" at "config.xqm";
import module namespace nav="http://www.tei-c./tei-simple/navigation" at "navigation.xql";
declare namespace tei="http://www.tei-c./ns/1.0";

declare variable $query:QUERY_OPTIONS := map {
    "leading-wildcard": "yes",
    "filter-rewrite": "yes"
};

declare function query:field-prefix($elem as element()) {
    switch (namespace-uri($elem))
        case "http://www.tei-c./ns/1.0" return
            ""
        case "http://docbook./ns/docbook" return
            "dbk."
        default return
            "jats."
};

declare %private function query:sort($items as element()*, $sortBy as xs:string?) {
    let $items :=
        if (exists($config:data-exclude)) then
            $items except $config:data-exclude
        else
            $items
    return
        if ($sortBy) then
            nav:sort($sortBy, $items)
        else
            $items
};

declare %private function query:dispatch($config as map(*), $function as xs:string, $args as array(*)) {
    let $fn := function-lookup(xs:QName($config?type || "-query:" || $function), array:size($args))
    return
        if (exists($fn)) then
            apply($fn, $args)
        else
            ()
};

(:~
 : Query the data set.
 :
 : @param $fields a sequence of field names describing the type of content to query,
 :  e.g. "heading" or "text"
 : @param $query the query string
 : @param $target-texts a sequence of identifiers for texts to query. May be empty.
 :)
declare function query:query-default($fields as xs:string+, $query as xs:string,
    $target-texts as xs:string*, $sortBy as xs:string*) {
    tei-query:query-default($fields, $query, $target-texts, $sortBy),
    docbook-query:query-default($fields, $query, $target-texts, $sortBy),
    jats-query:query-default($fields, $query, $target-texts, $sortBy)
};



(: declare function query:query-default($fields as xs:string+, $query as xs:string,
 $target-texts as xs:string*, $sortBy as xs:string*) {
 let $sortBy := xs:integer($sortBy)
 return (
  tei-query:query-default($fields, $query, $target-texts, $sortBy),
  docbook-query:query-default($fields, $query, $target-texts, $sortBy),
  jats-query:query-default($fields, $query, $target-texts, $sortBy)
 )
}; :)

declare function query:options($sortBy as xs:string*) {
    query:options($sortBy, ())
};

declare function query:options($sortBy as xs:string*, $field as xs:string?) {
    map:merge((
        $query:QUERY_OPTIONS,
        map {
            "facets":
                map:merge((
                    for $param in request:get-parameter-names()[starts-with(., 'facet-')]
                    let $dimension := substring-after($param, 'facet-')
                    return
                        map {
                            $dimension: request:get-parameter($param, ())
                        }
                ))
        },
        if ($sortBy) then
            map { "fields": ($sortBy, $config:default-fields, $field) }
        else
            map { "fields": ($config:default-fields, $field) }
    ))
};

declare function query:query-metadata($root as xs:string?, $field as xs:string?, $query as xs:string?, $sort as xs:string) {
    let $results := (
        tei-query:query-metadata($root, $field, $query, $sort) |
        docbook-query:query-metadata($root, $field, $query, $sort) |
        jats-query:query-metadata($root, $field, $query, $sort)
    )
    let $mode := 
        if ((empty($query) or $query = '') and empty(request:get-parameter-names()[starts-with(., 'facet-')])) then 
            "browse"
        else 
            "search"
    return map {
        "all": $results,
        "mode": $mode
    }
};

declare function query:get-parent-section($config as map(*), $node as node()) {
    query:dispatch($config, "get-parent-section", [$node])
};

declare function query:get-breadcrumbs($config as map(*), $hit as node(), $parent-id as xs:string) {
    query:dispatch($config, "get-breadcrumbs", [$config, $hit, $parent-id])
};

declare function query:expand($config as map(*), $data as node()) {
    query:dispatch($config, "expand", [$data])
};

declare function query:get-current($config as map(*), $div as node()?) {
    query:dispatch($config, "get-current", [$config, $div])
};

declare function query:autocomplete($doc as xs:string?, $fields as xs:string+, $q as xs:string) {
    tei-query:autocomplete($doc, $fields, $q),
    docbook-query:autocomplete($doc, $fields, $q),
    jats-query:autocomplete($doc, $fields, $q)
};

navigation.xql

(:
 :
 :  Copyright (C) 2017 TEI Publisher Project
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see <http://www.gnu./licenses/>.
 :)
xquery version "3.1";

module namespace nav="http://www.tei-c./tei-simple/navigation";

import module namespace config="http://www.tei-c./tei-simple/config" at "config.xqm";
import module namespace tei-nav="http://www.tei-c./tei-simple/navigation/tei" at "navigation-tei.xql";
import module namespace jats-nav="http://www.tei-c./tei-simple/navigation/jats" at "navigation-jats.xql";
import module namespace docbook-nav="http://www.tei-c./tei-simple/navigation/docbook" at "navigation-dbk.xql";

declare %private function nav:dispatch($config as map(*), $function as xs:string, $args as array(*)) {
    let $fn := function-lookup(xs:QName($config?type || "-nav:" || $function), array:size($args))
    return
        if (exists($fn)) then
            apply($fn, $args)
        else
            ()
};

declare function nav:get-root($root as xs:string?, $options as map(*)?) {
    tei-nav:get-root($root, $options),
    docbook-nav:get-root($root, $options),
    jats-nav:get-root($root, $options)
};

declare function nav:get-header($config as map(*), $node as element()) {
    nav:dispatch($config, "get-header", [$config, $node])
};

declare function nav:get-section-for-node($config as map(*), $node as element()) {
    nav:dispatch($config, "get-section-for-node", [$config, $node])
};

declare function nav:get-section($config as map(*), $doc as node()) {
    nav:dispatch($config, "get-section", [$config, $doc])
};

declare function nav:get-metadata($root as element(), $field as xs:string) {
    nav:get-metadata(map { "type": config:document-type($root) }, $root, $field)
};

declare function nav:get-metadata($config as map(*), $root as element(), $field as xs:string) {
    nav:dispatch($config, "get-metadata", [$config, $root, $field])
};

declare function nav:get-document-title($config as map(*), $root as element()) {
    nav:dispatch($config, "get-document-title", [$config, $root])
};

declare function nav:get-subsections($config as map(*), $root as node()) {
    nav:dispatch($config, "get-subsections", [$config, $root])
};

declare function nav:get-section-heading($config as map(*), $section as node()) {
    nav:dispatch($config, "get-section-heading", [$config, $section])
};

declare function nav:get-first-page-start($config as map(*), $data as node()) {
    nav:dispatch($config, "get-first-page-start", [$config, $data])
};

declare function nav:sort($sortBy as xs:string, $items as element()*) {
    if (empty($items)) then
        ()
    else
        nav:dispatch(map { "type": config:document-type(head($items)) }, "sort", [$sortBy, $items])
};

declare function nav:get-content($config as map(*), $div as element()) {
    nav:dispatch($config, "get-content", [$config, $div])
};

declare function nav:get-next($config as map(*), $div as element(), $view as xs:string) {
    nav:dispatch($config, "get-next", [$config, $div, $view])
};

declare function nav:get-previous($config as map(*), $div as element(), $view as xs:string) {
    nav:dispatch($config, "get-previous", [$config, $div, $view])
};

declare function nav:filler($config as map(*), $div as element()?) {
    nav:dispatch($config, "filler", [$config, $div])
};

declare function nav:is-filler($config as map(*), $div) {
    nav:dispatch($config, "is-filler", [$config, $div])
};

declare function nav:output-footnotes($footnotes as element()*) {
    <div class="popovers">
    {
        $footnotes/self::pb-popover
    }
    </div>,
    <div class="footnotes">
    {
        $footnotes[not(self::pb-popover)]
    }
    </div>
};

query-tei.xql

(:
 :
 :  Copyright (C) 2017 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 of the License, or
 :  (at your option) any later version.
 :
 :  This program is distributed in the hope that it will be useful,
 :  but WITHOUT ANY WARRANTY; without even the implied warranty of
 :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 :  GNU General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see <http://www.gnu./licenses/>.
 :)
xquery version "3.1";

module namespace teis="http://www.tei-c./tei-simple/query/tei";

declare namespace tei="http://www.tei-c./ns/1.0";

import module namespace config="http://www.tei-c./tei-simple/config" at "config.xqm";
import module namespace nav="http://www.tei-c./tei-simple/navigation/tei" at "navigation-tei.xql";
import module namespace query="http://www.tei-c./tei-simple/query" at "query.xql";

declare function teis:query-default($fields as xs:string+, $query as xs:string, $target-texts as xs:string*,
    $sortBy as xs:string*) {
    if(string($query)) then
        for $field in $fields
        return
            switch ($field)
                case "head" return
                    if (exists($target-texts)) then
                        for $text in $target-texts
                        return
                            $config:data-root ! doc(. || "/" || $text)//tei:head[ft:query(., $query, query:options($sortBy))]
                    else
                        collection($config:data-root)//tei:head[ft:query(., $query, query:options($sortBy))]
                default return
                    if (exists($target-texts)) then
                        for $text in $target-texts
                        let $divisions := $config:data-root ! doc(. || "/" || $text)//tei:div[ft:query(., $query, query:options($sortBy))]
                        return
                            if (empty($divisions)) then
                                $config:data-root ! doc(. || "/" || $text)//tei:text[ft:query(., $query, query:options($sortBy))]
                            else
                                $divisions
                    else
                        let $divisions := collection($config:data-root)//tei:div[ft:query(., $query, query:options($sortBy))]
                        return
                            if (empty($divisions)) then
                                collection($config:data-root)//tei:text[ft:query(., $query, query:options($sortBy))]
                            else
                                $divisions
    else ()
    
    
};

declare function teis:query-metadata($path as xs:string?, $field as xs:string?, $query as xs:string?, $sort as xs:string) {
    let $queryExpr := 
        if ($field = "file" or empty($query) or $query = '') then 
            "file:*" 
        else
            ($field, "text")[1] || ":" || $query
    let $options := query:options($sort, ($field, "text")[1])
    let $result :=
        $config:data-default ! (
            collection(. || "/" || $path)//tei:text[ft:query(., $queryExpr, $options)]
        )
    return
        query:sort($result, $sort)
};

declare function teis:autocomplete($doc as xs:string?, $fields as xs:string+, $q as xs:string) {
    let $lower-case-q := lower-case($q)
    for $field in $fields
    return
        switch ($field)
            case "author" return
                collection($config:data-root)/ft:index-keys-for-field("author", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
            case "file" return
                collection($config:data-root)/ft:index-keys-for-field("file", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
            case "text" return
                if ($doc) then (
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:div"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index"),
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:text"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                ) else (
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:div"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index"),
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:text"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                )
            case "head" return
                if ($doc) then
                    doc($config:data-root || "/" || $doc)/util:index-keys-by-qname(xs:QName("tei:head"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
                else
                    collection($config:data-root)/util:index-keys-by-qname(xs:QName("tei:head"), $lower-case-q,
                        function($key, $count) {
                            $key
                        }, 30, "lucene-index")
            default return
                collection($config:data-root)/ft:index-keys-for-field("title", $lower-case-q,
                    function($key, $count) {
                        $key
                    }, 30)
};

declare function teis:get-parent-section($node as node()) {
    ($node/self::tei:text, $node/ancestor-or-self::tei:div[1], $node)[1]
};

declare function teis:get-breadcrumbs($config as map(*), $hit as node(), $parent-id as xs:string) {
    let $work := root($hit)/*
    let $work-title := nav:get-document-title($config, $work)/string()
    return
        <div class="breadcrumbs">
            <a class="breadcrumb" href="{$parent-id}">{$work-title}</a>
            {
                for $parentDiv in $hit/ancestor-or-self::tei:div[tei:head]
                let $id := util:node-id(
                    if ($config?view = "page") then ($parentDiv/preceding::tei:pb[1], $parentDiv)[1] else $parentDiv
                )
                return
                    <a class="breadcrumb" href="{$parent-id || "?action=search&amp;root=" || $id || "&amp;view=" || $config?view || "&amp;odd=" || $config?odd}">
                    {$parentDiv/tei:head/string()}
                    </a>
            }
        </div>
};

(:~
 : Expand the given element and highlight query matches by re-running the query
 : on it.
 :)
declare function teis:expand($data as node()) {
    let $query := session:get-attribute($config:session-prefix || ".search")
    let $field := session:get-attribute($config:session-prefix || ".field")
    let $div :=
        if ($data instance of element(tei:pb)) then
            let $nextPage := $data/following::tei:pb[1]
            return
                if ($nextPage) then
                    if ($field = "text") then
                        (
                            ($data/ancestor::tei:div intersect $nextPage/ancestor::tei:div)[last()],
                            $data/ancestor::tei:text
                        )[1]
                    else
                        $data/ancestor::tei:text
                else
                    (: if there's only one pb in the document, it's whole
                      text part should be returned :)
                    if (count($data/ancestor::tei:text//tei:pb) = 1) then
                        ($data/ancestor::tei:text)
                    else
                      ($data/ancestor::tei:div, $data/ancestor::tei:text)[1]
        else
            $data
    let $result := teis:query-default-view($div, $query, $field)
    let $expanded :=
        if (exists($result)) then
            util:expand($result, "add-exist-id=all")
        else
            $div
    return
        if ($data instance of element(tei:pb)) then
            $expanded//tei:pb[@exist:id = util:node-id($data)]
        else
            $expanded
};


declare function teis:query-default-view($context as element()*, $query as xs:string, $fields as xs:string+) {
    for $field in $fields
    return
        switch ($field)
            case "head" return
                $context[./descendant-or-self::tei:head[ft:query(., $query, $query:QUERY_OPTIONS)]]
            default return
                $context[./descendant-or-self::tei:div[ft:query(., $query, $query:QUERY_OPTIONS)]] |
                $context[./descendant-or-self::tei:text[ft:query(., $query, $query:QUERY_OPTIONS)]]
};

declare function teis:get-current($config as map(*), $div as node()?) {
    if (empty($div)) then
        ()
    else
        if ($div instance of element(tei:teiHeader)) then
            $div
        else
            (nav:filler($config, $div), $div)[1]
};

xml-file:

<TEI xmlns="http://www.tei-c./ns/1.0" xml:id="DCH_Abogados" rendition="tei:teisimple"
    xml:lang="es">
    <teiHeader xml:lang="en">
        <fileDesc>
            <titleStmt>
                <title>Abogados (DCH)</title>
...

<body>
            <div n="1">
                <head>1. Introducción</head>
                <p>Para las <name type="place">Indias</name>, la definición de <term xml:lang="es">
                    abogado</term>, sus cualidades y requisitos, venía resuelta por la larga
                    tradición del <rs xml:lang="la">ius commune</rs>

the results appear in random order

The entire platform project is in this repository [https://github/eeditiones/tei-publisher-app]. My specific project has a few changes, but in general it is very similar to the matri code.

Share Improve this question edited yesterday ndso86 asked 2 days ago ndso86ndso86 11 bronze badge 0
Add a comment  | 

1 Answer 1

Reset to default 0

SOLVED::

Someone helped me and the solution is this:

for $hit in query:query-default($request?parameters?field, $request?parameters?query, $request?parameters?doc, ())
                let $config := tpu:parse-pi(root($hit), $request?parameters?view)
                let $parent := query:get-parent-section($config, $hit)
                let $parent-id := config:get-identifier($parent)
                order by query:get-breadcrumbs($config, $hit, $parent-id) ascending
                return $hit```

-------------------------------------

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论