XQuery/Parsing Query Strings

Motivation

edit

Normal http query strings use the ampersand (&) character in order to differentiate between different terms in a query string. However, because ampersands also are used as the start of entities within HTML and XML, this can make it difficult encoding parametric content into XML links, and it moreover makes it difficult to visually decipher query strings.

This program illustrates how to parse query strings using alternative delimiters (such as the semi-colon).

This program demonstrates some standard XQuery functions that are not part of the original XQuery specification but are required for precise web server XQuery functionality.

The functions are:

  • exist request:get-method()
  • exist util:unescape-uri()
  • exist request:get-query-string()
  • exist request:get-parameter()
  • exist request:get-parameter-names()

Namespace

edit
 module namespace common="http://www.example.org/xmlns/common";

Platform

edit
  • eXist

Parsing Query Strings

edit

common:get-parameters

edit

This base function retrieves the query string from the URI, parses the string using the given delimiter and creates an XML structure of the form

  <params>
    <param name="param1" value="paramval1"/>
    <param name="param2" value="paramval2"/>
  </params>
  declare function common:get-parameters($delimiter as xs:string) as node() {
     let $params := if (request:get-method() = "GET") then 
          let $query-string := util:unescape-uri(request:get-query-string(),"UTF-8")
          let $parsed-query := tokenize($query-string,$delimiter)
          return <params>
          {for $parsed-query-term in $parsed-query 
                let $parse-query-name := substring-before($parsed-query-term,"=")
                let $parse-query-value := substring-after($parsed-query-term,"=")
                return <param name="{$parse-query-name}" value="{$parse-query-value}"/>
                }
          </params>          
       else 
          <params>
              {for $name in request:get-parameter-names()
                    let $parse-query-name := $name
                    let $parse-query-value := request:get-parameter($name,"")                    
                return <param name="{$parse-query-name}" value="{$parse-query-value}"/>
                }
          </params>
    return $params
    };

common:get-parameter

edit

This function retrieves a sequence of string values corresponding to the values for a given parameter key given in the query string. Note that while typically there will be only one string in the sequence, if you have a query string of the form ?a=val1;b=val2;a=val3 then get-parameter("a","",";") will return ("val1","val3")

  declare function common:get-parameter($param-name as xs:string,$default-value as xs:string,$delimiter as xs:string) as xs:string* {
    let $params := common:get-parameters($delimiter)
    let $param-nodes := $params/param[@name=$param-name]
    let $param-values := 
       for $param-node in $param-nodes 
       return 
         if ($param-node/@value) 
         then string($param-node/@value) 
         else $default-value 
    return  $param-values
    };

common:get-parameter-names

edit

This function retrieves the name of each query string key (once and only once per key).

   
  declare function common:get-parameter-names($delimiter as xs:string) as xs:string* {
    let $params := common:get-parameters($delimiter)
    for $param-name in distinct-values($params/param/@name)
    return $param-name
    };

Example Program

edit

Assumes query string of http://www.example.org/?a=5;b=test;a=8;c=new+message

 let $msg := common:get-parameter("c","",";")
 return $msg
 

returns

 new message   

 
  {
    for $key in common:get-parameter-names(";")
    return 
       <seq>{$key}:{common:get-parameter($key,"",";")}</seq>
  }
 

returns

 
   <seq>a:5 8</seq>
   <seq>b:test</seq>
   <seq>c:new message</seq>
 

   let $seq1 := common:get-parameter("a",0,";")
   return  sum(for $n in $seq1 return number($n))

returns

 13