Get Attribute values and map this values together using SAX parser - android

here i want to get parse Map values in one array list or hash-map i dnt know which is the better way.
Here is my XMl file
I am using SAX parser to parse this thing
<Navigation useNavi="1" auto="1" diable="0" >
<Map MapName="paris" MapPath="\Storage Card\PA\xyz" LoadAtStartup="1" />
<Map MapName="swiss" MapPath="\Storage Card\SW\abc" LoadAtStartup="0" />
<Map MapName="delhi" MapPath="\Storage Card\DE\del" LoadAtStartup="1" />
</Navigation>
Here i want to pasre Map tag , i cant do it easily and also get its attributes values but i want to know how can i manage this Map element attributes values for a example MapName is paris and i want to use its respective values in future like LoadAtStartup attribute value.
How can i manage these 3 maps values ?
Thanks
Sam

Create a class:
class MapObject
public string MapName;
public string MapPath;
public boolean LoadAtStartup;
public MapObject(string name, string path, boolean loadAtStartup){
this.MapName = name;
this.MapPath = path;
this.LoadAtStartup = loadAtStartup;
}
And a container for the class instances:
List<MapObject> mapsObjects = new List<MapObject>();
And new instances in your JSON parser (pseudo code, you already have this)
for each object in JSON data{
mapObjects.add(new MapObject(name attribute, path attribute, loadAtStartup attribute);
}

There are different solutions for your question. Maybe the following will give you a possible solution:
HashMap<String, Pair<String, Boolean>> mapEntries = new HashMap<String, Pair<String,Boolean>>();
//Inside SAX callback
String place = attrs.getValue("MapName");
String path = attrs.getValue("MapPath");
Boolean isLoadAtStartup = Integer.parseInt(attrs.getValue("LoadAtStartup")) == 1;
mapEntries.put(place, new Pair<String, Boolean>(path, isLoadAtStartup));
The above uses the android.util.Pair class. You can use your user-defined container class (as illustrated by #Simon) as well.

Related

Firebase Database change node ID

How can I change the naming of the nodes of my children in the image below?
questions_stats is a List<Integer>, I'm aware that I get integers as nodes Id because this is a List. I create each of the children randomly with a number between 0 and 1000. I set this ID as part of the object and to find it I loop trough the list. What I want is to set the "0671" as the Key of the Object at the moment I create it.
How should I define my object in order to access each child with an Id that I define as a String.
Each of the questions_stats is an object.
This is my UserProfile Class definition.
public class UserProfile implements Parcelable {
private List<Integer> questions_list;
private List<QuestionsStats> questions_stats;
private String country_name, share_code, user_name;
private int token_count;
private Boolean is_guest;
public UserProfile() {
}
public UserProfile(List<Integer> questions_list, List<QuestionsStats> questions_stats, String country_name, String share_code, String user_name, int token_count, Boolean is_guest) {
this.questions_list = questions_list;
this.questions_stats = questions_stats;
this.country_name = country_name;
this.share_code = share_code;
this.user_name = user_name;
this.token_count = token_count;
this.is_guest = is_guest;
}
}
I know I can set them using the child("0159").setValue(QuestionStats) individually.
But for my purpose I need to retrieve the data of the "user" as a whole and then iterate whithin questions_stats like it is a List.
How should I define my UserProfile class in order to achieve what I want?
Anybody could give me a hint?
How can I change the node names of my children in the image below?
Answer: There is no way in which you can change the names of the nodes from your Firebase database. There is no API for doing that. What can you do instead is to attach a listener on that node and get the dataSnapshot object. Having that data, you can write it in another place using other names. You cannot simply rename them from 0 to 0000, 1 to 0001 and so on.
Perhaps I should have asked for How to "Set" the node Id instead of "Change"
What I have is an List<QuestionsStats>, but when using an List<QuestionsStats> you get indexes as Keys, What I want is to have the same List<QuestionsStats> but instead of indexes, String Keys for each of my items.
So I changed my List for a Map<String, QuestionsStats>. Now the tricky part is when parceling the Object. You can use readMap() or writeMap() to parcel as shown here in this answer by #David Wasser, but it gives a warning:
Please use writeBundle(Bundle) instead. Flattens a Map into the parcel
at the current dataPosition(), growing dataCapacity() if needed. The
Map keys must be String objects. The Map values are written using
writeValue(Object) and must follow the specification there. It is
strongly recommended to use writeBundle(Bundle) instead of this
method, since the Bundle class provides a type-safe API that allows
you to avoid mysterious type errors at the point of marshalling.
So with the help of the comments in This Question I parceled using this code, note that I'm leaving the "easy" way commented in case somebody find it useful or have any comment on that :
protected UserProfile(Parcel in) {
// in.readMap(myMap, Object.class.getClassLoader());
myMap = new HashMap<>();
String[] array = in.createStringArray();
Bundle bundle = in.readBundle(Object.class.getClassLoader());
for (String s : array) {
myMap.put(s, (Object) bundle.getParcelable(s));
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// dest.writeMap(myMap);
Bundle bundle = new Bundle();
for (Map.Entry<String, Object> entry : myMap.entrySet()) {
bundle.putParcelable(entry.getKey(), entry.getValue());
}
Set<String> keySet = myMap.keySet();
String[] array = keySet.toArray(new String[keySet.size()]);
dest.writeStringArray(array);
dest.writeBundle(bundle);
}
Why I want this, well at the moment my list contains less than 100 items but it could grow up to a 1000, I'm no Pro, but I believe that if I already know the key of the item I'm interested in will be always better than having to iterate over the list to find it. In the end my main problem was the usage of a Map, I did not know howto.

#Order annotation has no effect on the XML serialization order

I'm using Retrofit 2 with a SimpleXmlConverter and I am facing an issue when creating a Soap Request Object, that is basically an element with 4 element children each one of them being different datatypes.
Here is the XML output I want to produce. The element order must be respected:
<prf:container>
<prf:aaa>111111111</prf:aaa>
<prf:bbb>true</prf:bbb>
<prf:element>
<prf:ddd>50</prf:ddd>
<prf:eee>false</prf:eee>
</prf:element>
<prf:ccc>textcontent</prf:ccc>
</prf:container>
Now, here is my Android Class, Container.java, representing the Soap Request Object that will be serialized:
#Root (name = "prf:container")
#Order(elements={"prf:aaa", "prf:bbb", "prf:element", "prf:ccc"})
public class Container {
#Element (name = "prf:aaa")
private int aaa;
#Element(name = "prf:bbb")
private boolean bbb;
#Element (name = "prf:element", required = false)
private MyElement myElement;
#Element (name = "prf:ccc", required = false)
private String ccc;
}
According to the Simple XML framework documentation:
By default serialization of fields is done in declaration order.
However, in Android, this is not true, at least in some cases. No matter how I set the field declaration order in my Container class, the output has always the same element order. This is a known bug and as has been reported in other SO posts.
Nonetheless, there is a solution to this issue. The Order annotation.
Read more in the Javadoc.
My problem is that using the Order annotation in my case is not helping. Note that all my elements have a prefix on its name - prf:.
If I remove the prf prefix from all my element names, Order annotation will work properly, and force the XML Serialization to have the defined order. But the output elements won't have the prefix on its name.
But I really need my elements to have the prefix on its name, or else my request will have a 500 response. I also have to have the desired element order in my XML output.
Any solution to this?
Thank you
I know it has been a long item since you posted this question but, I would like to answer your question in case anyone faced the same issue. I solved the same issue by doing the following:
For the XML document to be prepared with the elements in the order you want and if the elements have a prefix, #Order annotation might not work in some cases. In your case, the prefix 'prf' mentioned in the #Order annotation for each element would not work to order them as you desired.
"By default serialization of fields is done in declaration order."
I don't believe this either, especially when you have prefixes for elements. So, I tried changing the Java variable names. I tried naming them in alphabetical order in the same way I needed them in the generated xml. So, in your case, you can change the variable names as follows:
#Root (name = "prf:container")
public class Container {
#Element (name = "prf:aaa")
private int element1;
#Element(name = "prf:bbb")
private boolean element2;
#Element (name = "prf:element", required = false)
private MyElement element3;
#Element (name = "prf:ccc", required = false)
private String element4;
}
This would form the xml document exactly as you wanted. You might wonder that if we change the variable names to be too generic, they are not representing what they actually are but, you can always have getters and setters. For example, in your case you can have:
public void setAaa(String aaa){
this.element1 = aaa;
}
public String getAaa(){
return element1;
}
In the same way you can always generate the classes with alphabetically ordered variables to make sure the generated xml has the elements in the desired format.
Maybe you using #Order with wrong syntax,Alphabetical order is not important. You can try:
#Root (name = "prf:container")
#Order(elements={"prf:container/prf:aaa", "prf:container/prf:bbb", "prf:container/prf:element", "prf:container/prf:ccc"})
public class Container {
#Element (name = "prf:aaa")
private int aaa;
#Element(name = "prf:bbb")
private boolean bbb;
#Element (name = "prf:element", required = false)
private MyElement myElement;
#Element (name = "prf:ccc", required = false)
private String ccc;
}
SimpleXML's auto ordering by alphabetical order is working. But on one condition: the type of those fields should be the same, usually for XML it is String. It took me long time to figure that out, I had different types, and ordering by name didn't work. Since I've changed all fields to String works like a charm.
#Root(name = "sch:CheckPaymentRequest", strict = true)
public class CheckPaymentData {
#Element(name = "sch:payId")
private String Aaa1;
#Element(name = "sch:fromCurrency")
private String Bbb2;
#Element(name = "sch:fromAmount")
private String Ccc3;
...}

Simple Xml Parsing error in Android

<GetProductsForMachine>
<Products>
<ProductsForMachine>coffee espresso</ProductsForMachine>
<ProductsForMachine>coffe1</ProductsForMachine>
<ProductsForMachine>coffee2</ProductsForMachine>
</Products>
What must to be the implementation of Class ProductsForMachine,it's difficult because there isn't elements to get theirs value.
I try with following code but i have errors in the parsing..
#Root
public class ProductsForMachine{
#Attribute(name="ProductsForMachine", required=true)
public String ProductsForMachine;
#Element(required=false)
public int value;
}
Thanks
Here's a simple solution assuming that each <ProductsForMachine>...</ProductsForMachine>
entry can be represented by a String.
#Root(name="GetProductsForMachine")
public class GetProductsForMachine
{
#ElementList(name="Products", entry="ProductsForMachine")
private ArrayList<String> products; /* 1 */
// Construtors / Methods
}
Note 1: For the reason why ArrayList<String> is used instead of List<String> please see here.
It's possible to rename the class / field since the name value of the Annotations is set.
You now can deserialize your XML like this:
File f = // your xml file
Serializer ser = new Persister();
GetProductsForMachine products = ser.read(GetProductsForMachine.class, f);
Btw. GetProductsForMachine requires a closing tag.
Have a look at my answer to this question. It provides a general approach to parsing simple xml when looking for a specific tag.

how to get an int value according to its name

I would like to ask how can I get the value of predefined value to its name
The following is my code
public class Calculation_Activity extends Activity{
int a=1;
int b=2;
int c=50;
int result;
String array1[]=new String[]{"a","b","c"};
}
I would like to ask how can I get the value of the string by using array1[i]?
for instance, I would like to use array1[3]to call the value of c[ie.50]
May you give me some advice on this matter?
You might solve your issue by using a Map and its standard implementation HashMap:
Map<String, Integer> values = new HashMap<String, Integer>();
values.put("a",1);
values.put("b",2);
values.put("c",50);
String array1[] = new String[] {"a","b","c"};
int result = values.get(array1[2]); //result = 50
// or
int result = values.get("c"); //result = 50
You can use a HashMap (http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html), is a dictionary like data structure where you can store key-pair values
What you're trying to achieve would be better suited to a dynamic/scripting language. Have you considered using a Map instead of multiple varaibles?
In Java, this is not a common approach, such as it would be in scripting languages. You could try to use a Map (ie HashMap), which would enable you to achieve what you want, sort of.
In fact I think it is possible to do exactly what you want using reflection in Java, but I would not go there!

Introducing variables to Gson

I have a large JSON file that contains A LOT of similar code. It's similar to this:
...,"techs":{"t1":{"level":24,"able":true},"t2":{"level":23,"able":true},"t3":{"level":20,"able":true},"t4"...,"t5"...
It has since t1 until t510... For this reason, I have to create an activity for each tN, so I have to create 510 activities! 0.0
To get acces to each tN I use the following lines:
Gson gson = new Gson();
Planets json = gson.fromJson(str, Planets.class);
System.out.println(json.techs.t1.level);
System.out.println(json.techs.t2.level);
etc...
So I wanna know if there's the possibility to change t1 for a variable, so that I only have to change the variable to access t2 in a single activity.
For example: String tech = t456; System.out.println(json.techs.tech.level);
Thank you very much in advance!
It's all just about your imagination ;-)
I will come out from this JSON snippet
"techs":{"t1":{"level":24,"able":true},"t2":{"level":23,"able":true},"t3":{"level":20,"able":true}}
This is easily representable as this structure
HashMap<String, InnerObject>
where InnerObject class is defined like this:
class InnerObject {
int level;
boolean able;
}
So everything you need is class, where single field will be called techs and it will be defined like this:
class JSONWrapper {
// another variables
HashMap<String, InnerObject> techs;
}
To access fields after, you can use:
String techId = "t546";
InnerObject = JSONWrapperInstance.techs.get(techId);
Whole code:
String str = "... contains JSON string ...";
JSONWrapper JSONWrapperInstance = new Gson().fromJson(str, JSONWrapper.class);
And you can walk through all items in HashMap like this:
Iterator<String> iterator = JSONWrapperInstance.techs.keySet().iterator();
while(iterator.hasNext()){
InnerObject = JSONWrapperInstance.techs.get(iterator.next());
}

Categories

Resources