如何解决使用 XPath 从参数映射构建 URL 查询字符串
从 XSLT/XPath 3.0 中的 <template>
<div id="app">
<VSelect
v-model="selectedContinent"
:options="contients"
:disabled="disabledContinent"
:searchable="searchableContinent"
class="style-chooser"
/>
</div>
</template>
<script>
import VSelect from "@alfsnd/vue-bootstrap-select";
export default {
name: "App",components: {
VSelect
},data() {
return {
contients: [
{ value: 0,text: "Africa" },{ value: 1,text: "America" },{ value: 2,text: "Asia" },{ value: 3,text: "Europe" },{ value: 4,text: "Oceania" },{ value: 5,text: "Antartica" }
],selectedname: null,searchableName: false,disabledname: false,selectedContinent: null,searchableContinent: false,disabledContinent: false
};
}
};
</script>
映射构建 URL 查询字符串的最易读的方法是什么?
解决方法
以下函数将起作用:
declare function local:build-uri($base-uri as xs:string,$params as map(xs:string,xs:string)) as xs:string {
if (map:size($params) ne 0) then
let $param-string := string-join(
map:keys($params)[. ne ""] ! (encode-for-uri(.) || "=" || encode-for-uri($params?(.))),"&"
)
return $base-uri || "?" || $param-string
else
$base-uri
};
例如:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare variable $params := map {
"one": "1","two": "2","three": "3","four": "4"
};
local:build-uri("http://www.example.com",map{}),local:build-uri("http://www.example.com",$params),local:build-uri("",()
返回:
http://www.example.com
http://www.example.com?four=4&one=1&two=2&three=3
?four=4&one=1&two=2&three=3
编辑:为了支持多值参数(同时保持函数体与 XPath 兼容),这样的事情应该可以工作:
declare function local:build-uri(
$base-uri as xs:string,xs:string*),$use-array-for-multivalue-params as xs:boolean (: param[]=value for PHP,etc. :)
) as xs:string {
if (map:size($params) ne 0) then
let $param-strings :=
for $param in map:keys($params)[. ne '']
return $params?($param) ! string-join((
encode-for-uri($param),if ($use-array-for-multivalue-params and count($params?($param)) gt 1) then "[]" else "","=",encode-for-uri(.)
),"")
return $base-uri || "?" || string-join($param-strings,"&")
else
$base-uri
};
,
不短,也不一定容易理解。
但是
- 它处理空值(使用 csv 你得到
key=
另一个完全省略键) - 它处理 xs:anyAtomicType (xs:dateTime,xs:decimal,xs:boolean,...)
- 添加了第三种常用方法来序列化查询字符串参数,其中多个值用逗号分隔
xquery version "3.1";
declare namespace qs="http://line-o.de/ns/qs";
(:~
: Append nothing to names of parameters with multiple values
: ?single=v1&multi=v2&multi=v3
:)
declare function qs:serialize-query-string($parameters as map(xs:string,xs:anyAtomicType*)) as xs:string? {
qs:serialize(
$parameters,qs:serialize-parameter(?,?,()))
};
(:~
: Append [] to names of parameters with multiple values
: ?single=v1&multi[]=v2&multi[]=v3
:)
declare function qs:serialize-query-string-array($parameters as map(xs:string,'[]'))
};
(:~
: Commma separated values for parameters with multiple values
: ?single=v1&multi=v2,v3
:)
declare function qs:serialize-query-string-csv($parameters as map(xs:string,qs:serialize-parameter-csv#2)
};
declare function qs:serialize(
$parameters as map(xs:string,xs:anyAtomicType*),$serializer as function(xs:string,xs:anyAtomicType*) as xs:string*
) as xs:string? {
if (map:size($parameters) eq 0)
then ()
else
$parameters
=> map:for-each($serializer)
=> string-join('&')
=> qs:prepend-questionmark()
};
declare function qs:serialize-parameter (
$raw-parameter-name as xs:string,$values as xs:anyAtomicType*,$appendix as xs:string?
) as xs:string* {
let $parameter-name := concat(
encode-for-uri($raw-parameter-name),if (exists($values) and count($values)) then $appendix else ()
)
return
for-each($values,qs:serialize-parameter-value($parameter-name,?))
};
declare function qs:serialize-parameter-csv ($raw-parameter-name as xs:string,$values as xs:anyAtomicType*) as xs:string* {
concat(
encode-for-uri($raw-parameter-name),'=',$values
=> for-each(function ($value) { encode-for-uri(xs:string($value)) })
=> string-join(',')
)
};
declare function qs:serialize-parameter-value (
$parameter as xs:string,$value as xs:anyAtomicType
) as xs:string {
``[`{$parameter}`=`{encode-for-uri($value)}`]``
};
declare function qs:prepend-questionmark ($query-string as xs:string) {
concat('?',$query-string)
};
qs:serialize-query-string(map{}),qs:serialize-query-string-array(map{}),qs:serialize-query-string-csv(map{}),qs:serialize-query-string(map{ "a": ("b0","b1"),"b": "$=@#'" }),qs:serialize-query-string-array(map{ "a": (xs:date("1970-01-01"),qs:serialize-query-string-csv(map{ "a": ("b0",3.14),"c": () }),qs:serialize-query-string-array(map{ "a": ("b0","c": () })
这是将上述内容拆分为模块和测试的要点:
https://gist.github.com/line-o/e492401494a4e003bb01b7a2f884b027
编辑:减少代码重复
,let
$encode-parameters-for-uri:= function($parameters as map(*)) as xs:string? {
let
(: serialize each map entry :)
$encoded-parameters:= map:for-each(
$parameters,function ($key,$values) {
(: serialize the sequence of values for this key :)
for $value in $values return
encode-for-uri($key) || '=' || encode-for-uri($value)
}
),(: join the URI parameters with ampersands :)
$parameters-string:= string-join(
$encoded-parameters,codepoints-to-string(38)
)
return
(: prepend '?' if parameters exist :)
if ($parameters-string) then
'?' || $parameters-string
else
()
}
return
$encode-parameters-for-uri(
map{
'size': 'large','flavour': ('chocolate','strawberry')
}
)
结果:?flavour=chocolate&flavour=strawberry&size=large
更简洁的版本,不同之处还在于它将空映射转换为零长度字符串而不是空字符串序列:
let
$encode-parameters-for-uri:= function($parameters as map(*)) as xs:string {
if (map:size($parameters)) then
'?' || string-join(
map:for-each(
$parameters,$values) {
for $value in $values return
encode-for-uri($key) || '=' || encode-for-uri($value)
}
),codepoints-to-string(38)
)
else
''
}
return
$encode-parameters-for-uri(
map{
'foo': ('bar','baz'),'direction': 'north'
}
)
结果?direction=north&foo=bar&foo=baz
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。