XQuery: возвращает, сколько раз поисковый запрос был найден в XML-документе.

У меня есть набор из двух файлов XML (помеченных в соответствии со стандартом TEI и содержащих множество элементов <entry>) в базе данных eXist. Я просматриваю файл с помощью подпрограммы FLWOR, ищу поисковый запрос, который пользователь ввел в форму ($searchterm), и возвращаю содержимое определенных элементов. Все идет нормально. Теперь я хотел бы добавить еще одну вещь, но я не знаю, как это сделать:

Я хотел бы подсчитать, сколько <entry> было $searchterm в <form type="hyperlemma">, и напечатать его вместо xxx. Если $searchterm равно "ангелъ", число будет "3". Поскольку мне нужно напечатать эту информацию, прежде чем я пройдусь по коллекции, я понятия не имею, что мне нужно делать.

Может ли кто-нибудь помочь? Поскольку я все еще новичок в XQuery, мой код, вероятно, не очень красивый, поэтому любые подсказки, которые помогут мне улучшить его, также очень ценятся!

Мой XQuery:

xquery version "3.0";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare option exist:serialize "method=xhtml media-type=text/html";
declare variable $searchphrase := request:get-parameter("searchphrase", ());
declare variable $collection_path := "/db/apps/ex02/data";
<html>
<head>
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=UTF-8"/>
<title>{$page-title}</title>
</head>
<body>
<h1>{$page-title}</h1>
<h2>Results</h2>
<p>Your input: "{$searchphrase}"</p>
<h3>Found xxx entries</h3>
   {
    for $file in collection($collection_path),
        $hyperlemma in $file/(descendant::tei:entry | descendant::tei:cit)/tei:form[@type='hyperlemma']/tei:orth [ft:query(., $searchphrase)]
        let $title := $hyperlemma/ancestor::*/tei:head
        let $entry_number := $hyperlemma/ancestor::tei:entry[1]/@xml:id
        let $lemma := $hyperlemma/ancestor::tei:entry/tei:form[@type='lemma']/tei:orth
    return
        <div>
        {string($title)} ({data($entry_number)}):<br/>
        <strong><font color="red">{string($lemma)}</font></strong><br/>
        {
            for $counterpart in $hyperlemma/ancestor::tei:entry/(tei:form[@type='lemma'] | tei:form[@type='variant'])/tei:cit/tei:form[@type='lemma']/tei:orth
            return
            <font color="green">&#160;&#160;&#160;&#160;{string($counterpart)}<br/></font>
        }
        </div>
}
</body>

These are snippets of the two XML files:

(A)

...
<text>
<head>Euch.</head>
<entry xml:id="pen-26">
    <form type="hyperlemma" xml:lang="grc">
        <orth>ἄγγελος</orth>
    </form>
    <form type="lemma" xml:lang="grc">
        <orth>ἄγγελος</orth>
        <cit type="counterpart" xml:lang="cu">
            <form type="hyperlemma" xml:lang="cu">
                <orth>ангелъ</orth>
            </form>
            <form type="lemma" xml:lang="cu">
                <orth>аньꙉелъ</orth>
            </form>
        </cit>
    </form>
</entry>
<entry xml:id="pen-336">
    <form type="hyperlemma" xml:lang="grc">
        <orth>ἀρχάγγελος</orth>
    </form>
    <form type="lemma" xml:lang="grc">
        <orth>ἀρχάγγελος</orth>
        <cit type="counterpart" xml:lang="cu">
            <form type="hyperlemma" xml:lang="cu">
                <orth>ангелъ</orth>
            </form>
            <form type="lemma" xml:lang="cu">
                <orth>аньꙉелъ</orth>
            </form>
        </cit>
    </form>
</entry>
</text>
...

(B)

...
<text>
<head>Syn.Tr. [1]</head>
<entry xml:id="tas-12">
<form type="hyperlemma" xml:lang="grc">
    <orth>ἄγγελος</orth>
</form>
<form type="lemma" xml:lang="grc">
    <orth>ἄγγελος</orth>
    <cit type="counterpart" xml:lang="cu">
        <form type="hyperlemma" xml:lang="cu">
            <orth>ангелъ</orth>
        </form>
        <form type="lemma" xml:lang="cu">
            <orth>ангєлъ</orth>
        </form>
    </cit>
    <cit type="counterpart" xml:lang="cu">
        <form type="hyperlemma" xml:lang="cu">
            <orth>вѣстьникъ</orth>
        </form>
        <form type="lemma" xml:lang="cu">
            <orth>вѣстьникъ</orth>
        </form>
    </cit>
</form>
</entry>
</text>

person smo    schedule 12.05.2015    source источник


Ответы (1)


Вам просто нужно немного реорганизовать запрос и вывод HTML, чтобы выполнить запрос до того, как вы захотите вывести количество результатов и отобразить результаты. Вы можете вызвать fn:count по результатам, чтобы получить количество результатов. Однако обратите внимание, здесь мы упаковываем в последовательность $results в два раза больше вещей, поэтому мы делим ее на 2. Например:

xquery version "3.0";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare option exist:serialize "method=xhtml media-type=text/html";
declare variable $page-title := "SlaVaComp-DB";
declare variable $searchphrase := request:get-parameter("searchphrase", ());
declare variable $collection_path := "/db/apps/ex02/data";
<html>
<head>
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=UTF-8"/>
<title>{$page-title}</title>
</head>
<body>
<h1>{$page-title}</h1>
{
    let $results := 
        for 
            $file in collection($collection_path),
            $hyperlemma in $file/(descendant::tei:entry | descendant::tei:cit)/tei:form[@type='hyperlemma']/tei:orth [ft:query(., $searchphrase)]
        return
            ($file, $hyperlemma)
    return
        let $count := count($results) 
        let $offsets :=
            for $i in (0 to ($count div 2) cast as xs:integer - (if($count mod 2 eq 0)then 1 else 0)) 
            return
                2 * $i + 1
        return
        <div>
            <h2>Results</h2>
            <p>Your input: "{$searchphrase}"</p>
            <h3>Found {$count div 2} entries</h3>
            {
                for $offset in $offsets
                let $hyperlemma := $results[$offset + 1]
                let $title := $hyperlemma/ancestor::*/tei:head
                let $entry_number := $hyperlemma/ancestor::tei:entry[1]/@xml:id
                let $lemma := $hyperlemma/ancestor::tei:entry/tei:form[@type='lemma']/tei:orth
                return
                    <div>
                    {string($title)} ({data($entry_number)}):<br/>
                    <strong><font color="red">{string($lemma)}</font></strong><br/>
                    {
                        for $counterpart in $hyperlemma/ancestor::tei:entry/(tei:form[@type='lemma'] | tei:form[@type='variant'])/tei:cit/tei:form[@type='lemma']/tei:orth
                        return
                        <font color="green">&#160;&#160;&#160;&#160;{string($counterpart)}<br/></font>
                    }
                    </div>
            }
        </div>
}
</body>

Приведенный выше запрос несколько сложен, так как мы упаковываем как $file, так и $hyperlemma в последовательность, где смещения с нечетными номерами — это файл, а смещения с четными номерами — гиперлемма.

Я заметил, однако, что вы не используете $file в своих результатах, если вам это не нужно, ваш запрос может быть значительно упрощен до:

xquery version "3.0";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare option exist:serialize "method=xhtml media-type=text/html";
declare variable $page-title := "SlaVaComp-DB";
declare variable $searchphrase := request:get-parameter("searchphrase", ());
declare variable $collection_path := "/db/apps/ex02/data";
<html>
<head>
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=UTF-8"/>
<title>{$page-title}</title>
</head>
<body>
<h1>{$page-title}</h1>
{
    let $hyperlemmas := collection($collection_path)/(descendant::tei:entry | descendant::tei:cit)/tei:form[@type='hyperlemma']/tei:orth [ft:query(., $searchphrase)]
    return
        <div>
            <h2>Results</h2>
            <p>Your input: "{$searchphrase}"</p>
            <h3>Found {count($hyperlemmas)} entries</h3>
            {
                for $hyperlemma in $hyperlemmas
                let $title := $hyperlemma/ancestor::*/tei:head
                let $entry_number := $hyperlemma/ancestor::tei:entry[1]/@xml:id
                let $lemma := $hyperlemma/ancestor::tei:entry/tei:form[@type='lemma']/tei:orth
                return
                    <div>
                    {string($title)} ({data($entry_number)}):<br/>
                    <strong><font color="red">{string($lemma)}</font></strong><br/>
                    {
                        for $counterpart in $hyperlemma/ancestor::tei:entry/(tei:form[@type='lemma'] | tei:form[@type='variant'])/tei:cit/tei:form[@type='lemma']/tei:orth
                        return
                        <font color="green">&#160;&#160;&#160;&#160;{string($counterpart)}<br/></font>
                    }
                    </div>
            }
        </div>
}
</body>

Вам также может быть интересно прочитать о KWIC, если вы хотите выделить, где в тексте совпадают поисковые запросы по различным ключевым словам: http://www.exist-db.org/exist/apps/doc/kwic.xml

person adamretter    schedule 12.05.2015
comment
Большое спасибо! Но, к сожалению, пока не работает. Я попытался интегрировать ваш фрагмент кода в свой документ XQuery, но теперь eXide выдает два предупреждения (tei: неиспользуемый префикс пространства имен и $results: неиспользуемая переменная) и ошибку: гиперлемма: неиспользуемая переменная. Я заметил, что во второй строке вы ссылаетесь на $file, но $file не задан нигде в вашем коде (это было в моем фрагменте). Это что-нибудь значит? Извините, что снова беспокою... - person smo; 12.05.2015
comment
Ах, да, упс, я вставил не тот этап своего кода, я обновил свой ответ. Я надеюсь, что это имеет больше смысла. - person adamretter; 12.05.2015
comment
Теперь это работает как шарм! Я выберу вторую версию, которая делает именно то, что я искал. Если мне когда-нибудь понадобится более сложное решение, подобное первому, оно у меня уже есть — благодаря вам! Большое спасибо, что нашли время дать подробный ответ! - person smo; 13.05.2015