Marcus Junius Brutus
Marcus Junius Brutus

Reputation: 27286

how to remove a query parameter from a query string

I am using UriBuilder to remove a parameter from a URI:

public static URI removeParameterFromURI(URI uri, String param) {
    UriBuilder uriBuilder = UriBuilder.fromUri(uri);
    return uriBuilder.replaceQueryParam(param, "").build();
}

public static String removeParameterFromURIString(String uriString, String param) {
    try {
        URI uri = removeParameterFromURI(new URI(uriString), param);
        return uri.toString();
    } catch (URISyntaxException e) {
        throw new RuntimeException(e);
    }
}

The above sort of works and modifies:

http://a.b.c/d/e/f?foo=1&bar=2&zar=3

… into:

http://a.b.c/d/e/f?bar=&foo=1&zar=3

But it has the following issues:

  1. It messes up the order of the parameters. I know that the order is not relevant but it still bothers me.
  2. it doesn't fully remove the parameter, it just sets its value to the empty string. I would prefer is the parameter is completely removed from the query string.

Is there some standard or commonly used library that can achieve the above neatly without having to parse and hack the query string myself?

Upvotes: 6

Views: 32793

Answers (11)

ViV
ViV

Reputation: 317

The following piece of code worked for me:

Code:

import java.util.Arrays;
import java.util.stream.Collectors;

public class RemoveURL {

    public static void main(String[] args) {
        final String remove = "password";
        final String url = "http://testdomainxyz.com?username=john&password=cena&password1=cena";
        System.out.println(url);
        System.out.println(RemoveURL.removeParameterFromURL(url, remove));
    }

    public static String removeParameterFromURL(final String url, final String remove) {
        final String[] urlArr = url.split("\\?");
        final String params = Arrays.asList(urlArr[1].split("&")).stream()
                .filter(item -> !item.split("=")[0].equalsIgnoreCase(remove)).collect(Collectors.joining("&"));
        return String.join("?", urlArr[0], params);
    }
}

Output

http://testdomainxyz.com?username=john&password=cena&password1=cena
http://testdomainxyz.com?username=john&password1=cena

Upvotes: 2

muthuraj
muthuraj

Reputation: 1102

@TTKatrina's answer worked for me, but I need to remove query param from fragment too. So extended that for fragment and came up with this.

fun Uri.removeQueryParam(key: String): Uri {

    //Create new Uri builder with no query params.
    val builder = buildUpon().clearQuery()

    //Add all query params excluding the key we don't want back to the new Uri.
    queryParameterNames.filter { it != key }
        .onEach { builder.appendQueryParameter(it, getQueryParameter(it)) }

    //If query param is in fragment, remove from it.
    val fragmentUri = fragment?.toUri()
    if (fragmentUri != null) {
        builder.encodedFragment(fragmentUri.removeQueryParam(key).toString())
    }

    //Now this Uri doesn't have the query param for [key]
    return builder.build()
}

Upvotes: -1

linkaipeng
linkaipeng

Reputation: 503

public static String removeQueryParameter(String url, List<String> removeNames) {
    try {
        Map<String, String> queryMap = new HashMap<>();
        Uri uri = Uri.parse(url);
        Set<String> queryParameterNames = uri.getQueryParameterNames();
        for (String queryParameterName : queryParameterNames) {
            if (TextUtils.isEmpty(queryParameterName)
                    ||TextUtils.isEmpty(uri.getQueryParameter(queryParameterName))
                    || removeNames.contains(queryParameterName)) {
                continue;
            }
            queryMap.put(queryParameterName, uri.getQueryParameter(queryParameterName));
        }
        // remove all params
        Uri.Builder uriBuilder = uri.buildUpon().clearQuery();

        for (String name : queryMap.keySet()) {
            uriBuilder.appendQueryParameter(name, queryMap.get(name));
        }
        return uriBuilder.build().toString();
    } catch (Exception e) {
        return url;
    }
}

Upvotes: 0

Daniel F
Daniel F

Reputation: 14239

If you are on Android and want to remove all query parameters, you can use

Uri uriWithoutQuery = Uri.parse(urlWithQuery).buildUpon().clearQuery().build();

Upvotes: 5

TTKatrina
TTKatrina

Reputation: 541

In Android, without import any library. I write a util method inspired by this answerReplace query parameters in Uri.Builder in Android?(Replace query parameters in Uri.Builder in Android?)

Hope can help you. Code below:

public static Uri removeUriParameter(Uri uri, String key) {
    final Set<String> params = uri.getQueryParameterNames();
    final Uri.Builder newUri = uri.buildUpon().clearQuery();
    for (String param : params) {
        if (!param.equals(key)) {
            newUri.appendQueryParameter(param, uri.getQueryParameter(param));
        }
    }
    return newUri.build();
}

Upvotes: 10

sendon1982
sendon1982

Reputation: 11244

You can use simpler method from Collection based on @Flips solution:

public String removeQueryParameter(String url, String parameterName) throws URISyntaxException {
    URIBuilder uriBuilder = new URIBuilder(url);
    List<NameValuePair> queryParameters = uriBuilder.getQueryParams();

    queryParameters.removeIf(param -> 
         param.getName().equals(parameterName));

    uriBuilder.setParameters(queryParameters);

    return uriBuilder.build().toString();
}

Upvotes: 1

Grisha
Grisha

Reputation: 416

To fully remove the parameter, you can use

public static URI removeParameterFromURI(URI uri, String param) {
    UriBuilder uriBuilder = UriBuilder.fromUri(uri);
    return uriBuilder.replaceQueryParam(param, (Object[]) null).build();
}

Upvotes: 3

VolkerK
VolkerK

Reputation: 1510

Using streams and URIBuilder from httpclient it would look like this

public String removeQueryParameter(String url, String parameterName) throws URISyntaxException {
    URIBuilder uriBuilder = new URIBuilder(url);
    List<NameValuePair> queryParameters = uriBuilder.getQueryParams()
              .stream()
              .filter(p -> !p.getName().equals(parameterName))
              .collect(Collectors.toList());
    if (queryParameters.isEmpty()) {
        uriBuilder.removeQuery();
    } else {
        uriBuilder.setParameters(queryParameters);
    }
    return uriBuilder.build().toString();
}

Upvotes: 2

Flips
Flips

Reputation: 170

Using httpclient URIBuilder would be much cleaner if you can.

public String removeQueryParameter(String url, String parameterName) throws URISyntaxException {
    URIBuilder uriBuilder = new URIBuilder(url);
    List<NameValuePair> queryParameters = uriBuilder.getQueryParams();
    for (Iterator<NameValuePair> queryParameterItr = queryParameters.iterator(); queryParameterItr.hasNext();) {
        NameValuePair queryParameter = queryParameterItr.next();
        if (queryParameter.getName().equals(parameterName)) {
            queryParameterItr.remove();
        }
    }
    uriBuilder.setParameters(queryParameters);
    return uriBuilder.build().toString();
}

Upvotes: 4

Marcus Junius Brutus
Marcus Junius Brutus

Reputation: 27286

Based on the suggestion by JB Nizzet, this is what I ended up doing (I added some extra logic to be able to assert whether I expect the parameter to be present, and if so, how many times):

public static URI removeParameterFromURI(URI uri, String parameter, boolean assertAtLeastOneIsFound, Integer assertHowManyAreExpected) {
    Assert.assertFalse("it makes no sense to expect 0 or less", (assertHowManyAreExpected!=null) && (assertHowManyAreExpected<=0) );
    Assert.assertFalse("it makes no sense to not assert that at least one is found and at the same time assert a definite expected number", (!assertAtLeastOneIsFound) && (assertHowManyAreExpected!=null) );
    String queryString = uri.getQuery();
    if (queryString==null)
        return uri;
    Map<String, List<String>> params = parseQuery(queryString);
    Map<String, List<String>> paramsModified = new LinkedHashMap<>();
    boolean found = false;
    for (String key: params.keySet()) {
        if (!key.equals(parameter))
            Assert.assertNull(paramsModified.put(key, params.get(key)));
        else {
            found = true;
            if (assertHowManyAreExpected!=null) {
                Assert.assertEquals((long) assertHowManyAreExpected, params.get(key).size());
            }
        }
    }
    if (assertAtLeastOneIsFound)
        Assert.assertTrue(found);
    UriBuilder uriBuilder = UriBuilder.fromUri(uri)
        .replaceQuery("");
    for (String key: paramsModified.keySet()) {
        List<String> values = paramsModified.get(key);
        uriBuilder = uriBuilder.queryParam(key, (Object[]) values.toArray(new String[values.size()]));
    }
    return uriBuilder.build();
}

public static String removeParameterFromURI(String uri, String parameter, boolean assertAtLeastOneIsFound, Integer assertHowManyAreExpected) {
    try {
        return removeParameterFromURI(new URI(uri), parameter, assertAtLeastOneIsFound, assertHowManyAreExpected).toString();
    } catch (URISyntaxException e) {
        throw new RuntimeException(e);
    }
}

private static Map<String, List<String>> parseQuery(String queryString) {
    try {
        final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
        final String[] pairs = queryString.split("&");
        for (String pair : pairs) {
            final int idx = pair.indexOf("=");
            final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8.name()) : pair;
            if (!query_pairs.containsKey(key)) {
                query_pairs.put(key, new ArrayList<String>());
            }
            final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8.name()) : null;
            query_pairs.get(key).add(value);
        }
        return query_pairs;
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
    }
}

Upvotes: 1

SedJ601
SedJ601

Reputation: 13859

I am not sure if there is some library to help, but I would just split the string on "?" and take the second half and split it on "&". Then I would rebuild the string accordingly.

    public static void main(String[] args) {
        // TODO code application logic here
        System.out.println("original: http://a.b.c/d/e/f?foo=1&bar=2&zar=3");
        System.out.println("new     : " + fixString("http://a.b.c/d/e/f?foo=1&bar=2&zar=3"));
    }

    static String fixString(String original)
    {
        String[] processing = original.split("\\?");
        String[] processing2ndHalf = processing[1].split("&");

        return processing[0] + "?" + processing2ndHalf[1] + "&" + processing2ndHalf[0] + "&" + processing2ndHalf[2];
    }

Output:

enter image description here

To remove a paramater just remove it from the return string.

Upvotes: 0

Related Questions