19

Does anyone have, or know of, a java class that I can use to manipulate query strings?

Essentially I'd like a class that I can simply give a query string to and then delete, add and modify query string KVP's.

Thanks in advance.

EDIT

In response to a comment made to this question, the query string will look something like this;

N=123+456+112&Ntt=koala&D=abc

So I'd like to pass this class the query string and say something like;

String[] N = queryStringClass.getParameter("N");

and then maybe

queryStringClass.setParameter("N", N);

and maybe queryStringClass.removeParameter("N");

Or something to that effect.

zengr
  • 38,346
  • 37
  • 130
  • 192
griegs
  • 22,624
  • 33
  • 128
  • 205

5 Answers5

17

SOmething like this

 public static Map<String, String> getQueryMap(String query)  
 {  
     String[] params = query.split("&");  
     Map<String, String> map = new HashMap<String, String>();  
     for (String param : params)  
     {  
         String name = param.split("=")[0];  
         String value = param.split("=")[1];  
         map.put(name, value);  
     }  
     return map;  
 }  

To iterate the map simply:

 String query = url.getQuery();  
 Map<String, String> map = getQueryMap(query);  
 Set<String> keys = map.keySet();  
 for (String key : keys)  
 {  
    System.out.println("Name=" + key);  
    System.out.println("Value=" + map.get(key));  
 }  
12

You can also use Google Guava's Splitter.

String queryString = "variableA=89&variableB=100";
Map<String,String> queryParameters = Splitter
    .on("&")
    .withKeyValueSeparator("=")
    .split(queryString);
System.out.println(queryParameters.get("variableA"));

prints out

89

This I think is a very readable alternative to parsing it yourself.

Edit: As @raulk pointed out, this solution does not account for escaped characters. However, this may not be an issue because before you URL-Decode, the query string is guaranteed to not have any escaped characters that conflict with '=' and '&'. You can use this to your advantage in the following way.

Say that you must decode the following query string:

a=%26%23%25!)%23(%40!&b=%23%24(%40)%24%40%40))%24%23%5E*%26

which is URL encoded, then you are guaranteed that the '&' and '=' are specifically used for separating pairs and key from value, respectively, at which point you can use the Guava splitter to get:

a = %26%23%25!)%23(%40!
b = %23%24(%40)%24%40%40))%24%23%5E*%26

Once you have obtained the key-value pairs, then you can URL decode them separately.

a = &#%!)#(@!
b = #$(@)$@@))$#^*&

That should cover all cases.

laughing_man
  • 3,756
  • 1
  • 20
  • 20
5

If you are using J2EE, you can use ServletRequest.getParameterValues().

Otherwise, I don't think Java has any common classes for query string handling. Writing your own shouldn't be too hard, though there are certain tricky edge cases, such as realizing that technically the same key may appear more than once in the query string.

One implementation might look like:

import java.util.*;
import java.net.URLEncoder;
import java.net.URLDecoder;

public class QueryParams {
private static class KVP {
    final String key;
    final String value;
    KVP (String key, String value) {
        this.key = key;
        this.value = value;
    }
}

List<KVP> query = new ArrayList<KVP>();

public QueryParams(String queryString) {
    parse(queryString);
}

public QueryParams() {
}

public void addParam(String key, String value) {
    if (key == null || value == null)
        throw new NullPointerException("null parameter key or value");
    query.add(new KVP(key, value));
}

private void parse(String queryString) {
    for (String pair : queryString.split("&")) {
        int eq = pair.indexOf("=");
        if (eq < 0) {
            // key with no value
            addParam(URLDecoder.decode(pair), "");
        } else {
            // key=value
            String key = URLDecoder.decode(pair.substring(0, eq));
            String value = URLDecoder.decode(pair.substring(eq + 1));
            query.add(new KVP(key, value));
        }
    }
}

public String toQueryString() {
    StringBuilder sb = new StringBuilder();
    for (KVP kvp : query) {
        if (sb.length() > 0) {
            sb.append('&');
        }
        sb.append(URLEncoder.encode(kvp.key));
        if (!kvp.value.equals("")) {
            sb.append('=');
            sb.append(URLEncoder.encode(kvp.value));
        }
    }
    return sb.toString();
}

public String getParameter(String key) {
    for (KVP kvp : query) {
        if (kvp.key.equals(key)) {
            return kvp.value;
        }
    }
    return null;
}

public List<String> getParameterValues(String key) {
    List<String> list = new LinkedList<String>();
    for (KVP kvp : query) {
        if (kvp.key.equals(key)) {
            list.add(kvp.value);
        }
    }
    return list;
}

public static void main(String[] args) {
    QueryParams qp = new QueryParams("k1=v1&k2&k3=v3&k1=v4&k1&k5=hello+%22world");
    System.out.println("getParameter:");
    String[] keys = new String[] { "k1", "k2", "k3", "k5" };
    for (String key : keys) {
        System.out.println(key + ": " + qp.getParameter(key));
    }
    System.out.println("getParameters(k1): " + qp.getParameterValues("k1"));
}
}
Avi
  • 19,934
  • 4
  • 57
  • 70
  • +1, thanks for this. Already implemented something like this. – griegs Nov 09 '10 at 05:17
  • @Achimnol: What's the problem? & is XML-encoding, it should pass through a URL parameter as %26amp;. If you want to further XML-decode the string, you can use other methods for that. – Avi May 07 '11 at 18:15
  • Note that `ServletRequest.getParameterValues()` can badly handle encoding: http://stackoverflow.com/questions/469874/how-do-i-correctly-decode-unicode-parameters-passed-to-a-servlet – Vadzim Apr 21 '16 at 21:55
2

Another way is to use apache http-components. It's a bit hacky, but at least you leverage all the parsing corner cases:

List<NameValuePair> params = 
    URLEncodedUtils.parse("http://example.com/?" + queryString, Charset.forName("UTF-8"));

That'll give you a List of NameValuePair objects that should be easy to work with.

matt burns
  • 24,742
  • 13
  • 105
  • 107
  • I found strange that this was not already proposed ... this is hacky but a good usage of an existing library... – AxelH Sep 08 '17 at 10:15
0

You can create a util method and use regular expression to parse it. A pattern like "[;&]" should suffice.

CoolBeans
  • 20,654
  • 10
  • 86
  • 101