=== modified file 'lisp/url/url-util.el' --- lisp/url/url-util.el 2011-01-25 04:08:28 +0000 +++ lisp/url/url-util.el 2011-06-09 16:43:39 +0000 @@ -26,7 +26,8 @@ (require 'url-parse) (require 'url-vars) -(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cl) + (require 'ert)) (autoload 'timezone-parse-date "timezone") (autoload 'timezone-make-date-arpa-standard "timezone") (autoload 'mail-header-extract "mailheader") @@ -263,24 +264,65 @@ ;;;###autoload (defun url-parse-query-string (query &optional downcase allow-newlines) (let (retval pairs cur key val) - (setq pairs (split-string query "&")) + (setq pairs (split-string query "[;&]")) (while pairs (setq cur (car pairs) pairs (cdr pairs)) - (if (not (string-match "=" cur)) - nil ; Grace - (setq key (url-unhex-string (substring cur 0 (match-beginning 0)) - allow-newlines)) - (setq val (url-unhex-string (substring cur (match-end 0) nil) - allow-newlines)) - (if downcase - (setq key (downcase key))) - (setq cur (assoc key retval)) - (if cur - (setcdr cur (cons val (cdr cur))) - (setq retval (cons (list key val) retval))))) + (unless (string-match "=" cur) + (setq cur (concat cur "="))) + + (when (string-match "=" cur) + (setq key (url-unhex-string (substring cur 0 (match-beginning 0)) + allow-newlines)) + (setq val (url-unhex-string (substring cur (match-end 0) nil) + allow-newlines)) + (if downcase + (setq key (downcase key))) + (setq cur (assoc key retval)) + (if cur + (setcdr cur (cons val (cdr cur))) + (setq retval (cons (list key val) retval))))) retval)) +;;;###autoload +(defun url-build-query-string (query &optional semicolons keep-empty) + "Build a query-string. + +Given a QUERY in the form: +'((key1 val1) + (key2 val2) + (key3 val1 val2) + (key4) + (key5 "")) + +\(This is the same format as produced by `url-parse-query-string') + +This will return a string +\"key1=val1&key2=val2&key3=val1&key3=val2&key4&key5\". Keys may +be strings or symbols; if they are symbols, the symbol name will +be used. + +When SEMICOLONS is given, the separator will be \";\". + +When KEEP-EMPTY is given, empty values will show as \"key=\" +instead of just \"key\" as in the example above." + (mapconcat + (lambda (key-vals) + (let ((escaped + (mapcar (lambda (sym) + (url-hexify-string (format "%s" sym))) key-vals))) + (mapconcat (lambda (val) + (let ((vprint (format "%s" val)) + (eprint (format "%s" (car escaped)))) + (concat eprint + (if (or keep-empty + (and val (not (zerop (length vprint))))) + "=" + "") + vprint))) + (or (cdr escaped) '("")) (if semicolons ";" "&")))) + query (if semicolons ";" "&"))) + (defun url-unhex (x) (if (> x ?9) (if (>= x ?a) @@ -529,6 +571,27 @@ (error "Danger: `%s' is a symbolic link" file)) (set-file-modes file #o0600)))) +(ert-deftest url-build-and-parse-query-string () + (let ((tests + '(("key1=val1&key2=val2&key3=val1&key3=val2&key4&key5" + ((key1 val1) (key2 "val2") (key3 val1 val2) (key4) (key5 ""))) + ("key1=val1;key2=val2;key3=val1;key3=val2;key4;key5" + ((key1 "val1") (key2 val2) (key3 val1 val2) ("key4") (key5 "")) t) + ("key1=val1;key2=val2;key3=val1;key3=val2;key4=;key5=" + ((key1 val1) (key2 val2) ("key3" val1 val2) (key4) (key5 "")) t t))) + test) + (while tests + (setq test (car tests) + tests (cdr tests)) + (should (equal (apply 'url-build-query-string (cdr test)) (car test))))) + (should (equal (url-parse-query-string + "key1=val1&key2=val2&key3=val1&key3=val2&key4=&key5") + '(("key5" "") + ("key4" "") + ("key3" "val2" "val1") + ("key2" "val2") + ("key1" "val1"))))) + (provide 'url-util) ;;; url-util.el ends here