23 votes

Comment analyser les paramètres d'une URL en Clojure ?

Si j'ai la demande "size=3&mean=1&sd=3&type=pdf&distr=normal" quelle est la façon idiomatique d'écrire la fonction (defn request->map [request] ...) qui prend en compte cette demande et renvoie une carte {:size 3, :mean 1, :sd 3, :type pdf, :distr normal}

Voici ma tentative (en utilisant clojure.walk et clojure.string) :

(defn request-to-map
   [request]
   (keywordize-keys
      (apply hash-map
             (split request #"(&|=)"))))

J'aimerais savoir comment d'autres personnes résoudraient ce problème.

24voto

KendallB Points 539

Utilisation form-decode y keywordize-keys :

(use 'ring.util.codec)
(use 'clojure.walk)

(keywordize-keys (form-decode "hello=world&foo=bar"))

{:foo "bar", :hello "world"}

18voto

ordnungswidrig Points 2088

Si vous souhaitez analyser les paramètres des requêtes HTTP, pourquoi ne pas utiliser anneau ? ring.middleware.params contient ce que vous voulez.

La fonction d'extraction des paramètres est la suivante :

(defn- parse-params
  "Parse parameters from a string into a map."
  [^String param-string encoding]
  (reduce
    (fn [param-map encoded-param]
      (if-let [[_ key val] (re-matches #"([^=]+)=(.*)" encoded-param)]
        (assoc-param param-map
          (codec/url-decode key encoding)
          (codec/url-decode (or val "") encoding))
         param-map))
    {}
    (string/split param-string #"&")))

11voto

Brian Carper Points 40078

Vous pouvez le faire facilement avec un certain nombre de bibliothèques Java. J'hésiterais à essayer de créer mon propre analyseur sans avoir lu attentivement les spécifications de l'URI et sans m'être assuré que je ne manquais aucun cas limite (par exemple, des paramètres apparaissant deux fois dans la requête avec des valeurs différentes). Ceci utilise jetty-util :

(import '[org.eclipse.jetty.util UrlEncoded MultiMap])

(defn parse-query-string [query]
  (let [params (MultiMap.)]
    (UrlEncoded/decodeTo query params "UTF-8")
    (into {} params)))

user> (parse-query-string "size=3&mean=1&sd=3&type=pdf&distr=normal")
{"sd" "3", "mean" "1", "distr" "normal", "type" "pdf", "size" "3"}

4voto

bluegray Points 159

Cette bibliothèque peut également être utilisée pour clojure et clojurescript : https://github.com/cemerick/url

user=> (-> "a=1&b=2&c=3" cemerick.url/query->map clojure.walk/keywordize-keys)
{:a "1", :b "2", :c "3"}

3voto

amalloy Points 29125

Le vôtre a l'air bien. J'ai tendance à abuser des expressions rationnelles, et j'aurais donc résolu le problème de la manière suivante

(defn request-to-keywords [req]
  (into {} (for [[_ k v] (re-seq #"([^&=]+)=([^&]+)" req)]
    [(keyword k) v])))

(request-to-keywords "size=1&test=3NA=G")

{:size "1", :test "3NA=G"}

Edit : essayez de rester à l'écart de clojure.walk. Je ne pense pas qu'il soit officiellement déprécié, mais il n'est pas très bien maintenu. (Je l'utilise aussi beaucoup, donc ne vous sentez pas trop mal).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X