使用标记化和匹配在 xquery 中搜索多个关键字
Multiple keyword search in xquery with tokenize and match
我之前问的好像太绕了,再试一次!
我正在 Xquery 中进行搜索。在其中一个字段(标题)中,应该可以输入多个关键字。目前只有一个关键字有效。当存在多个时,会出现错误 ERROR XPTY0004:参数 1 的实际基数与函数签名中声明的基数不匹配:concat($atomizable-values as xs:anyAtomicType? , ...) xs:string?.预期基数:零或一,得到 2.
在我的 xquery 中,我试图通过 \s 标记关键字,然后分别匹配它们。我认为这种方法可能是错误的,但我不确定使用其他什么方法。我明明是初学者!!
这里是要搜索的例子XML:
<files>
<file>
<identifier>
<institution>name1</institution>
<idno>signature</idno>
</identifier>
<title>Math is fun</title>
</file>
<file>
<identifier>
<institution>name1</institution>
<idno>signature1</idno>
</identifier>
<title>philosophy of math</title>
</file>
<file>
<identifier>
<institution>name2</institution>
<idno>signature2</idno>
</identifier>
<title>i like cupcakes</title>
</file>
</files>
这是 Xquery,示例输入 'math' 用于搜索字段标题,'name1' 用于搜索字段机构。 有效,搜索输出是标题 'math is fun' 和 'philosophy of math'。如果将输入 ($title) 更改为 'math fun',则不起作用。然后您会收到错误消息。期望的输出是标题 'math is fun'.
xquery version "3.0";
let $institution := 'name1'
let $title := 'math' (:change to 'math fun' and doesn't work anymore, only a single word works:)
let $title-predicate :=
if ($title)
then
if (contains($title, '"'))
then concat("[contains(lower-case(title), '", replace($title, '["]', ''), "')]") (:This works fine:)
else
for $title2 in tokenize($title, '\s') (:HERE IS THE PROBLEM, this only works when the input is a single word, for instance 'math' not 'math fun':)
return
concat("[matches(lower-case(title), '", $title2, "')]")
else ()
let $institution-predicate := if ($institution) then concat('[lower-case(string-join(identifier/institution))', " = '", $institution, "']") else ()
let $eval-string := concat
("doc('/db/Unbenannt.xml')//file",
$institution-predicate,
$title-predicate
)
let $records := util:eval($eval-string)
let $test := count($records)
let $content :=
<inner_container>
<div>
<h2>Search Results</h2>
<ul>
{
for $record in $records
return
<li id="searchList">
<span>{$record//institution/text()}</span> <br/>
<span>{$record//title/text()}</span>
</li>
}
</ul>
</div>
</inner_container>
return
$content
如果tokenize($title)
return是一个字符串序列,那么
for $title2 in tokenize($title, '\s')
return concat("[matches(lower-case(title), '", $title2, "')]")
还将return一个字符串序列
因此 $title-predicate
将是一个字符串序列,您不能将字符串序列作为参数之一提供给 concat()
。
所以问题很明显,但修复它需要比我有时间更深入地了解您的查询。
我很难相信将查询生成为字符串然后对该查询进行动态评估的方法真的很有必要。
您必须使用 string-join() 包装您的 FLWOR 表达式:
string-join(
for $title2 in tokenize($title, '\s')
return
concat("[matches(lower-case(title), '", $title2, "')]")
)
我之前问的好像太绕了,再试一次! 我正在 Xquery 中进行搜索。在其中一个字段(标题)中,应该可以输入多个关键字。目前只有一个关键字有效。当存在多个时,会出现错误 ERROR XPTY0004:参数 1 的实际基数与函数签名中声明的基数不匹配:concat($atomizable-values as xs:anyAtomicType? , ...) xs:string?.预期基数:零或一,得到 2.
在我的 xquery 中,我试图通过 \s 标记关键字,然后分别匹配它们。我认为这种方法可能是错误的,但我不确定使用其他什么方法。我明明是初学者!!
这里是要搜索的例子XML:
<files>
<file>
<identifier>
<institution>name1</institution>
<idno>signature</idno>
</identifier>
<title>Math is fun</title>
</file>
<file>
<identifier>
<institution>name1</institution>
<idno>signature1</idno>
</identifier>
<title>philosophy of math</title>
</file>
<file>
<identifier>
<institution>name2</institution>
<idno>signature2</idno>
</identifier>
<title>i like cupcakes</title>
</file>
</files>
这是 Xquery,示例输入 'math' 用于搜索字段标题,'name1' 用于搜索字段机构。 有效,搜索输出是标题 'math is fun' 和 'philosophy of math'。如果将输入 ($title) 更改为 'math fun',则不起作用。然后您会收到错误消息。期望的输出是标题 'math is fun'.
xquery version "3.0";
let $institution := 'name1'
let $title := 'math' (:change to 'math fun' and doesn't work anymore, only a single word works:)
let $title-predicate :=
if ($title)
then
if (contains($title, '"'))
then concat("[contains(lower-case(title), '", replace($title, '["]', ''), "')]") (:This works fine:)
else
for $title2 in tokenize($title, '\s') (:HERE IS THE PROBLEM, this only works when the input is a single word, for instance 'math' not 'math fun':)
return
concat("[matches(lower-case(title), '", $title2, "')]")
else ()
let $institution-predicate := if ($institution) then concat('[lower-case(string-join(identifier/institution))', " = '", $institution, "']") else ()
let $eval-string := concat
("doc('/db/Unbenannt.xml')//file",
$institution-predicate,
$title-predicate
)
let $records := util:eval($eval-string)
let $test := count($records)
let $content :=
<inner_container>
<div>
<h2>Search Results</h2>
<ul>
{
for $record in $records
return
<li id="searchList">
<span>{$record//institution/text()}</span> <br/>
<span>{$record//title/text()}</span>
</li>
}
</ul>
</div>
</inner_container>
return
$content
如果tokenize($title)
return是一个字符串序列,那么
for $title2 in tokenize($title, '\s')
return concat("[matches(lower-case(title), '", $title2, "')]")
还将return一个字符串序列
因此 $title-predicate
将是一个字符串序列,您不能将字符串序列作为参数之一提供给 concat()
。
所以问题很明显,但修复它需要比我有时间更深入地了解您的查询。
我很难相信将查询生成为字符串然后对该查询进行动态评估的方法真的很有必要。
您必须使用 string-join() 包装您的 FLWOR 表达式:
string-join(
for $title2 in tokenize($title, '\s')
return
concat("[matches(lower-case(title), '", $title2, "')]")
)