メモ : java を使ったRSS Reader

####内容
僕の目標として「自作スマートホーム」を作りたいと思っています。
その一環として「お天気を教えてほしいなー」と思い、
RSSからお天気情報を入手して表示するプログラムを書いたのでメモします。

プログラム初心者ですので間違ったことも多々あると思います。
その時はコメントにて指摘していただければ幸いです。

###RSSを読み取る
```RssStation.java
import java.io.IOException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLInputFactory;
import java.net.URL;
import javax.xml.stream.XMLEventReader;
import java.io.InputStream;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.events.StartElement;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.net.MalformedURLException;

public class RssStation{

    URL url; //XMLファイルのあるURLを指定。
    XMLInputFactory factory;
    XMLEventReader readMan;
    InputStream stream;

    public RssStation(String sURL){
        try{
            url = new URL(sURL);
        }catch(MalformedURLException e){
            e.printStackTrace();
        }
    }

    ArrayList<String> getDetail(String tag){
　　　　　//String tag どの要素を取得するのかを指定

　　　　　//配列では扱いにくいと思ったのでArrayListを使います。
        ArrayList<String> detail = new ArrayList<String>();
　　　　　/*
         *QNameのインスタンス生成。名前空間URLを使っていないXMLファイルなので、
　 　　　　*わざわざ,インスタンスを作る必要があったのか分かりません。
　　　　　 */
        QName tagName = new QName(tag);
        try{
            stream = url.openStream();
        //XMLEventReaderを使う為の関数をnewInstanveを実行。
            factory = XMLInputFactory.newInstance();
　　　　  //streamを指定しXMLEventReaderを生成して、URLとの橋をかける。
            readMan = factory.createXMLEventReader(stream);
　　　　  //XMLファイルに対して操作をする。

　　　　　//hasNextで要素・要素値などの何らかのイベントが次にあるのかを判定。
            while(readMan.hasNext()){
                XMLEvent events = readMan.nextEvent();
        //eventsが開始要素であるかを判定する。
                if (events.isStartElement()){
                    StartElement startTag = events.asStartElement();
　　　　 /*
        *StartElementに開始要素を入れることで開始要素に対して、
　　　　　*できる操作を増やしている。
        */
                    if (tagName.equals(startTag.getName())){
　　　　 //リストに追加する。
                        detail.add(readMan.getElementText());
                    }
                }
       /*
        *次のイベントを操作の対象にする。上の方でもnextEventを
        *行っていますが、何で２回も行うんでしょうね。
        */
              readMan.nextEvent();
            }
       //例外処理とリソースの解放。
        }catch(XMLStreamException e){
            e.printStackTrace();
        }finally{
            try{
                if (readMan != null){
                    readMan.close();
                }
                if (stream != null){
                    stream.close();
                }
            }catch(XMLStreamException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }
            return detail;
        }
    }
}
```
####お天気テキスト加工
```ProcessString.java
import java.util.ArrayList;
import java.util.StringTokenizer;

public class ProcessString{
    
    RssStation rss;
    
    public ProcessString(String url){
        this.rss = new RssStation(url);
    }

    String[] getTodays(){
        ArrayList<String> details = rss.getDetail(XMLTag.DATE_ONLY.getTag());
        String detail = details.get(0);

        String[] elements = detail.split(" ");
        elements[0] = elements[0].replace(",","");

        String month = "";
        String days = "";
        for (String s:elements){
            switch(s){
                case "Jan": month = "1月";break;
                case "Feb": month = "2月";break;
                case "Mar": month = "3月";break;
                case "Apr": month = "4月";break;
                case "May": month = "5月";break;
                case "Jun": month = "6月";break;
                case "Jul": month = "7月";break;
                case "Aug": month = "8月";break;
                case "Sep": month = "9月";break;
                case "Oct": month = "10月";break;
                case "Nov": month = "11月";break;
                case "Dec": month = "12月";break;

                case "Sun": days = "日曜日 ";break;
                case "Mon": days = "月曜日 ";break;
                case "Tue": days = "火曜日 ";break;
                case "Wed": days = "水曜日 ";break;
                case "Thu": days = "木曜日 ";break;
                case "Fri": days = "金曜日 ";break;
                case "Sat": days = "土曜日 ";break;

                default: break;
            }
        }
        String[] day = {elements[3]+"年 ",month,elements[1]+"日 ",days};
        return day;
    }
   /* 
    *String[] getWeekWeather(){
    *   something
    *}
    */

    String[] getTodayWeather(){
        ArrayList<String> details = rss.getDetail(XMLTag.WEATHER_ONLY.getTag());
        String detail = details.get(0);

        StringTokenizer token = new StringTokenizer(detail," ,./\n\t-\"\b\r\f\'");
        String[] weathers = new String[3];
        int i = 0;
        while(token.hasMoreTokens()){
            weathers[i] = token.nextToken();
            i++;
        }
        weathers[1] = weathers[1].replace("℃","度");
        weathers[2] = weathers[2].replace("℃","度");
        String weather = "";
        for(String s:weathers){
            switch(s){
                case "晴れ":weather = "晴れ ☀️  ";break;
                case "曇り":weather = "曇り ☁️  ";break;
                case "晴時々曇":weather = "晴時々曇 🌤  ";break;
                case "曇時々雨":weather = "曇時々雨 🌧  ";break;
                case "曇一時雨":weather = "曇一時雨 🌧  ";break;
                case "曇時々晴":weather = "曇時々晴 🌥  ";break;
                case "晴のち曇":weather = "晴のち曇 ☀️-> ☁️  ";break;
                case "雪":weather = "雪 ☃️  ";break;
                case "曇一時雪":weather = "曇一時雪 🌨  ";break;
                case "曇のち晴":weather = "曇のち晴 ☁️-> ☀️  ";break;
                case "雨":weather = "雨 ☔️";break;
            }
        }
        String[] all = {weather,"最高気温 "+weathers[1]," 最低気温 "+weathers[2]};
        return all;
    }

    private enum XMLTag{
        ALL_WEATHER("title"),
        WEATHER_ONLY("description"),
        LINK_ONLY("link"),
        DATE_ONLY("lastBuildDate");
    
        private String tag;
    
        private XMLTag(String tag){
            this.tag = tag;
        }
    
        public String getTag(){
            return this.tag;
        }
    }
}
```
RssStationで取得した内容をuserに分かりやすように、加工する。
列挙型の必要性があまり感じられませんね。
####表示
```Weather.java
public class Weather{
    public static void main(String args[]){
        ProcessString p = new ProcessString("https://rss-weather.yahoo.co.jp/rss/days/4620.xml");
        String[] day = p.getTodays();
        String[] weather = p.getTodayWeather();
        for (String s:day){
            System.out.print(s);
        }
        System.out.println("");
        for (String s:weather){
            System.out.print(s);
        } 
        System.out.println("");
    }
}
```
####結果
```
2019年 3月18日 月曜日 
晴時々曇 🌤  最高気温 14度 最低気温 1度
```
見やすいテキストになりました。
でも🌤を使ってしまっては読み上げできないし、実行環境に依存してしまいますね。
####感想
XML形式の仕組みがわからない状態で初めてしまったので、
XMLに対して行う処理が具体的には理解できませんでした。
でも、Streamを使ったのでStreamの仕組みを再確認できたので、よかったです。