I am attempting to parse a data document from open weather app. I am successfully reading in the entire file. I can put that entire file into a text view. I just need to parse that data. I get this error when I try to parse:
org.xml.sax.SAXParseException: Unexpected end of document
Here is my code for parse and reading the document in.
public void Weather(View view){
InputStream data;
final String OPEN_WEATHER_MAP_API =
"http://api.openweathermap.org/data/2.5/weather?q=";
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
URL url = new URL(String.format(OPEN_WEATHER_MAP_API + City + "&mode=xml&appid=40f9dad632ecd4d87b55cb512d538b75"));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// connection.addRequestProperty("x-api-key", this.getString(R.string.open_weather_maps_app_id));
data = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(data);
BufferedReader Reader = new BufferedReader(inputStreamReader);
StringBuffer Weatherdata = new StringBuffer();
String storage;
while ((storage = Reader.readLine()) != null) {
Weatherdata.append(storage + "\n");
}
cityField.setText(Weatherdata.toString());
}
catch(Exception e){
e.printStackTrace();
cityField.setText("Fail");
return;
}
try {
DocumentBuilderFactory documetBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documetBuilderFactory.newDocumentBuilder();
Document xmlDocument = documentBuilder.parse(data);
Element rootElement = xmlDocument.getDocumentElement();
}
catch (Exception e){
e.printStackTrace();
}
}
I did a quick google search the other person who had this error was having this error when he had the file stored on the computer/phone.
It occurs because you already reach the end of the InputStream when trying to parse your xml.
Indeed, when displaying the stream content using the InputStreamReader you move the file "cursor" until the end of the stream.
So, when you try to parse it with the SAX parser, it raises this end of document Exception (if you replace the parsing code to a call to data.read(), it will return -1 which means that you already reach the end of the stream).
If you remove the InputStreamReader related code, you will be able to parse the xml.
If you want to keep this code, since the reset method (which allows to reset the cursor to the beginning of the file) is not supported on HttpInputStream you should copy its content to a StringBuilder or a BufferedInputStream for example.
Related
I have used map in my android application. I passed origin and destination latlon and get data from map url then parse the response.
But while auditing below code as marked for DOS attack stating that "This code might allow an attacker to crash the program or otherwise make it unavailable to legitimate users."
Concern : What if attacker push too large file then it will go on line by line and loop will be run for too long.
Proposed solution : Do not allow to read more than specific file size, so that it won't read file beyond some limit
Here is my code :
String url = "https://maps.googleapis.com/maps/api/directions/json"+ "?" + str_origin + "&" + str_dest + "&" + "sensor=false";
private String downloadDataFromUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpsURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream),1024);
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
Please provide solution. Thanks in advance.
Edit 1:by calling append() it appends Untrusted data to a StringBuilder instance initialized with the default backing-array size (16). This can cause the JVM to over-consume heap memory space.
If you download from an unknown URL, the data can indeed be arbitrary and BufferedReader.readLine() can encounter a line so long the program cannot handle it. This question indicates that limiting BufferedReader line length may not be trivial.
Number of lines can be too big as well, in which case line count check instead of simple null check in the while loop seems to be enough.
Question is why would you allow the user to input an arbitrary URL and download it without checking. The URL can easily be a several GB binary file. Your first line indicates that you intend to use the Google Maps API, which AFAIK does not return excessively large lines, rendering the DOS concern moot (except in some ultrasecure applications, which I do not think Android is suitable to use for).
I want to share database between an android application and a web application build using Asp.net (my database is based on an IIS server.)
I just want to find the possible ways available to do it, and if I could use php services with IIS server.
I would be so thankful if someone could help me.
Million ways. I can advise you this one: create REST or SOAP service which will have access to database with all methods you need. Now in android application and in ASP.NET application you can "ask" your service to create/update/delete/do something.
try with below code.Hope it will resolved your query.
/**
* This method is used for getting user response after sending request to server.
* It returns the response after executing url request.
* #param params
* #return
*/
public String getJSONObject(String params)
{
try
{
URL url = null;
String response = null;
String parameters = "param1=value1¶m2=value2";
//url = new URL("http://www.somedomain.com/sendGetData.php");
url = new URL(params);
//create the connection
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setReadTimeout(40000);
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
//set the request method to GET
connection.setRequestMethod("GET");
//get the output stream from the connection you created
OutputStreamWriter request = new OutputStreamWriter(connection.getOutputStream());
//write your data to the ouputstream
request.write(parameters);
request.flush();
request.close();
String line = "";
//create your inputsream
InputStreamReader isr = new InputStreamReader(
connection.getInputStream());
//read in the data from input stream, this can be done a variety of ways
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
//get the string version of the response data
response = sb.toString();
//do what you want with the data now
//always remember to close your input and output streams
isr.close();
reader.close();
}
catch (Exception e)
{
Log.e("HTTP GET:", e.toString());
response="";
}
return response;
}
there are some some web site that call end point and recive a json response.
I would like to know how in myAndroid app i can call the web site and retrive the json data that he show.
Example: this is a drivenow site map
drivenow map link
if i open debug mode of browser i see this ajax call that give a josn response.
I would like to know i can call this website and take (grap) this response in my android app so i can use the json
Any idea? Help?
Thanks
You can perform GET/POST request using two ways.
Some 3rd party network request libraries
I would suggest using robospice. Using robospice you perform a network request and give it a POJO. For more info on POJO refer to the link below
https://github.com/stephanenicolas/robospice/wiki/Starter-Guide
What is RoboSpice Library in android
Using native Android/Java code
Use this function to get JSON from URL.
public static JSONObject getJSONObjectFromURL(String urlString) throws IOException, JSONException {
HttpURLConnection urlConnection = null;
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setDoOutput(true);
urlConnection.connect();
BufferedReader br=new BufferedReader(new InputStreamReader(url.openStream()));
char[] buffer = new char[1024];
String jsonString = new String();
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line+"\n");
}
br.close();
jsonString = sb.toString();
System.out.println("JSON: " + jsonString);
return new JSONObject(jsonString);}
Then use it like this:
try{
JSONObject jsonObject = getJSONObjectFromURL(String urlString);
// Parse your json here
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
Do not forget to add Internet permission in your manifest
<uses-permission android:name="android.permission.INTERNET" />
For more info on parsing JSON visit
How to parse JSON in Android
Note
You don't have to manually parse your json if you use a 3rd party library.
Confused too much! What is the sole purpose of using BufferReader, InputStream and StringBuffer. Why they should be used and in what kind of a sequence / pattern we should code them. I recently came across a chunk of code while understanding how to send and receive HTTP requests using HttpUrlConnection in android. I tried to search for all these terms and I did not get what I need. In this case, how to use each of them in a sequence or pattern? Any simple example for using all these three in combination would be great. And also kindly what should be all these 3 in layman terms? Thanks
InputStream is used for reading byte based data from the web server (or url) one byte at a time.
BufferReader it is used for reading data from an input stream all by once
StringBuffer A modifiable sequence of characters for use in creating strings, where all accesses are synchronized. This class has mostly been replaced by StringBuilder because this synchronization is rarely useful. This class is mainly used to interact with legacy APIs that expose it. [Did not understand what it means as my official language is not English]
//These two need to be declared outside the try/catch
//so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
//Construct the URL for the OpenWeatherMap query
//Possible parameters are avaiable at OWM's forecast API page, at
//http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7");
//Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
//Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
//Nothing to do.
forecastJsonStr = null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
//Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
//But it does make debugging a *lot* easier if you print out the completed
//buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
//Stream was empty. No point in parsing.
forecastJsonStr = null;
}
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
//If the code didn't successfully get the weather data, there's no point in attemping
//to parse it.
forecastJsonStr = null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
I am using the following website to find elevation:
http://gisdata.usgs.gov/xmlwebservices2/elevation_service.asmx/getElevation?X_Value=-78.85834070853889&Y_Value=43.869369104504585&Elevation_Units=METERS&Source_Layer=-1&Elevation_Only=true
This provides a results in the format of 93.7665481567383 in an XML format.
Anyone know of a quick and simple way of extracting this data for my android program?
I tried the following but I keep getting "null" as the output.
HttpURLConnection connection = null;
URL serverAddress = null;
serverAddress = new URL("http://gisdata.usgs.gov/xmlwebservices2/elevation_service.asmx/getElevation?X_Value=-78.85834070853889&Y_Value=43.869369104504585&Elevation_Units=METERS&Source_Layer=-1&Elevation_Only=true");
connection = null;
connection = (HttpURLConnection)serverAddress.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setReadTimeout(10000);
connection.connect();
BufferedReader rd = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
line = rd.readLine();
while ((line = rd.readLine()) != null)
{
sb.append(line + '\n');
}
When i output sb.toString() i get Null
Any ideas?
You made a small mistake:
the first rd.readLine() returns your <tag>number</tag> stuff but the while loop erase it with null again. Remove the first rd.readLine() call and it should work.
String line = null;
line = rd.readLine(); // you get the only line... remove it!
while ((line = rd.readLine()) != null) {
sb.append(line + '\n');
}
To get your number, try to use something like this:
// line should contain your string...
line = line.substring(line.indexOf(">"), line.indexOf("</"));
Without actually trying this myself, I recommend trying to parse the XML as opposed to trying to read it in from a Buffer. To do this in great detail, you will need to know the XML tree structure, because you will be reading in based on Nodes. For example:
// Data members
private URL URL;
private InputStream stream;
private DocumentBuilder builder;
private Document document;
private Element root;
private NodeList nodeList;
URL = new URL(url); // The URL of the site you posted goes here.
stream = URL.openStream();
// Set up and initialize the document.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace(true);
builder = dbf.newDocumentBuilder();
document = builder.parse(stream);
document.getDocumentElement().normalize();
root = document.getDocumentElement();
nodeList = root.getChildNodes();
// The number of calls to 'getFirstChild()' will vary with the complexity of
// your XML tree. Also, 'i' could vary as well, depending on which Node off
// of the root you want to access.
String number = nodeList.item(i).getFirstChild().getFirstChild().getNodeValue();
That may seem very confusing, but let me give you an example in XML.
<Building>
<name>Train Station</name>
<address>8 Main Street</address>
<color>Blue</color>
</Building>
<Building>
<name>Drugstore</name>
<address>14 Howard Boulevard</address>
<color>Yellow</color>
</Building>
Each building would represent a different value passed as a parameter to '.item(i)'. To access information about the first Building, pass a value of 0. The children of Building are accessed using the '.getFirstChild()' method, but that only returns the Node. If you wanted the text "Drugstore", you would have to traverse the XML tree to the Data of the First Child of the Second Item, eg. nodeList.item(1).getFirstChild().getNodeValue();
I hope that helped!!