Extract parameter / value pairs from an Uri as a Map - dart

How do I get the parameter / value pairs of an URL / URI using Dart? Unfortunately currently there is no built-in functionality for this problem neither in the Uri library or the Location interface.

You can use Uri.splitQueryString to split the query into a map.

There is now a queryParameters member of Uri that returns a Map
Uri u = Uri.parse("http://app.org/main?foo=bar&baz=bat");
Map<String,String> qp = u.queryParameters;
print(qp);
// {foo: bar, baz: bat}

// url=http://127.0.0.1:3030/path/Sandbox.html?paramA=1&parmB=2#myhash
void main() {
String querystring = window.location.search.replaceFirst("?", "");
List<String> list = querystring.split("&").forEach((e) => e.split("="));
print(list); // [[paramA, 1], [parmB, 2]]
}

Map<String, String> getUriParams(String uriSearch) {
if (uriSearch != '') {
final List<String> paramValuePairs = uriSearch.substring(1).split('&');
var paramMapping = new HashMap<String, String>();
paramValuePairs.forEach((e) {
if (e.contains('=')) {
final paramValue = e.split('=');
paramMapping[paramValue[0]] = paramValue[1];
} else {
paramMapping[e] = '';
}
});
return paramMapping;
}
}
// Uri: http://localhost:8080/incubator/main.html?param=value&param1&param2=value2&param3
final uriSearch = window.location.search;
final paramMapping = getUriParams(uriSearch);

Related

Generate Nested Map from Path String in dart

I want to create a map using the path
generateNestedMap("foo.bar.baz", "someValue")
and the output should be
Output: {'foo'{'bar':{'baz': 'someValue'}}}
Run this in dartpad. No recursion required. Just build it from inside-out:
void main() {
print(generateNestedMap("foo.bar.baz", "someValue"));
}
Map generateNestedMap(String path, String payload) {
var steps = path.split('.');
Object result = payload;
for (var step in steps.reversed) {
result = {step : result};
}
return result as Map;
}
EDIT: Or, as I suggested in one of the comments, a little fancier, but cool:
void main() {
print(generateNestedMap("foo.bar.baz", "someValue"));
}
Map generateNestedMap(String path, String payload) {
var steps = path.split('.');
var result = steps.reversed.fold(payload, (old, next) => {next: old});
return result as Map;
}

Convert Stream<List<T>> to Stream<Map<K,T>>

I have a requirement of converting Stream<List<T>> to Stream<Map<K,T>>
I have a class
class Order
{
int id;
DateTime date;
}
I want to convert Stream<List<Order>> to Stream<Map<DateTime, List<Order>>
I want to display orders as below
12-Dec-2020
Order 1
Order 2
13-Dec-2020
Order 3
Order 4
14-Dec-2020
Order 5
Order 6
Suggestions for a better DS are welcome.
How do I do this?
Please suggest.
Thanks in advance.
Using groupListsBy from collection: ^1.15.0
K keySelector(T t) { ... }
final Stream<List<T>> source$ = ...;
final Stream<Map<K, List<T>>> result$ = source$.map((list) => list.groupListsBy(keySelector));
You can do this without any package.
First, you have to create an empty Map, then map a List<Order> to a map with a key as a date from the list item (single order) then add it to That Empty map.
Check if the date is available as a key in Map. If the date exists as a key in that map then simply add a new order to that value or else simply add a new key to the Map.
Code:
Stream<List<Order>> orders = ...;
Stream<Map<DateTime, List<Order>>> ordersByDate = {};
orders.forEach((Order order){
ordersByDate.keys.contains(order.date)
? ordersByDate.update(order.date, (oldValue) => oldValue + <Order>[order])
: ordersByDate[order.date] = [order];
});
print(ordersByDate);
//At here your ordersByDate
Let me know if it works for you.
Fold method is what you're looking for.
Example:
void main() async {
final today = DateTime.now();
final tomorrow = today.add(const Duration(days: 1));
final order1 = Order(1, today);
final order2 = Order(2, today);
final order3 = Order(3, tomorrow);
final x = await Stream
.fromIterable([order1, order2, order3])
.fold<Map<DateTime, List<Order>>>({}, (val, element) {
(val[element.date] ??= []).add(element);
// Same as:
// if (val[element.date] == null) {
// val[element.date] = [];
// }
// val[element.date]!.add(element);
return val;
});
print(x);
}
class Order
{
int id;
DateTime date;
Order(this.id, this.date);
#override
String toString() {
return 'Order(id: $id, date: $date)';
}
}

How do I write a custom sorter to sort my springdoc swagger tags by name in the UI?

I am using springdoc-openapi with the latest version (1.3.0). Now I would like sort my tags in the UI by "name" property.
I know about the "springdoc.swagger-ui.tagsSorter" configuration and that I can use a custom sorter function. But I cannot find examples how the function should look like.
I tried the following which does not seem to work:
springdoc.swagger-ui.tagsSorter=(a, b) => a.get("name").localeCompare(b.get("name"))
By default, you can sort tags alphabetically:
https://springdoc.org/faq.html#how-can-i-sort-endpoints-alphabetically
You can have control on the tags order, using OpenApiCustomiser and define your own Comparator:
#Bean
public OpenApiCustomiser sortTagsAlphabetically() {
return openApi -> openApi.setTags(openApi.getTags()
.stream()
.sorted(Comparator.comparing(tag -> StringUtils.stripAccents(tag.getName())))
.collect(Collectors.toList()));
}
With reference from #brianbro's answer, as suggested at https://springdoc.org/faq.html#how-can-i-sort-endpoints-alphabetically
I added
#Tag(name="1. Admin endpoints")
#Tag(name = "2. Everyone's enpoints!")
and below prop to application.yml :
springdoc.swagger-ui.tagsSorter=alpha
And can see them sorted according to numbering on my swagger UI.
For sorting schemas , paths and tags in OpenApi.
#Bean
public OpenApiCustomiser openApiCustomiser() {
return openApi -> {
Map<String, Schema> schemas = openApi.getComponents().getSchemas();
openApi.getComponents().setSchemas(new TreeMap<>(schemas));
};
}
#Bean
public OpenApiCustomiser sortPathsAndTagsAlphabetically() {
return openApi -> {
Map<String, PathItem> paths = openApi.getPaths();
Paths sortedPaths = new Paths();
TreeMap<String, PathItem> sortedTree = new TreeMap<String, PathItem>(paths);
Set<Map.Entry<String, PathItem>> pathItems = sortedTree.entrySet();
Map<String, Map.Entry<String, PathItem>> distinctTagMap = new TreeMap<String, Map.Entry<String, PathItem>>();
for ( Map.Entry<String, PathItem> entry:pathItems) {
PathItem pathItem = entry.getValue();
Operation getOp = pathItem.getGet();
if(getOp != null) {
String tag = getOp.getTags().get(0);
if (!distinctTagMap.containsKey(tag)) {
distinctTagMap.put(tag, entry);
}
}
Operation postOp = pathItem.getPost();
if(postOp != null){
String tag1 = postOp.getTags().get(0);
if(!distinctTagMap.containsKey(tag1)){
distinctTagMap.put(tag1,entry);
}
}
Operation putOp = pathItem.getPut();
if(putOp != null) {
String tag2 = putOp.getTags().get(0);
if (!distinctTagMap.containsKey(tag2)) {
distinctTagMap.put(tag2, entry);
}
}
}
LinkedHashMap<String, PathItem> customOrderMap = new LinkedHashMap<String, PathItem>();
for (Map.Entry<String, PathItem> entry: distinctTagMap.values()) {
customOrderMap.put(entry.getKey(), entry.getValue());
}
for(Map.Entry<String, PathItem> entry : sortedTree.entrySet()) {
customOrderMap.putIfAbsent(entry.getKey(), entry.getValue());
}
sortedPaths.putAll(customOrderMap);
openApi.setPaths(sortedPaths);
};
}

Dart: Use Futures to asynchronously fill a static var

I have defined a static var as Map for all instances of my element. If it contains a specific key, it should use the value. If the key is not contains the instance should get the data with a request and save it in the static map, so other instances could use it.
static var data = new Map();
func() {
if (Elem.data.containsKey(['key']) {
list = Elem.data['key'];
}
else {
Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
}
}
The Problem is that all my instances go into the else, since the key is not contained in the Map at the moment the other instances are at the if. So i need them to wait, until the Data is in the Map.
static var data = new Map();
static Completer _dataCompleter;
Future<bool> func() {
if(_dataCompleter == null) {
_dataCompleter = new Completer();
Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
_dataCompleter.complete(true);
})
}
if(_dataCompleter.isCompleted) {
return new Future.value(true);
}
return _dataCompleter.future;
}
and call it like
func().then((success) => /* continue here when `key` in `data` has a value.
In response to Günter Zöchbauer. I generally avoid using Completers directly:
static var data = new Map();
static Future _pendingFuture;
Future func() {
if (_pendingFuture == null) {
_pendingFuture = Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
});
}
return _pendingFuture;
}

How to remove partucular list of querystring from current page url querystring in c#2.0

Say my current page url has got (http://mysite/english/faq.aspx?faqid=12123&cid=4545&intcid=65456&h=man)
string excludeQuerystring = DynConfig.Item("GoogleSEOLinkSettings/ExcludeQuerystring"); //this is the list of my exclude querystring (cid,intcid,del)
querystring = HttpContext.Current.Request.Url.AbsoluteUri.Split('?')[1]; //I will get faqid=12123&cid=4545,intcid=65456
StringBuilder fullQueryString = new StringBuilder();
if (!string.IsNullOrEmpty(excludeQuerystring) && !string.IsNullOrEmpty(querystring))
{
string[] strEQ = excludeQuerystring.Split(','); //making a array of excluded querystrings
NameValueCollection navValues = HttpUtility.ParseQueryString(querystring); //getting the list of querystring in NameValueCollection
if (navValues.Count > 0)
{
string[] strQ = navValues.AllKeys;
if(strQ.Length>0)
{
}
}
}
querystring= ?+faqid=12123&h=man //here I want updated querystring which does not have any querystring which is there in my excludeQuerystring
I am confused how to get this, actually I want to make a function which will do this all.
Please suggest!!
EDIT:
I applied new code to resolve above problem, however got little stuck while converting NameValueCollection to querystring again.
protected void Page_Load(object sender, EventArgs e)
{
string querystring = string.Empty;
string excludeList = "cid,intcid,del";
if (!string.IsNullOrEmpty(excludeList))
{
string getFinalString = GetQueryString(excludeList);
getFinalString = "?" + getFinalString;
}
}
public string GetQueryString(string excludeArray)
{
string retQueryString = string.Empty;
if (excludeArray.IndexOf(",") != -1)
{
string[] strArray = excludeArray.Split(",".ToCharArray());
NameValueCollection filtered = new NameValueCollection();
filtered.Add(HttpUtility.ParseQueryString(Request.Url.Query));
if (filtered.HasKeys())
{
foreach (string strMatch in strArray)
{
filtered.Remove(strMatch);
}
retQueryString = filtered.ToString(); //Here I am not able to convert back to querystring, however there are other ways to get it like (http://leekelleher.com/2008/06/06/how-to-convert-namevaluecollection-to-a-query-string/), is there any other way to do that
}
}
return retQueryString;
}
Below is the perfect solution I got it, any comments on this.
string excludeList = "cid,intcid,del";
string getFinalString = Regex.Replace(Regex.Replace(Regex.Replace(Request.Url.Query, #"^\?", "&"), "&(" + excludeList.Replace(",", "|") + ")=[^&]*", "", RegexOptions.IgnoreCase), "^&", "?");
We cannot delete a query string directly like below:
Request.QueryString.Remove("foo")
If you do this, you will get an error - collection is read-only. So, we need to write the below code before deleting the query string.
In C#:
PropertyInfo isreadonly =
typeof(System.Collections.Specialized.NameValueCollection).GetProperty(
"IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isreadonly.SetValue(this.Request.QueryString, false, null);
// remove
this.Request.QueryString.Remove("foo");
Hope this will help you !!
yes there is a way to compare two arrays
var array1 = new byte[] { 1, 2, 5, 4 };
var array2 = new byte[] { 1, 2, 3, 4 };
var areEqual = array1.SequenceEqual(array2); //return boolean value True or False

Resources