学习范围: 本教程将讲解如何使用SAXParser恰当地解析(自网络中获取的)XML.

难度: 1/5 

应用效果:

描述:

0.) 本教程中我们将解析的XML文档来自如下URL:


http://www.anddev.org/images/tut/basic/parsingxml/example.xml

XML:

<?xml version="1.0"?>
<outertag>
<innertag sampleattribute="innertagAttribute">
<mytag>
anddev.org rulez =)
</mytag>
<tagwithnumber thenumber="1337"/>
</innertag>
</outertag>

本文中使用SAX风格的解析器来完成对上述XML文档的解析. SAX 即"Simple API for XML"的缩写, 用于此处相当合适:) 

1.) 首先我们来看看onCreate(...)方法中的处理. 这个方法将完成打开URL连接, 创建一个 SAXParser对象, 并为其添加一个ContentHandler对象, 解析从URL 获取的XML内容, 最后将其结果 Results 显示在TextView对象中. 

Java:

/** Called when the activity is first created. */
     @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* Create a new TextView to display the parsingresult later. */
          TextView tv = new TextView(this);
try {
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://www.anddev.org/images/tut/basic/parsingxml/example.xml");
/* Get a SAXParser from the SAXPArserFactory. */
               SAXParserFactory spf = SAXParserFactory.newInstance();
               SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
               XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
               ExampleHandler myExampleHandler = new ExampleHandler();
               xr.setContentHandler(myExampleHandler);
/* Parse the xml-data from our URL. */
               xr.parse(new InputSource(url.openStream()));
/* Parsing has finished. */
/* Our ExampleHandler now provides the parsed data to us. */
               ParsedExampleDataSet parsedExampleDataSet =
                                             myExampleHandler.getParsedData();
/* Set the result to be displayed in our GUI. */
               tv.setText(parsedExampleDataSet.toString());
} catch (Exception e) {
/* Display any Error to the GUI. */
               tv.setText("Error: " + e.getMessage());
               Log.e(MY_DEBUG_TAG, "WeatherQueryError", e);
}
/* Display the TextView. */
this.setContentView(tv);
}

2.) 其次我们来看看ExampleHandler 类, 其继承自类 org.xml.sax.helpers.DefaultHandler. SAX处理器(SAX-Handler) 是个相当简洁的类. 使用该类时我们仅需实现几个简单函数即可. 

SAX处理器所基于的SAXParser 将从头至尾线性地遍历整个XML文档, 而且当其遇见一个节点开始的标记时, 例如: 

XML:

<outertag>

则将调用如下的处理函数: 

Java:

     @Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
}

在这个例子中, 函数的localName参数值既是"outertag". 

同理可知对于如下的标示一个节点结束的标记: 

XML:

</outertag>

则将调用对应的结束处理函数: 

Java:

     @Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
}

在XML中, 一个节点开始和结束标签的中间可以置入任意内容, 诸如: 

XML:

<mytag>
anddev.org rulez =)
</mytag>

当解析器进入该标签内容中时, 将调用如下的函数处理开始和结束标签中的字符串内容:

Java:

/** Gets be called on the following structure:
      * <tag>characters</tag> */

     @Override
public void characters(char ch[], int start, int length) {
String textBetween = new String(ch, start, length);
}

当然在整个文档的最外层, 如下的开始和结束函数将被调用: 

Java:

     @Override
public void startDocument() throws SAXException {
// Do some startup if needed
}
     @Override
public void endDocument() throws SAXException {
// Do some finishing work if needed
}

卷毛
2009-06-04 20:46

3.) 前面所阐述的只是一个SAX处理器(SAX-Handler)最基本的结构. 现在我们开看看一个真正比较实用的处理器的实现. 这也很是简单. 由于解析器是线性地一次遍历整个XML文档, 我们通常需要知道当前解析器的遍历到底'深入'到了XML文档中的哪一层节点, 所以我们使用一些布尔值变量来记录哪些节点标签是解析器已经进入而还没有走出的. 实现代码如下: 

Java:

// ===========================================================
// Fields
// ===========================================================
private boolean in_outertag = false;
private boolean in_innertag = false;
private boolean in_mytag = false;

如前所属, 当解析器遇见一个节点开始标签标签时将调用 startElement(...)函数:
所以我们此处只需根据传入的 localName参数值 来将相应的 "in_xyz"布尔变量置为true. 

Java:

     @Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (localName.equals("outertag")) {
this.in_outertag = true;
}else if (localName.equals("innertag")) {
this.in_innertag = true;
}else if (localName.equals("mytag")) {
this.in_mytag = true;
}else if (localName.equals("tagwithnumber")) {
String attrValue = atts.getValue("thenumber");
int i = Integer.parseInt(attrValue);
               myParsedExampleDataSet.setExtractedInt(i);
}
}

同理推之, 当遇见节点结束标记时, 调用 endElement(..)函数将对应的 "in_xyz"布尔变量值置回为false: 

Java:

     @Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("outertag")) {
this.in_outertag = false;
}else if (localName.equals("innertag")) {
this.in_innertag = false;
}else if (localName.equals("mytag")) {
this.in_mytag = false;
}else if (localName.equals("tagwithnumber")) {
// Nothing to do here
}
}

所以在解析器处理如下XML文档片段时: 

XML:

<mytag>
anddev.org rulez =)
</mytag>

我们的一系列"in_xyz"布尔变量将指示出如下的字符串是在哪一层的节点中被检测出来,从而将其轻松提取: 

Java:

/** Gets be called on the following structure:
      * <tag>characters</tag> */

     @Override
public void characters(char ch[], int start, int length) {
if(this.in_mytag){
          myParsedExampleDataSet.setExtractedString(new String(ch, start, length));
}
}

4.) 我们倾向于在整篇XML文档的遍历开始时就创建一个对象来保存解析结果, 并在遍历结束后将包含解析结果的该对象返回: 

Java:

public ParsedExampleDataSet getParsedData() {
return this.myParsedExampleDataSet;
}

现在我们应该清楚如何配合使用SAXParserSAXHandler 来解析XML文档了. :)

完整代码清单:
"/src/your_package_structure/ParsingXML.java

Java:

package org.anddev.android.parsingxml;
import java.net.URL;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class ParsingXML extends Activity {
private final String MY_DEBUG_TAG = "WeatherForcaster";
/** Called when the activity is first created. */
     @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* Create a new TextView to display the parsingresult later. */
          TextView tv = new TextView(this);
try {
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://www.anddev.org/images/tut/basic/parsingxml/example.xml");
/* Get a SAXParser from the SAXPArserFactory. */
               SAXParserFactory spf = SAXParserFactory.newInstance();
               SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
               XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
               ExampleHandler myExampleHandler = new ExampleHandler();
               xr.setContentHandler(myExampleHandler);
/* Parse the xml-data from our URL. */
               xr.parse(new InputSource(url.openStream()));
/* Parsing has finished. */
/* Our ExampleHandler now provides the parsed data to us. */
               ParsedExampleDataSet parsedExampleDataSet =
                                             myExampleHandler.getParsedData();
/* Set the result to be displayed in our GUI. */
               tv.setText(parsedExampleDataSet.toString());
} catch (Exception e) {
/* Display any Error to the GUI. */
               tv.setText("Error: " + e.getMessage());
               Log.e(MY_DEBUG_TAG, "WeatherQueryError", e);
}
/* Display the TextView. */
this.setContentView(tv);
}
}

"/src/your_package_structure/ExampleHandler.java

Java:

package org.anddev.android.parsingxml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ExampleHandler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private boolean in_outertag = false;
private boolean in_innertag = false;
private boolean in_mytag = false;
private ParsedExampleDataSet myParsedExampleDataSet = new ParsedExampleDataSet();
// ===========================================================
// Getter & Setter
// ===========================================================
public ParsedExampleDataSet getParsedData() {
return this.myParsedExampleDataSet;
}
// ===========================================================
// Methods
// ===========================================================
     @Override
public void startDocument() throws SAXException {
this.myParsedExampleDataSet = new ParsedExampleDataSet();
}
     @Override
public void endDocument() throws SAXException {
// Nothing to do
}
/** Gets be called on opening tags like:
      * <tag>
      * Can provide attribute(s), when xml was like:
      * <tag attribute="attributeValue">*/

     @Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (localName.equals("outertag")) {
this.in_outertag = true;
}else if (localName.equals("innertag")) {
this.in_innertag = true;
}else if (localName.equals("mytag")) {
this.in_mytag = true;
}else if (localName.equals("tagwithnumber")) {
// Extract an Attribute
String attrValue = atts.getValue("thenumber");
int i = Integer.parseInt(attrValue);
               myParsedExampleDataSet.setExtractedInt(i);
}
}
/** Gets be called on closing tags like:
      * </tag> */

     @Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("outertag")) {
this.in_outertag = false;
}else if (localName.equals("innertag")) {
this.in_innertag = false;
}else if (localName.equals("mytag")) {
this.in_mytag = false;
}else if (localName.equals("tagwithnumber")) {
// Nothing to do here
}
}
/** Gets be called on the following structure:
      * <tag>characters</tag> */

     @Override
public void characters(char ch[], int start, int length) {
if(this.in_mytag){
          myParsedExampleDataSet.setExtractedString(new String(ch, start, length));
}
}
}

"/src/your_package_structure/ParsedExampleDataSet.java

Java:

package org.anddev.android.parsingxml;
public class ParsedExampleDataSet {
private String extractedString = null;
private int extractedInt = 0;
public String getExtractedString() {
return extractedString;
}
public void setExtractedString(String extractedString) {
this.extractedString = extractedString;
}
public int getExtractedInt() {
return extractedInt;
}
public void setExtractedInt(int extractedInt) {
this.extractedInt = extractedInt;
}
public String toString(){
return "ExtractedString = " + this.extractedString
                    + "\nExtractedInt = " + this.extractedInt;
}
}

posted on 2011-03-01 14:32  四渡冰点  阅读(3907)  评论(0编辑  收藏  举报