[size=medium]
这几天在研究使用SAX方式来解析XML文件,在这个期间还没有遇到什么阻塞性的问题,也看到大家在使用Google Weather API来实现天气预报数据显示的功能,所以我也写了一个,总体来说没有大的问题,但是遇到一个很奇怪的问题,如果直接使用URL.openStream()方法获得的InputStream解析老是出问题,问题的提示很奇怪,如果把文件保存起来,再解析就没有什么问题,不知道什么问题,希望大家热心帮助,初步感觉是字符编码问题。
[/size]
这几天在研究使用SAX方式来解析XML文件,在这个期间还没有遇到什么阻塞性的问题,也看到大家在使用Google Weather API来实现天气预报数据显示的功能,所以我也写了一个,总体来说没有大的问题,但是遇到一个很奇怪的问题,如果直接使用URL.openStream()方法获得的InputStream解析老是出问题,问题的提示很奇怪,如果把文件保存起来,再解析就没有什么问题,不知道什么问题,希望大家热心帮助,初步感觉是字符编码问题。
[/size]
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:684)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:369)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1742)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.scanLiteral(XMLEntityScanner.java:1064)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.scanAttributeValue(XMLScanner.java:813)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanAttribute(XMLDocumentFragmentScannerImpl.java:1539)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1316)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2747)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:807)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
at WeatherForecast.parse(WeatherForecast.java:51)
at WeatherForecast.parse(WeatherForecast.java:30)
at WeatherForecast.main(WeatherForecast.java:65)
null
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class WeatherForecast {
public final static String WEATHER_URL =
"http://www.google.com/ig/api?weather=%s&hl=zh_CN";
public static WeatherSet parse(String city) {
city = city.replace(" ", "%20");
String weatherURL = String.format(WEATHER_URL, city);
InputStream in = null;
try {
URL url = new URL(weatherURL);
in = url.openStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return parse(in);
}
public static WeatherSet parse(String fileName, String city) {
InputStream in = WeatherForecast.class.getResourceAsStream(fileName);
return parse(in);
}
public static WeatherSet parse(InputStream in) {
if(in == null){
return null;
}
SAXParserFactory spf = SAXParserFactory.newInstance();
try {
SAXParser parser = spf.newSAXParser();
XMLReader reader = parser.getXMLReader();
GoogleWeatherHandler handler = new GoogleWeatherHandler();
reader.setContentHandler(handler);
reader.parse(new InputSource(in));
return handler.getWeatherSet();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
WeatherForecast weather = new WeatherForecast();
WeatherSet weatherSet = weather.parse("api.xml","beijing,china");
System.out.println(weatherSet);
}
}
public class WeatherForecastCondition extends WeatherCondition {
private String low;
private String high;
private String dayOfWeek;
public String getLow() {
return low;
}
public void setLow(String low) {
this.low = low;
}
public String getHigh() {
return high;
}
public void setHigh(String high) {
this.high = high;
}
public String getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(String dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("\t<day_of_week data=" + this.dayOfWeek +"/>\n");
sb.append("\t<low data=" + this.low+"/>\n");
sb.append("\t<high data=" + this.high+"/>\n");
sb.append("\t<icon data=" +super.getIcon()+"/>\n");
sb.append("\t<condition data=" +super.getCondition()+"/>\n");
return sb.toString();
}
}
import java.util.ArrayList;
import java.util.List;
public class WeatherSet {
private String city;
private String postalCode;
private String latitude;
private String longitude;
private String forecastDate;
private String currentDate;
private String unitSystem;
private WeatherCurrentCondition currentCondition;
private List<WeatherForecastCondition> forecastConditions;
public WeatherSet() {
forecastConditions = new ArrayList<WeatherForecastCondition>();
}
public WeatherForecastCondition getLastForecastCondition() {
return forecastConditions.get(forecastConditions.size() - 1);
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getForecastDate() {
return forecastDate;
}
public void setForecastDate(String forecastDate) {
this.forecastDate = forecastDate;
}
public String getCurrentDate() {
return currentDate;
}
public void setCurrentDate(String currentDate) {
this.currentDate = currentDate;
}
public String getUnitSystem() {
return unitSystem;
}
public void setUnitSystem(String unitSystem) {
this.unitSystem = unitSystem;
}
public WeatherCurrentCondition getCurrentCondition() {
return currentCondition;
}
public void setCurrentCondition(WeatherCurrentCondition currentCondition) {
this.currentCondition = currentCondition;
}
public List<WeatherForecastCondition> getForeastConditions() {
return forecastConditions;
}
public void setForeastConditions(
List<WeatherForecastCondition> foreastConditions) {
this.forecastConditions = foreastConditions;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("<city data=" + this.city + "/>\n");
sb.append("<postal_code data=" +this.postalCode+"/>\n");
sb.append("<latitude_e6 data=" +this.latitude+"/>\n");
sb.append("<longitude_e6 data="+this.longitude+"/>\n");
sb.append("<forecast_date data="+this.forecastDate+"/>\n");
sb.append("<current_date_time data="+this.currentDate+"/>\n");
sb.append("<unit_system data="+this.unitSystem+"/>\n");
sb.append("\n\n" + this.currentCondition + "\n\n");
sb.append(this.forecastConditions);
return sb.toString();
}
}
public class WeatherCurrentCondition extends WeatherCondition {
private String tempFahrenheit;
private String tempCelcius;
private String humidity;
private String icon;
private String windCondition;
public String getTempFahrenheit() {
return tempFahrenheit;
}
public void setTempFahrenheit(String tempFahrenheit) {
this.tempFahrenheit = tempFahrenheit;
}
public String getTempCelcius() {
return tempCelcius;
}
public void setTempCelcius(String tempCelcius) {
this.tempCelcius = tempCelcius;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getWindCondition() {
return windCondition;
}
public void setWindCondition(String windCondition) {
this.windCondition = windCondition;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("<condition data=" + super.getCondition() + "/>\n");
sb.append("<temp_f data=" + this.tempFahrenheit + "/>\n");
sb.append("<temp_c data=" + this.tempFahrenheit + "/>\n");
sb.append("<humidity data=humidity:" + this.humidity + "12%/>\n");
sb.append("<icon data=" + super.getIcon() +"/>\n");
sb.append("<wind_condition data=" + this.windCondition +"/>\n");
return sb.toString();
}
}
public class WeatherCondition {
private String condition;
private String icon;
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
}
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class GoogleWeatherHandler extends DefaultHandler {
private WeatherSet weatherSet = null;
private boolean inForecastInformation = false;
private boolean inCurrentConditions = false;
private boolean inForecastConditions = false;
public WeatherSet getWeatherSet() {
return weatherSet;
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("xml_api_reply") || qName.equals("weather")) {
return;
}
if(qName.equals("forecast_information")){
weatherSet = new WeatherSet();
inForecastInformation = true;
return;
}
if(qName.equals("current_conditions")){
WeatherCurrentCondition todayCondition = new WeatherCurrentCondition();
weatherSet.setCurrentCondition(todayCondition);
inCurrentConditions = true;
return;
}
if(qName.equals("forecast_conditions")){
WeatherForecastCondition forecastCondition = new WeatherForecastCondition();
weatherSet.getForeastConditions().add(forecastCondition);
inForecastConditions = true;
return;
}
String dataAttr = attributes.getValue("data");
if(inForecastInformation) {
if(qName.equals("city")){
weatherSet.setCity(dataAttr);
} else if(qName.equals("postal_code")){
weatherSet.setPostalCode(dataAttr);
} else if(qName.equals("latitude_e6")){
weatherSet.setLatitude(dataAttr);
} else if(qName.equals("longitude_e6")) {
weatherSet.setLongitude(dataAttr);
} else if(qName.equals("forecast_date")){
weatherSet.setForecastDate(dataAttr);
} else if(qName.equals("current_date_time")){
weatherSet.setCurrentDate(dataAttr);
} else if(qName.equals("unit_system")){
weatherSet.setUnitSystem(dataAttr);
}
return;
}
if(qName.equals("condition")) {
if(inCurrentConditions) {
weatherSet.getCurrentCondition().setCondition(dataAttr);
} else {
weatherSet.getLastForecastCondition().setCondition(dataAttr);
}
} else if(qName.equals("temp_f")) {
weatherSet.getCurrentCondition().setTempFahrenheit(dataAttr);
} else if(qName.equals("temp_c")){
weatherSet.getCurrentCondition().setTempCelcius(dataAttr);
} else if(qName.equals("humidity")){
weatherSet.getCurrentCondition().setHumidity(dataAttr);
} else if(qName.equals("icon")){
if(inCurrentConditions) {
weatherSet.getCurrentCondition().setIcon(dataAttr);
} else {
weatherSet.getLastForecastCondition().setIcon(dataAttr);
}
} else if(qName.equals("wind_condition")){
weatherSet.getCurrentCondition().setWindCondition(dataAttr);
} else if(qName.equals("day_of_week")) {
weatherSet.getLastForecastCondition().setDayOfWeek(dataAttr);
} else if(qName.equals("low")) {
weatherSet.getLastForecastCondition().setLow(dataAttr);
} else if(qName.equals("high")) {
weatherSet.getLastForecastCondition().setHigh(dataAttr);
}
}
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
if(name.equals("forecast_information")){
inForecastInformation = false;
return;
}
if(name.equals("current_conditions")){
inCurrentConditions = false;
return;
}
if(name.equals("forecast_conditions")){
inForecastConditions = false;
return;
}
}
}