Monday, March 26, 2012

Search WOEID from http://query.yahooapis.com/

In previous exercises "Get weather info from Yahoo! Weather RSS Feed" and "Get description from Yahoo! Weather RSS feed, and display in WebView", I search Yahoo Weather with fixed WOEID. How can I know the WOEID of a certain place? Yahoo provide a web service to search WOEID.

Here is a example for "new york", you can get the woeid from the returned xml.
http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=%22New%20York%22&format=xml

www.yahooapis.com

It's a example to list the woeid(s) from the returned xml from query.yahooapis.com. Enter the place you want to search in the TextView, and click the "Search WOEID by place" button. The query will be sent to http://query.yahooapis.com/ with expected place, and the returned xml will be parsed, and the woeid(s) will be listed.

Search WOEID from http://query.yahooapis.com/

package com.exercise.AndroidSearchWOEID;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class AndroidSearchWOEIDActivity extends Activity {

//Example for "New York"
//http://query.yahooapis.com/v1/public/yql?q=select*from geo.places where text="New York"&format=xml
final String yahooapisBase = "http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=";
final String yahooapisFormat = "&format=xml";
String yahooAPIsQuery;

EditText place;
Button search;
ListView listviewWOEID;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    place = (EditText)findViewById(R.id.place);
 search = (Button)findViewById(R.id.search);
 listviewWOEID = (ListView)findViewById(R.id.woeidlist);

 search.setOnClickListener(searchOnClickListener);
}

Button.OnClickListener searchOnClickListener
= new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
if(place.getText().toString().equals("")){
 Toast.makeText(getBaseContext(),
   "Enter place!",
   Toast.LENGTH_LONG).show();
}else{
 ArrayList<String> l = QueryYahooAPIs();

 ArrayAdapter<String> aa = new ArrayAdapter<String>(
   getBaseContext(), android.R.layout.simple_list_item_1, l);

 listviewWOEID.setAdapter(aa);
}
}

};

private ArrayList<String> QueryYahooAPIs(){

 String uriPlace = Uri.encode(place.getText().toString());

 yahooAPIsQuery = yahooapisBase
   + "%22" + uriPlace + "%22"
   + yahooapisFormat;

 String woeidString = QueryYahooWeather(yahooAPIsQuery);
 Document woeidDoc = convertStringToDocument(woeidString);
 return  parseWOEID(woeidDoc);

}

private ArrayList<String> parseWOEID(Document srcDoc){

 ArrayList<String> listWOEID = new ArrayList<String>();

 NodeList nodeListDescription = srcDoc.getElementsByTagName("woeid");
 if(nodeListDescription.getLength()>=0){
  for(int i=0; i<nodeListDescription.getLength(); i++){
   listWOEID.add(nodeListDescription.item(i).getTextContent());
  }
 }else{
  listWOEID.clear();
 }

 return listWOEID;
}

private Document convertStringToDocument(String src){
 Document dest = null;

 DocumentBuilderFactory dbFactory =
   DocumentBuilderFactory.newInstance();
 DocumentBuilder parser;

 try {
  parser = dbFactory.newDocumentBuilder();
dest = parser.parse(new ByteArrayInputStream(src.getBytes()));
} catch (ParserConfigurationException e1) {
e1.printStackTrace();
Toast.makeText(getBaseContext(),
    e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),
    e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),
    e.toString(), Toast.LENGTH_LONG).show();
}

 return dest;

}

private String QueryYahooWeather(String queryString){

 String qResult = "";

 HttpClient httpClient = new DefaultHttpClient();

 //return Uri.encode(queryString);

    HttpGet httpGet = new HttpGet(queryString);

    try {
     HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();
  
     if (httpEntity != null){
      InputStream inputStream = httpEntity.getContent();
      Reader in = new InputStreamReader(inputStream);
      BufferedReader bufferedreader = new BufferedReader(in);
      StringBuilder stringBuilder = new StringBuilder();
   
      String stringReadLine = null;

      while ((stringReadLine = bufferedreader.readLine()) != null) {
       stringBuilder.append(stringReadLine + "\n");
      }
   
      qResult = stringBuilder.toString();
     }

} catch (ClientProtocolException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}

    return qResult;

}

}


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />
<EditText
    android:id="@+id/place"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
<Button
    android:id="@+id/search"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Search WOEID by place" />
<ListView
    android:id="@+id/woeidlist"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

</LinearLayout>


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.

Related:
- Get weather info from Yahoo! Weather RSS Feed
- Search WOEID and query Yahoo Weather


11 comments:

  1. Hi. Tried your files but it doesnt seem to work after I have keyed in a place e.g New York and click on the button. Any suggestions on what could be causing it to fail?

    Just a question, I noted the query string from YQL ending with -%3D%22New%20York%22 contains %3D but not in your example. Does it matter?

    I have tried including it but it doesnt make a difference.

    ReplyDelete
  2. I test it again, it work as expected.

    Are you using the downloaded file?

    How you test it? in true device? in Emulator? what device?

    ReplyDelete
  3. I am testing it in emulator.

    I seem to be getting this error message-Parser exception for C:\Users\XXX\workspace\Intents\AndroidManifest.xml: The value of attribute "android:name" associated with an element type "action" must not contain the '<' character.

    ReplyDelete
  4. If you use the downloaded files, should not have this error!

    And, please try to test on real device. emulator is too slow...!

    ReplyDelete
  5. I am unable to connect to 3g in my emulator. So I will try to fix that first.

    ReplyDelete
  6. I have tried it on an android phone HTC Desire HD and it fails once I click on the button.

    Actually if it s not working in emulator, it also shouldnt work in the device.

    Any other suggestions on why it is failing even in real device? I have used the same files that you provided.

    I noted that in my emulator, I am unable to connect to 3g.

    ReplyDelete
  7. Hello Damon R,

    What's your target API Level? or minSdkVersion?

    Can you check what error reported? Is it NetworkOnMainThreadException?

    Refer to this: android.os.NetworkOnMainThreadException.

    ReplyDelete
  8. Yes. the logcat shows android.os.NetworkonMainThreadException. My minSdkVersion="10" .

    I tried the example for android.os.NetworkOnMainThreadException. and getting error -threadid=3: reacting to signal 3.

    I will read up further on Asynctask.

    ReplyDelete
  9. Hi. I tried your code and it worked! But how i can combine this code with the previous exercise ("Get weather info from Yahoo! Weather RSS Feed"). I mean, when i click on the WOEID, it will link to the weather activity.

    ReplyDelete