【问题标题】:Parsing a URL query string into a map of parameters with XPath使用 XPath 将 URL 查询字符串解析为参数映射
【发布时间】: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* 序列。

【问题讨论】:

    标签: xpath xslt-3.0 xpath-3.0 xpath-3.1


    【解决方案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()
      

      【讨论】:

        猜你喜欢
        • 2021-07-23
        • 1970-01-01
        • 2017-04-14
        • 2023-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-28
        • 2014-08-04
        相关资源
        最近更新 更多