1.SAX方式解析xml文件的步骤:
①创建解析器工厂对象
②使用当前配置的工厂参数创建SAXParser对象
③解析xml文件
④利用DefaultHandler创建事件驱动者
2.对于标签对象进行引用怎么办?
①定义当前解析的标签:private String tagName=null;
②在startElement()方法中赋值tagName:this.tagName=qName;
③在endElement()方法中将tagName赋值为空:this.tagName=null;
④在characters()方法中利用tagName获取标签中的内容
3.利用SAX方式解析xml文件的相关代码
public List<City> saxXML() {
MyDefaultHandler myHandler=new MyDefaultHandler();
// 第一步:创建解析器工厂对象
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
try {
// 第二步:使用当前配置的工厂参数创建SAXParser对象
SAXParser saxparser = saxParserFactory.newSAXParser();
//第三步:解析xml文件
saxparser.parse(
getClass().getClassLoader()
.getResourceAsStream("china.xml"),
myHandler);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return myHandler.getCities();
}
// 事件驱动处理者
class MyDefaultHandler extends DefaultHandler {
//当前解析的标签
private String tagName=null;
//当前解析的对象
private City currentCity=null;
private List<City> cities;
public List<City> getCities() {
return cities;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("------------startDocument()-----------");
//实例化
cities = new ArrayList<>();
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("-------------endDocument()----------");
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// System.out.println("---startElement()------uri=" + uri
// + ";localName=" + localName + ";qName=" + qName
// + ";attributes=" + attributes);
if(qName.equals("city")){
//实例化
currentCity=new City();
if(attributes!=null){
//如果不为空则获取属性值并复制到xity对象中
currentCity.setCityName(attributes.getValue("cityname"));
currentCity.setPyName(attributes.getValue("pyName"));
currentCity.setQuName(attributes.getValue("quName"));
currentCity.setState1(attributes.getValue("state1"));
currentCity.setState2(attributes.getValue("state2"));
currentCity.setStateDetailed(attributes.getValue("stateDetailed"));
currentCity.setTem1(attributes.getValue("tem1"));
currentCity.setTem2(attributes.getValue("tem2"));
currentCity.setWindState(attributes.getValue("windState"));
}
}
/*int length = attributes.getLength();
for(int i=0;i<length;i++){
String attrName = attributes.getQName(i);
String attrValue = attributes.getValue(attrName);
System.out.println(attrName+"----------"+attrValue);
}*/
this.tagName=qName;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
// System.out.println("------endElement()------uri=" + uri
// + ";localName=" + localName + ";qName=" + qName);
if(qName.equals("city")){
cities.add(currentCity);
currentCity=null;
}
this.tagName=null;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
// System.out.println("----characters()------"+new String(ch,start,length));
if(tagName!=null){
String value=new String(ch,start,length);
if(tagName.equals("cityname")){
//System.out.println("----name------"+new String(ch,start,length));
currentCity.setCityName(value);
}else if(tagName.equals("pyName")){
currentCity.setPyName(value);
}else if(tagName.equals("quName")){
currentCity.setQuName(value);
}else if(tagName.equals("state1")){
currentCity.setState1(value);
}else if(tagName.equals("state2")){
currentCity.setState2(value);
}else if(tagName.equals("stateDetailed")){
currentCity.setStateDetailed(value);
}else if(tagName.equals("tem1")){
currentCity.setTem1(value);
}else if(tagName.equals("tem2")){
currentCity.setTem2(value);
}else if(tagName.equals("windState")){
currentCity.setWindState(value);
}
}
}
}
4.天气界面的有一种搭建方式可以使用spinner插件进行城市的选择。
搭建界面的相关代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${packageName}.${activityClass}" >
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="@string/tq_wendu" />
<TextView
android:id="@+id/tv_wendu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/textView2"
android:gravity="right"
android:text="@string/wendu_default" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView2"
android:text="@string/tq_fengli" />
<TextView
android:id="@+id/tv_fengli"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/sp_cities"
android:layout_alignParentRight="true"
android:gravity="right"
android:text="@string/fengli_txt" />
<Spinner
android:id="@+id/sp_cities"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/textView1"
android:entries="@array/cities" />
</RelativeLayout>
5.调试
注册事件应该注册sp_cities.setOnItemSelectedListener(this);而不是sp_cities.setOnItemClickListener(this);事件
设置控件默认值只需要使用sp_cities.setSelection(1);方式来获取城市的默认值。(当然其中的“1”可以换成您想要的数字)
6.查看天气相关的代码:
package www.csden.net.activityh;
import java.util.List;
import www.csdn.domain.City;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnItemSelectedListener{
private Spinner sp_cities;
private String cities[];
private SaxXML saxXml;
private TextView tv_fengli,tv_wendu;
private List<City> entities;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件对象
sp_cities=(Spinner) findViewById(R.id.sp_cities);
//注册事件
sp_cities.setOnItemSelectedListener(this);
//int cityId = R.array.cities;
saxXml=new SaxXML();
//获取字符串数组
cities=getResources().getStringArray(R.array.cities);
tv_fengli=(TextView) findViewById(R.id.tv_fengli);
tv_wendu=(TextView) findViewById(R.id.tv_wendu);
//设置控件的默认值
sp_cities.setSelection(1);
//获取解析的xml文件
entities=saxXml.saxXML();
}
/**
* parent: The AdapterView where the selection happened
* view: The view within the AdapterView that was clicked
* position: The position of the view in the adapter
* id: The row id of the item that is selected
*/
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
System.out.println(parent+"---"+view+"---"+position+"---"+id);
Toast.makeText(this, cities[position], Toast.LENGTH_LONG).show();
//遍历
for(City c:entities){
//找到对应的City对象
if(c.getQuName().equals(cities[position])){
//设置风力
tv_fengli.setText(c.getWindState());
//设置温度
tv_wendu.setText(c.getTem1()+"°~"+c.getTem2()+"°");
}
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
总结:
SAX方式解析xml文件:
在读取文档时激活一系列事件,这些事件被推给事件处理器,然后由事件处理器提供对文档内容的访问。无需一次把xml文件加载到内存中,利用的是事件驱动的操作。
SAX优点:最大的优点是内存消耗小,因为整个文档无需一次加载到内存中,这使SAX解析器可以解析大于系统内存的文档。
SAX缺点:你必须实现多个事件处理程序以便能够处理所有到来的事件,同时你还必须在应用程序代码中维护这个事件状态,因为SAX解析器不能交流元信息,所以你必须跟踪解析器处在文档层次的哪个位置。
它没有内置如XPath所提供的那些导航支持。