使用 XPath 将 URL 查询字符串解析为参数映射

Posted

技术标签:

【中文标题】使用 XPath 将 URL 查询字符串解析为参数映射【英文标题】:Parsing a URL query string into a map of parameters with XPath 【发布时间】:2021-10-26 21:12:30 【问题描述】:

在 XSLT/XPath 3.0 中将 URL 查询字符串解析为 'param': 'value' 映射的最易读的方法是什么?

注意:这是Building a URL query string from a map of parameters with XPath 中描述的函数的反函数。

更新:我没有提到该函数应该支持多值参数,例如a=1&a=2,并理想地将它们解析为xs:string* 序列。

【问题讨论】:

【参考方案1】:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
let $querystring := "a=1&b=2&c=3"
return 
  ( tokenize($querystring, "&") 
    ! (let $param := tokenize(., "=") 
      return map:entry($param[1], $param[2]) ) 
  ) => map:merge()

为了支持多个值,您可以应用$options parameter 指定如何处理duplicates

declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
let $querystring := "a=1&b=2&a=3"
return 
  ( tokenize($querystring, "&") 
    ! (let $param := tokenize(., "=") 
      return map:entry($param[1], $param[2]) ) 
  ) => map:merge(map:entry('duplicates', 'combine'))

【讨论】:

首先想到的 - 重复的参数名称怎么办? :) 我正在使用的反向 URI 构建函数的版本支持查询参数为 map(xs:string, xs:string*),这意味着一个参数可以有多个值。那么在这种情况下是否可以将它们解析为xs:string* 序列? 是的,如果处理多个同名参数,则需要有一个可用的映射,并在放置新条目时附加值。 map:put($map, $key, (map:get($map, $key), $value) )【参考方案2】:

Christian Grün 的另外 2 个回答:

let $querystring := "a=1&b=2&a=3"
return map:merge(
  for $query in tokenize($querystring, "&")
  let $param := tokenize($query, "=")
  return map:entry(head($param), tail($param)),
  map  'duplicates': 'combine' 
)

另一种解决方案(如果您不想使用 for 子句):

let $querystring := "a=1&b=2&a=3"
return map:merge(
  tokenize($querystring, "&")
  ! array  tokenize(., "=") 
  ! map:entry(.(1), .(2)),
  map  'duplicates': 'combine' 
)

【讨论】:

【参考方案3】:

让我们看看 - 要获取的子字符串?并去除任何尾随的 #... 片段标识符 然后在 [&;] 上进行标记(实际上是 [;&] 以获取名称=值对,它们由 & 或(不太常见)分隔; 然后substring-before and after,或者再次tokenize,得到=(name value)的前后 然后分别对名称和值进行uridecode

let $query := substring-after($uri, '?'),
     $beforefrag := substring-before($query || '#', '#')
return
  tokenize($beforefrag, '[;&]')
  ! [substring-before(., '='), substring-after(., '=') ]
  ! map:entry(local:uridecode(.(1), local:uridecode(.(2))

可能会给我们一系列映射条目,我们可以在上面使用 map:merge。

如果我们知道我们的输入经过合理编码,我们可以使用

declare function local:uridecode($input as xs:string?) as xs:string?

   parse-xml-fragment(replace($input, '=(..)', '&x$1;'))
;

但更好的版本只是替换两个十六进制字符。真的很不幸,我们没有一个版本的 replace(),它为每个匹配的子表达式调用一个函数参数,ala perl 的 e 标志。```

当然你可以把它放进去

(...) => map:merge()

【讨论】:

以上是关于使用 XPath 将 URL 查询字符串解析为参数映射的主要内容,如果未能解决你的问题,请参考以下文章

将url的查询参数解析成字典对象

php URL解析函数parse_str和parse_url的区别

将url的查询参数解析成字典对象

使用Xpath将href链接替换为来自同一父节点的字符串

将url的查询参数解析成字典对象

解析 html -> xml 并使用 Xpath 进行查询