Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert query string to map in scala

I have a query string in this form:

val query = "key1=val1&key2=val2&key3=val3

I want to create a map with the above key/value pairs. So far I'm doing it like this:

//creating an iterator with 2 values in each group. Each index consists of a key/value pair
val pairs = query.split("&|=").grouped(2)

//inserting the key/value pairs into a map
val map = pairs.map { case Array(k, v) => k -> v }.toMap

Are there any problems with doing it like I do? If so, is there some library I could use to do it?

like image 684
Michael Avatar asked Mar 15 '17 14:03

Michael


2 Answers

Here is an approach using the URLEncodedUtils:

import java.net.URI

import org.apache.http.client.utils.URLEncodedUtils
import org.apache.http.{NameValuePair => ApacheNameValuePair}

import scala.collection.JavaConverters._
import scala.collection.immutable.Seq

object GetEncodingTest extends App {
  val url = "?one=1&two=2&three=3&three=3a"
  val params = URLEncodedUtils.parse(new URI(url), "UTF_8")

  val convertedParams: Seq[ApacheNameValuePair] = collection.immutable.Seq(params.asScala: _*)
  val scalaParams: Seq[(String, String)] = convertedParams.map(pair => pair.getName -> pair.getValue)
  val paramsMap: Map[String, String] = scalaParams.toMap
  paramsMap.foreach(println)
}
like image 142
matfax Avatar answered Nov 09 '22 05:11

matfax


Assuming the query string you are working with is as simple as you showed, the use of grouped(2) is a great insight and gives a pretty elegant looking solution.

The next step from where you're at is to use the under-documented Array::toMap method:

val qs = "key=value&foo=bar"
qs.split("&|=")              // Array(key, value, foo, bar)
  .grouped(2)                // <iterator>
  .map(a => (a(0), a(1)))    // <iterator>
  .toMap                     // Map(key -> value, foo -> bar)

grouped(2) returns an Iterator[Array[String]], that's a little harder to follow because iterators don't serialize nicely on the Scala console.

Here's the same result, but a bit more step-by-step:

val qs = "key=value&foo=bar"
qs.split("&")                                      // Array(key=value, foo=bar)
  .map(kv => (kv.split("=")(0), kv.split("=")(1))) // Array((key,value), (foo,bar))
  .toMap                                           // Map(key -> value, foo -> bar)

If you want a more general solution for HTTP query strings, consider using a library for URL parsing.

like image 1
yegeniy Avatar answered Nov 09 '22 04:11

yegeniy