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!!
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 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.
I am reading html source code of a public website using the following code:
Code:
#Override
protected Void doInBackground(Void... params)
{
try
{
URL url = new URL(""+URL);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String inputLine;
PageCode = "";
OriginalPageCode = "";
while ((inputLine = in.readLine()) != null)
{
PageCode += inputLine;
}
OriginalPageCode = PageCode;
try
{
extract_website_and_save(); // extracting data from PageCode
}
catch (Exception e1)
{
}
in.close();
}
Background:
The above code sometimes can fetch the most updated website properly. But occasionally it linked to an outdated version of the website and hence unable to obtain the most updated information for the website.
I am curious why the above will occur, does it related to extracting from cache instead of the real updated website??
I therefore used Chrome to browse the same link, and discovered that Chrome also fetched the outdated website.
I have tried restarting the device, but the problem continues.
After 30 minutes to an hour, I requested the app to fetch again and it then can extract the most updated information. I at the same time browse the website using Chrome, Chrome can now obtain the most updated website.
Question:
The above BufferedReader should have no relationship with Chrome? But they follow the same logic and hence extracting from cache instead of from the most updated website?
I strongly suspect the end point is being cached by URL
Try something like this
urlSrt = urlSrt + "?x=" + new Random().nextInt(100000);
// If your URL already is passing parameters i.e. example.com?x=1&p=pass - then modify
// the urlSrt line to to use an "&" and not "?"
// i.e. urlSrt = urlSrt + "&x=" + new Random().nextInt(100000);
URL url = new URL(urlSrt);
URLConnection con = url.openConnection();
con.setUseCaches(false); //This will stop caching!
So if you modify your code to something like this.
URLConnection con = url.openConnection();
con.setUseCaches(false);
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
I am making an android application which requires to send a mathematical question like 1+1 to google's calculator and I need to get that result which is displayed on the web. How can I achieve this on android?
One possibility is to create a URL for the equation you are trying to calculate and then use a URLConnection to open the URL and read the webpage source code to find the answer to the equation.
For example if you have the equation:
2+2
Then the URL to calculate the result with the Google Chrome calculator would be:
https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=2%2B2
You will have to construct the proper query in the URL for the equation you are solving. In this URL the query at the end has the equation 2+2:
q=2%2B2 (where the %2B represents the + sign)
After constructing the URL open it with a URLConnection and read the source. The answer to the equation will be in this element:
<span class="cwcot" id="cwos">4</span>
So you can parse the source in order to find that particular span element and retrieve the result of your equation.
This is probably more work than you expected but it is the only solution I can think of to accomplish what you asked. Also, this approach may be error prone and may break easily. I would consider using a different approach altogether such as launching an intent to use the calculator app on the mobile device (even though this approach has issues as well).
EDIT:
This worked for me (it will output: 2 + 2 = 4):
public static void test() {
try {
String source = getUrlSource();
String span = "<span class=\"nobr\"><h2 class=\"r\" style=\"display:inline;font-size:138%\">";
int length = span.length();
int index = source.indexOf(span) + length;
String equation = source.substring(index, source.indexOf("<", index));
System.out.println( "equation: " + equation);
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getUrlSource() throws IOException {
String url = "https://www.google.com/search";
String charset = "UTF-8";
String param1 = "2+2";
String query = String.format("?q=%s", URLEncoder.encode(param1, charset));
HttpsURLConnection urlConn = (HttpsURLConnection)new URL(url + query).openConnection();
urlConn.setRequestProperty("User-Agent", "Mozilla/5.0");
urlConn.setRequestProperty("Accept-Charset", charset);
BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
String inputLine;
StringBuilder a = new StringBuilder();
while ((inputLine = in.readLine()) != null)
a.append(inputLine);
in.close();
return a.toString();
}
I'm trying to figure out why special characters in a JSON feed (that looks completely fine when viewed in a browser) will break when used in my Android code. Characters with accent marks, ellipsis characters, curly quote characters and so on are replaced by other characters--perhaps translating it from UTF-8 down to ASCII? I'm not sure. I'm using a GET request to pull JSON data from a server, parsing it, storing it in a database, then using Html.fromHtml() and placing the contents in a TextView.
After much experimentation, I narrowed down possibilities until I discovered the problem is with the Ignition HTTP libraries (https://github.com/kaeppler/ignition). Specifically, with ignitedHttpResponse.getResponseBodyAsString()
Although that's a handy shortcut, that one line results in the broken characters. Instead, I now use:
InputStream contentStream = ignitedHttpResponse.getResponseBody();
String content = Util.inputStreamToString(contentStream);
public static String inputStreamToString(InputStream is) throws IOException {
String line = "";
StringBuilder total = new StringBuilder();
// Wrap a BufferedReader around the InputStream
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
// Read response until the end
while ((line = rd.readLine()) != null) {
total.append(line);
}
// Return full string
return total.toString();
}
Edit: Adding more detail
Here is a minimum test case to reproduce the issue.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
activity = this;
instance = this;
String url = SaveConstants.URL;
IgnitedHttpRequest request = new IgnitedHttp(activity).get(url);
InputStream contentStream = null;
try {
IgnitedHttpResponse response = request.send();
String badContent = response.getResponseBodyAsString();
int start = badContent.indexOf("is Texas");
Log.e(TAG, "bad content: " + badContent.substring(start, start + 10));
contentStream = response.getResponseBody();
String goodContent = Util.inputStreamToString(contentStream);
start = goodContent.indexOf("is Texas");
Log.e(TAG, "good content: " + goodContent.substring(start, start + 10));
} catch (IOException ioe) {
Log.e(TAG, "error", ioe);
}
}
In the log:
bad content: is Texasâ good content: is Texas’
Update: either I'm crazy, or the problem only occurs in the clients' production feed, not their development feed, although the contents look identical when viewed in a browser--showing "Texas’". So perhaps there's some wonky server configuration required to cause this issue... but still, the fix for this issue when it occurs is as I outlined. I do not recommend using response.getResponseBodyAsString();