1.SAX方式解析xml文件的步骤:
①创建解析器工厂对象
②使用当前配置的工厂参数创建SAXParser对象
③解析xml文件
④利用DefaultHandler创建事件驱动者
2.对于标签对象进行引用怎么办?
①定义当前解析的标签:private String tagName=null;
②在startElement()方法中赋值tagName:this.tagName=qName;
③在endElement()方法中将tagName赋值为空:this.tagName=null;
④在characters()方法中利用tagName获取标签中的内容
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 qName) throws SAXException { super.endElement(uri,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,length)); if(tagName!=null){ String value=new String(ch,length); if(tagName.equals("cityname")){ //System.out.println("----name------"+new String(ch,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所提供的那些导航支持。