My function looks like this:
#PUT
#Path("property/{uuid}/{key}/{value}")
#Produces("application/xml")
public Map<String,ValueEntity> updateProperty(#Context HttpServletRequest request,
#PathParam("key") String key,
#PathParam("value") String value,
#PathParam("uuid") String uuid) throws Exception {
...
}
I have to modify it, so it accepts indefinite(or many) list of key-value pairs from REST call, something like
#Path("property/{uuid}/{key1}/{value1}/{key2}/{value2}/{key3}/{value3}/...")
Is it possible to store them in an array or list, so I do not list dozens of #PathParams and parameters, to avoid this:
#PathParam("key1") String key1,
#PathParam("key2") String key2,
#PathParam("key3") String key3,
Might be a good opportunity to rethink this design. By using /s, we are in a way signifying, with each / that we are trying to locate a different resource. Key/Value pairs (in the context of the URL) are mainly for query parameters or matrix parameters.
If /property/{uuid} is the path to a main resource, and we just want to offer some parameters to the client for accessing this resource, then we could allow matrix parameters or query parameters
Matrix Parameters (in a request url) will look something like
/12345;key1=value1;key2=value2;key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getMatrix(#PathParam("uuid") PathSegment pathSegment) {
StringBuilder builder = new StringBuilder();
// Get the {uuid} value
System.out.println("Path: " + pathSegment.getPath());
MultivaluedMap matrix = pathSegment.getMatrixParameters();
for (Object key : matrix.keySet()) {
builder.append(key).append(":")
.append(matrix.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See PathSegment
Query Parameters (in a request url) might look something like
/12345?key1=value1&key2=value2&key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getQuery(#PathParam("uuid") String uuid,
#Context UriInfo uriInfo) {
MultivaluedMap params = uriInfo.getQueryParameters();
StringBuilder builder = new StringBuilder();
for (Object key : params.keySet()) {
builder.append(key).append(":")
.append(params.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See UriInfo
The difference is that Matrix parameters can be embedded into path segments, while query parameters must be placed at the end of the URL. You can also notice a little difference in syntax.
Some Resources
Query String (Wikipedia)
When to use query parameters versus matrix parameters?
URL matrix parameters vs. request parameters
UPDATE
Also looking at the PUT in you method signature, it appears you are trying update a resource using the path as the values for which you are trying to update, as I don't see any parameters in your method for an entity body. When PUTting, you should be sending the representation in the the entity body, not as as path segments or parameters.
A workaround:
#Path("/foo/bar/{other: .*}
public Response foo(#PathParam("other") VariableStrings vstrings) {
String[] splitPath = vstrings.getSplitPath();
}
VariableStrings class:
public class VariableStrings {
private String[] splitPath;
public VariableStrings(String unparsedPath) {
splitPath = unparsedPath.split("/");
}
}
Path segment sequence to vararg array in JAX-RS / Jersey?
Another example where you map the optional parameter to a Map:
#GET
# Produces({"application/xml", "application/json", "plain/text"})
# Path("/location/{locationId}{path:.*}")
public Response getLocation(#PathParam("locationId") int locationId, #PathParam("path") String path) {
Map < String, String > params = parsePath(path);
String format = params.get("format");
if ("xml".equals(format)) {
String xml = "<location<</location<<id<</id<" + locationId + "";
return Response.status(200).type("application/xml").entity(xml).build();
} else if ("json".equals(format)) {
String json = "{ 'location' : { 'id' : '" + locationId + "' } }";
return Response.status(200).type("application/json").entity(json).build();
} else {
String text = "Location: id=" + locationId;
return Response.status(200).type("text/plain").entity(text).build();
}
}
private Map < String, String > parsePath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
String[] pathParts = path.split("/");
Map < String, String > pathMap = new HashMap < String, String > ();
for (int i = 0; i < pathParts.length / 2; i++) {
String key = pathParts[2 * i];
String value = pathParts[2 * i + 1];
pathMap.put(key, value);
}
return pathMap;
}
I have a URL and I need to get the value of v from this URL.
Here is my URL: http://www.youtube.com/watch?v=_RCIP6OrQrE
How can I do that?
I think the one of the easiest ways out would be to parse the string returned by URL.getQuery() as
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;
}
You can use the map returned by this function to retrieve the value keying in the parameter name.
If you're on Android, you can do this:
Uri uri = Uri.parse(url);
String v = uri.getQueryParameter("v");
I have something like this:
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
private String getParamValue(String link, String paramName) throws URISyntaxException {
List<NameValuePair> queryParams = new URIBuilder(link).getQueryParams();
return queryParams.stream()
.filter(param -> param.getName().equalsIgnoreCase(paramName))
.map(NameValuePair::getValue)
.findFirst()
.orElse("");
}
I wrote this last month for Joomla Module when implementing youtube videos (with the Gdata API). I've since converted it to java.
Import These Libraries
import java.net.URL;
import java.util.regex.*;
Copy/Paste this function
public String getVideoId( String videoId ) throws Exception {
String pattern = "^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(videoId);
int youtu = videoId.indexOf("youtu");
if(m.matches() && youtu != -1){
int ytu = videoId.indexOf("http://youtu.be/");
if(ytu != -1) {
String[] split = videoId.split(".be/");
return split[1];
}
URL youtube = new URL(videoId);
String[] split = youtube.getQuery().split("=");
int query = split[1].indexOf("&");
if(query != -1){
String[] nSplit = split[1].split("&");
return nSplit[0];
} else return split[1];
}
return null; //throw something or return what you want
}
URL's it will work with
http://www.youtube.com/watch?v=k0BWlvnBmIE (General URL)
http://youtu.be/k0BWlvnBmIE (Share URL)
http://www.youtube.com/watch?v=UWb5Qc-fBvk&list=FLzH5IF4Lwgv-DM3CupM3Zog&index=2 (Playlist URL)
Import these libraries
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
Similar to the verisimilitude, but with the capabilities of handling multivalue parameters. Note: I've seen HTTP GET requests without a value, in this case the value will be null.
public static List<NameValuePair> getQueryMap(String query)
{
List<NameValuePair> queryMap = new ArrayList<NameValuePair>();
String[] params = query.split(Pattern.quote("&"));
for (String param : params)
{
String[] chunks = param.split(Pattern.quote("="));
String name = chunks[0], value = null;
if(chunks.length > 1) {
value = chunks[1];
}
queryMap.add(new BasicNameValuePair(name, value));
}
return queryMap;
}
Example:
GET /bottom.gif?e235c08=1509896923&%49%6E%...
Using pure Java 8
Assumming you want to extract param "v" from url:
String paramV = Stream.of(url.split("?")[1].split("&"))
.map(kv -> kv.split("="))
.filter(kv -> "v".equalsIgnoreCase(kv[0]))
.map(kv -> kv[1])
.findFirst()
.orElse("");
Assuming the URL syntax will always be http://www.youtube.com/watch?v= ...
String v = "http://www.youtube.com/watch?v=_RCIP6OrQrE".substring(31);
or disregarding the prefix syntax:
String url = "http://www.youtube.com/watch?v=_RCIP6OrQrE";
String v = url.substring(url.indexOf("v=") + 2);
I believe we have a better approach to answer this question.
1: Define a function that returns Map values.
Here we go.
public Map<String, String> getUrlValues(String url) throws UnsupportedEncodingException {
int i = url.indexOf("?");
Map<String, String> paramsMap = new HashMap<>();
if (i > -1) {
String searchURL = url.substring(url.indexOf("?") + 1);
String params[] = searchURL.split("&");
for (String param : params) {
String temp[] = param.split("=");
paramsMap.put(temp[0], java.net.URLDecoder.decode(temp[1], "UTF-8"));
}
}
return paramsMap;
}
2: Call your function surrounding with a try catch block
Here we go
try {
Map<String, String> values = getUrlValues("https://example.com/index.php?form_id=9&page=1&view_id=78");
String formId = values.get("form_id");
String page = values.get("page");
String viewId = values.get("view_id");
Log.d("FormID", formId);
Log.d("Page", page);
Log.d("ViewID", viewId);
} catch (UnsupportedEncodingException e) {
Log.e("Error", e.getMessage());
}
If you are using Jersey (which I was, my server component needs to make outbound HTTP requests) it contains the following public method:
var multiValueMap = UriComponent.decodeQuery(uri, true);
It is part of org.glassfish.jersey.uri.UriComponent, and the javadoc is here. Whilst you may not want all of Jersey, it is part of the Jersey common package which isn't too bad on dependencies...
I solved the problem like this
public static String getUrlParameterValue(String url, String paramName) {
String value = "";
List<NameValuePair> result = null;
try {
result = URLEncodedUtils.parse(new URI(url), UTF_8);
value = result.stream().filter(pair -> pair.getName().equals(paramName)).findFirst().get().getValue();
System.out.println("--------------> \n" + paramName + " : " + value + "\n");
} catch (URISyntaxException e) {
e.printStackTrace();
}
return value;
}
this will work for all sort of youtube url :
if url could be
youtube.com/?v=_RCIP6OrQrE
youtube.com/v/_RCIP6OrQrE
youtube.com/watch?v=_RCIP6OrQrE
youtube.com/watch?v=_RCIP6OrQrE&feature=whatever&this=that
Pattern p = Pattern.compile("http.*\\?v=([a-zA-Z0-9_\\-]+)(?:&.)*");
String url = "http://www.youtube.com/watch?v=_RCIP6OrQrE";
Matcher m = p.matcher(url.trim()); //trim to remove leading and trailing space if any
if (m.matches()) {
url = m.group(1);
}
System.out.println(url);
this will extract video id from your url
further reference
My solution mayble not good
String url = "https://www.youtube.com/watch?param=test&v=XcHJMiSy_1c&lis=test";
int start = url.indexOf("v=")+2;
// int start = url.indexOf("list=")+5; **5 is length of ("list=")**
int end = url.indexOf("&", start);
end = (end == -1 ? url.length() : end);
System.out.println(url.substring(start, end));
// result: XcHJMiSy_1c
work fine with:
https://www.youtube.com/watch?param=test&v=XcHJMiSy_1c&lis=test
https://www.youtube.com/watch?v=XcHJMiSy_1c
public static String getQueryMap(String query) {
String[] params = query.split("&");
for (String param : params) {
String name = param.split("=")[0];
if ("YourParam".equals(name)) {
return param.split("=")[1];
}
}
return null;
}
The places with ** around them throw cannot find symbol method getValue() error.
The code by the way is part of a program to check validity of mine-craft account names; if they're available or not.
public String connectToMigrate() {
try {
Connection.Response response =
Jsoup.connect("https://account.mojang.com/migrate").execute();
Document doc = response.parse();
Element authToken = doc.select("input[name^=authenticityToken]").get(0);
Map cookies = response.cookies();
Connection connection =
Jsoup.connect("https://account.mojang.com/migrate/check")
.data("authenticityToken", authToken.val())
.data("mcusername", this.username)
.data("password", this.password)
.method(Connection.Method.POST)
.followRedirects(true);
connection.timeout(10000);
for (Object cookie : cookies.entrySet()) {
connection.cookie((String) **cookie.getValue**(), (String) **cookie.getKey**());
}
Connection.Response postResponse = connection.execute();
if (postResponse.body().toLowerCase().contains("invalid username"))
return "error";
if (postResponse.body().toLowerCase().contains("already been migrated"))
return "error";
if (postResponse.body().toLowerCase().contains("locked out"))
return "error";
if (postResponse.body().toLowerCase().contains("bought minecraft"))
return "error";
if (postResponse.body().toLowerCase().contains("too many failed attempts")) {
getNewProxy();
return "try again";
}
if (postResponse.body().toLowerCase().contains("error")) {
return "try again";
}
Map cookies2 = postResponse.cookies();
Connection connection2 =
Jsoup.connect("https://account.mojang.com/migrate/chooseEmail");
for (Object cookie : cookies2.entrySet()) {
connection2.cookie((String) **cookie.getValue()**, (String) **cookie.getKey()**);
}
connection2.timeout(10000);
Connection.Response postResponse2 = connection2.execute();
String s = postResponse2.body().toLowerCase();
s = s.split("i want to use <strong>")[1];
s = s.split("</strong>")[0];
String email = s;
return email; } catch (Exception e) {
}return "try again";
}
cookie is an Object which doesn't contain getValue() method. You need to cast it to proper type before calling getValue().
i think you just misunderstood how to use maps in java.
it should be quite easy, try this:
Map<String,String> cookies = response.cookies();
[...]
for ( Map.Entry<String,String> e : cookies.entrySet()){
connection.cookie( e.getKey(), e.getValue() );
}
however, you can copy all the cookies at once by doing this:
connection.cookies( response.cookies() );
getCookies on the JSoup Connection.Response object returns a Map<String, String>.
So in your first for loop:
for (Object cookie : cookies.entrySet())
each cookie is a Set, and Set doesn't support these methods (see the docs).
Instead, in these loops you should iterate over the Map keys, which will be the cookie names:
for (Object cookie : cookies.keySet())
Now each cookie is the key, and you can query the original map for the value with cookies.get(cookie).
But Jsoup's Connection already allows you to copy the cookies directly (see the docs), no loop necessary:
connection.cookies(response.cookies());
I have a String containing a URL. I want to get just one piece of data out of it: an int that should be showing up in the query string.
So if the url is:
http://domain.tld/page.html?iVar=123
I want to get "123" into an int.
What's the most elegant way you know to do this?
You could try matching just that parameter in the URL string:
public static Integer getIVarParamValue(String urlStr) {
Pattern p = Pattern.compile("iVar=(\\d+)");
Matcher m = p.matcher(urlStr);
if (m.find()) {
return Integer.parseInt(m.group(1));
}
return null;
}
It seems you want to obtain get parameters and parse them. I have this method here (got it from somewhere on SO, I guess):
public static Map<String, List<String>> getQueryParams(String url) {
try {
Map<String, List<String>> params = new HashMap<String, List<String>>();
String[] urlParts = url.split("\\?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String[] pair = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
return params;
} catch (UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
}
So:
String var = WebUtils.getQueryParams(url).get("iVar");
int intVar = Integer.parseInt(var);
You can use the URL class.
i.e.:
URL myUrl = new URL("http://domain.tld/page.html?iVar=123");
String query = myUrl.getQuery(); //this will return iVar=123
//at this point you can either parse it manually (i.e. use some of the regexp in the other suggestions, or use something like:
String[] parts = query.split();
String variable = parts[0];
String value = parts[1];
This will work only for this case though and won't work if you have additional params or no params.
There are a number of solution that will split it into a param map online, you can see some here.
If it's really as simple as you describe: There is only 1 int in your URL and all you want is that int, I'd go for a regular expression. If it is actually more complicated see the other answers.
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher("http://domain.tld/page.html?iVar=123");
if (m.find())
System.out.println(m.group());
This also could do the work :
public static int getIntParam(HttpServletRequest request, String name, int defaultValue) {
String value = request.getParameter(name);
try {
if (value != null) {
return Integer.valueOf(value);
}
} catch (NumberFormatException e) {
}
return defaultValue;
}
Hope it helps!
If the query string part of the URL is always the same (so if it was always iVar) you could use urlAsString.indexOf("iVar=") to find iVar= and then knowing the number is after that, extract the number. That is admittedly not the least brittle approach.
But if you're looking for all the query strings then Bozho's answer is much better.
Java EE has ServletRequest.getParameterValues().
On non-EE platforms, URL.getQuery() simply returns a string.
What's the normal way to properly parse the query string in a URL when not on Java EE?
It is popular in the answers to try and make your own parser. This is very interesting and exciting micro-coding project, but I cannot say that it is a good idea.
The code snippets below are generally flawed or broken. Breaking them is an interesting exercise for the reader. And to the hackers attacking the websites that use them.
Parsing query strings is a well defined problem but reading the spec and understanding the nuances is non-trivial. It is far better to let some platform library coder do the hard work, and do the fixing, for you!
On Android:
import android.net.Uri;
[...]
Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");
Since Android M things have got more complicated. The answer of android.net.URI.getQueryParameter() has a bug which breaks spaces before JellyBean.
Apache URLEncodedUtils.parse() worked, but was deprecated in L, and removed in M.
So the best answer now is UrlQuerySanitizer. This has existed since API level 1 and still exists. It also makes you think about the tricky issues like how do you handle special characters, or repeated values.
The simplest code is
UrlQuerySanitizer.ValueSanitizer sanitizer = UrlQuerySanitizer.getAllButNullLegal();
// remember to decide if you want the first or last parameter with the same name
// If you want the first call setPreferFirstRepeatedParameter(true);
sanitizer.parseUrl(url);
String value = sanitizer.getValue("paramName");
If you are happy with the default parsing behavior you can do:
new UrlQuerySanitizer(url).getValue("paramName")
but you should make sure you understand what the default parsing behavor is, as it might not be what you want.
On Android, the Apache libraries provide a Query parser:
http://developer.android.com/reference/org/apache/http/client/utils/URLEncodedUtils.html and http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URLEncodedUtils.html
public static Map<String, List<String>> getUrlParameters(String url)
throws UnsupportedEncodingException {
Map<String, List<String>> params = new HashMap<String, List<String>>();
String[] urlParts = url.split("\\?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String pair[] = param.split("=", 2);
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
return params;
}
If you have jetty (server or client) libs on your classpath you can use the jetty util classes (see javadoc), e.g.:
import org.eclipse.jetty.util.*;
URL url = new URL("www.example.com/index.php?foo=bar&bla=blub");
MultiMap<String> params = new MultiMap<String>();
UrlEncoded.decodeTo(url.getQuery(), params, "UTF-8");
assert params.getString("foo").equals("bar");
assert params.getString("bla").equals("blub");
If you're using Spring 3.1 or greater (yikes, was hoping that support went back further), you can use the UriComponents and UriComponentsBuilder:
UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");
components.getQueryParams() returns a MultiValueMap<String, String>
Here's some more documentation.
I have methods to achieve this:
1):
public static String getQueryString(String url, String tag) {
String[] params = url.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);
}
Set<String> keys = map.keySet();
for (String key : keys) {
if(key.equals(tag)){
return map.get(key);
}
System.out.println("Name=" + key);
System.out.println("Value=" + map.get(key));
}
return "";
}
2) and the easiest way to do this Using Uri class:
public static String getQueryString(String url, String tag) {
try {
Uri uri=Uri.parse(url);
return uri.getQueryParameter(tag);
}catch(Exception e){
Log.e(TAG,"getQueryString() " + e.getMessage());
}
return "";
}
and this is an example of how to use either of two methods:
String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";
String tagValue = getQueryString(url,"awidth");
the value of tagValue is 800
For a servlet or a JSP page you can get querystring key/value pairs by using request.getParameter("paramname")
String name = request.getParameter("name");
There are other ways of doing it but that's the way I do it in all the servlets and jsp pages that I create.
On Android, I tried using #diyism answer but I encountered the space character issue raised by #rpetrich, for example:
I fill out a form where username = "us+us" and password = "pw pw" causing a URL string to look like:
http://somewhere?username=us%2Bus&password=pw+pw
However, #diyism code returns "us+us" and "pw+pw", i.e. it doesn't detect the space character. If the URL was rewritten with %20 the space character gets identified:
http://somewhere?username=us%2Bus&password=pw%20pw
This leads to the following fix:
Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");
Parsing the query string is a bit more complicated than it seems, depending on how forgiving you want to be.
First, the query string is ascii bytes. You read in these bytes one at a time and convert them to characters. If the character is ? or & then it signals the start of a parameter name. If the character is = then it signals the start of a paramter value. If the character is % then it signals the start of an encoded byte. Here is where it gets tricky.
When you read in a % char you have to read the next two bytes and interpret them as hex digits. That means the next two bytes will be 0-9, a-f or A-F. Glue these two hex digits together to get your byte value. But remember, bytes are not characters. You have to know what encoding was used to encode the characters. The character é does not encode the same in UTF-8 as it does in ISO-8859-1. In general it's impossible to know what encoding was used for a given character set. I always use UTF-8 because my web site is configured to always serve everything using UTF-8 but in practice you can't be certain. Some user-agents will tell you the character encoding in the request; you can try to read that if you have a full HTTP request. If you just have a url in isolation, good luck.
Anyway, assuming you are using UTF-8 or some other multi-byte character encoding, now that you've decoded one encoded byte you have to set it aside until you capture the next byte. You need all the encoded bytes that are together because you can't url-decode properly one byte at a time. Set aside all the bytes that are together then decode them all at once to reconstruct your character.
Plus it gets more fun if you want to be lenient and account for user-agents that mangle urls. For example, some webmail clients double-encode things. Or double up the ?&= chars (for example: http://yoursite.com/blah??p1==v1&&p2==v2). If you want to try to gracefully deal with this, you will need to add more logic to your parser.
On Android its simple as the code below:
UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");
Also if you don't want to register each expected query key use:
sanitzer.setAllowUnregisteredParamaters(true)
Before calling:
sanitzer.parseUrl(yourUrl)
On Android, you can use the Uri.parse static method of the android.net.Uri class to do the heavy lifting. If you're doing anything with URIs and Intents you'll want to use it anyways.
Just for reference, this is what I've ended up with (based on URLEncodedUtils, and returning a Map).
Features:
it accepts the query string part of the url (you can use request.getQueryString())
an empty query string will produce an empty Map
a parameter without a value (?test) will be mapped to an empty List<String>
Code:
public static Map<String, List<String>> getParameterMapOfLists(String queryString) {
Map<String, List<String>> mapOfLists = new HashMap<String, List<String>>();
if (queryString == null || queryString.length() == 0) {
return mapOfLists;
}
List<NameValuePair> list = URLEncodedUtils.parse(URI.create("http://localhost/?" + queryString), "UTF-8");
for (NameValuePair pair : list) {
List<String> values = mapOfLists.get(pair.getName());
if (values == null) {
values = new ArrayList<String>();
mapOfLists.put(pair.getName(), values);
}
if (pair.getValue() != null) {
values.add(pair.getValue());
}
}
return mapOfLists;
}
A compatibility helper (values are stored in a String array just as in ServletRequest.getParameterMap()):
public static Map<String, String[]> getParameterMap(String queryString) {
Map<String, List<String>> mapOfLists = getParameterMapOfLists(queryString);
Map<String, String[]> mapOfArrays = new HashMap<String, String[]>();
for (String key : mapOfLists.keySet()) {
mapOfArrays.put(key, mapOfLists.get(key).toArray(new String[] {}));
}
return mapOfArrays;
}
This works for me..
I'm not sure why every one was after a Map, List>
All I needed was a simple name value Map.
To keep things simple I used the build in URI.getQuery();
public static Map<String, String> getUrlParameters(URI uri)
throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
for (String param : uri.getQuery().split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
params.put(new String(key), new String(value));
}
return params;
}
Guava's Multimap is better suited for this. Here is a short clean version:
Multimap<String, String> getUrlParameters(String url) {
try {
Multimap<String, String> ret = ArrayListMultimap.create();
for (NameValuePair param : URLEncodedUtils.parse(new URI(url), "UTF-8")) {
ret.put(param.getName(), param.getValue());
}
return ret;
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
Origanally answered here
On Android, there is Uri class in package android.net . Note that Uri is part of android.net, while URI is part of java.net .
Uri class has many functions to extract query key-value pairs.
Following function returns key-value pairs in the form of HashMap.
In Java:
Map<String, String> getQueryKeyValueMap(Uri uri){
HashMap<String, String> keyValueMap = new HashMap();
String key;
String value;
Set<String> keyNamesList = uri.getQueryParameterNames();
Iterator iterator = keyNamesList.iterator();
while (iterator.hasNext()){
key = (String) iterator.next();
value = uri.getQueryParameter(key);
keyValueMap.put(key, value);
}
return keyValueMap;
}
In Kotlin:
fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
val keyValueMap = HashMap<String, String>()
var key: String
var value: String
val keyNamesList = uri.queryParameterNames
val iterator = keyNamesList.iterator()
while (iterator.hasNext()) {
key = iterator.next() as String
value = uri.getQueryParameter(key) as String
keyValueMap.put(key, value)
}
return keyValueMap
}
Apache AXIS2 has a self-contained implementation of QueryStringParser.java. If you are not using Axis2, just download the sourcecode and test case from here -
http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/src/org/apache/axis2/transport/http/util/QueryStringParser.java
http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/test/org/apache/axis2/transport/http/util/QueryStringParserTest.java
if (queryString != null)
{
final String[] arrParameters = queryString.split("&");
for (final String tempParameterString : arrParameters)
{
final String[] arrTempParameter = tempParameterString.split("=");
if (arrTempParameter.length >= 2)
{
final String parameterKey = arrTempParameter[0];
final String parameterValue = arrTempParameter[1];
//do something with the parameters
}
}
}
I don't think there is one in JRE. You can find similar functions in other packages like Apache HttpClient. If you don't use any other packages, you just have to write your own. It's not that hard. Here is what I use,
public class QueryString {
private Map<String, List<String>> parameters;
public QueryString(String qs) {
parameters = new TreeMap<String, List<String>>();
// Parse query string
String pairs[] = qs.split("&");
for (String pair : pairs) {
String name;
String value;
int pos = pair.indexOf('=');
// for "n=", the value is "", for "n", the value is null
if (pos == -1) {
name = pair;
value = null;
} else {
try {
name = URLDecoder.decode(pair.substring(0, pos), "UTF-8");
value = URLDecoder.decode(pair.substring(pos+1, pair.length()), "UTF-8");
} catch (UnsupportedEncodingException e) {
// Not really possible, throw unchecked
throw new IllegalStateException("No UTF-8");
}
}
List<String> list = parameters.get(name);
if (list == null) {
list = new ArrayList<String>();
parameters.put(name, list);
}
list.add(value);
}
}
public String getParameter(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
if (values.size() == 0)
return "";
return values.get(0);
}
public String[] getParameterValues(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
return (String[])values.toArray(new String[values.size()]);
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameters.keySet());
}
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new TreeMap<String, String[]>();
for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
List<String> list = entry.getValue();
String[] values;
if (list == null)
values = null;
else
values = (String[]) list.toArray(new String[list.size()]);
map.put(entry.getKey(), values);
}
return map;
}
}
public static Map <String, String> parseQueryString (final URL url)
throws UnsupportedEncodingException
{
final Map <String, String> qps = new TreeMap <String, String> ();
final StringTokenizer pairs = new StringTokenizer (url.getQuery (), "&");
while (pairs.hasMoreTokens ())
{
final String pair = pairs.nextToken ();
final StringTokenizer parts = new StringTokenizer (pair, "=");
final String name = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
final String value = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
qps.put (name, value);
}
return qps;
}
Use Apache HttpComponents and wire it up with some collection code to access params by value: http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-java-and-accessing-values-by-key/
using Guava:
Multimap<String,String> parseQueryString(String queryString, String encoding) {
LinkedListMultimap<String, String> result = LinkedListMultimap.create();
for(String entry : Splitter.on("&").omitEmptyStrings().split(queryString)) {
String pair [] = entry.split("=", 2);
try {
result.put(URLDecoder.decode(pair[0], encoding), pair.length == 2 ? URLDecoder.decode(pair[1], encoding) : null);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return result;
}
Answering here because this is a popular thread. This is a clean solution in Kotlin that uses the recommended UrlQuerySanitizer api. See the official documentation. I have added a string builder to concatenate and display the params.
var myURL: String? = null
// if the url is sent from a different activity where you set it to a value
if (intent.hasExtra("my_value")) {
myURL = intent.extras.getString("my_value")
} else {
myURL = intent.dataString
}
val sanitizer = UrlQuerySanitizer(myURL)
// We don't want to manually define every expected query *key*, so we set this to true
sanitizer.allowUnregisteredParamaters = true
val parameterNamesToValues: List<UrlQuerySanitizer.ParameterValuePair> = sanitizer.parameterList
val parameterIterator: Iterator<UrlQuerySanitizer.ParameterValuePair> = parameterNamesToValues.iterator()
// Helper simply so we can display all values on screen
val stringBuilder = StringBuilder()
while (parameterIterator.hasNext()) {
val parameterValuePair: UrlQuerySanitizer.ParameterValuePair = parameterIterator.next()
val parameterName: String = parameterValuePair.mParameter
val parameterValue: String = parameterValuePair.mValue
// Append string to display all key value pairs
stringBuilder.append("Key: $parameterName\nValue: $parameterValue\n\n")
}
// Set a textView's text to display the string
val paramListString = stringBuilder.toString()
val textView: TextView = findViewById(R.id.activity_title) as TextView
textView.text = "Paramlist is \n\n$paramListString"
// to check if the url has specific keys
if (sanitizer.hasParameter("type")) {
val type = sanitizer.getValue("type")
println("sanitizer has type param $type")
}
this method takes the uri and return map of par name and par value
public static Map<String, String> getQueryMap(String uri) {
String queryParms[] = uri.split("\\?");
Map<String, String> map = new HashMap<>();//
if (queryParms == null || queryParms.length == 0) return map;
String[] params = queryParms[1].split("&");
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
return map;
}
You say "Java" but "not Java EE". Do you mean you are using JSP and/or servlets but not a full Java EE stack? If that's the case, then you should still have request.getParameter() available to you.
If you mean you are writing Java but you are not writing JSPs nor servlets, or that you're just using Java as your reference point but you're on some other platform that doesn't have built-in parameter parsing ... Wow, that just sounds like an unlikely question, but if so, the principle would be:
xparm=0
word=""
loop
get next char
if no char
exit loop
if char=='='
param_name[xparm]=word
word=""
else if char=='&'
param_value[xparm]=word
word=""
xparm=xparm+1
else if char=='%'
read next two chars
word=word+interpret the chars as hex digits to make a byte
else
word=word+char
(I could write Java code but that would be pointless, because if you have Java available, you can just use request.getParameters.)