読者です 読者をやめる 読者になる 読者になる

ScalaでRSS読み取り

import scala.swing._
import scala.swing.event._
import java.awt.event._
import scala.collection.mutable.ArrayBuffer
import scala.io.Source
import java.awt.Desktop
import java.net.URI
import scala.xml._
import java.net.URL
import java.io.FileWriter
import java.io.File

class RSSFrame(var rssarticles:List[RSS]) extends MainFrame {
  title="RSS"
  val tabPane:TabbedPane= new TabbedPane{
    preferredSize=new Dimension(500,500)
    listenTo(mouse.clicks)
    reactions+={
      case e :MouseClicked=>{
        val event=e.asInstanceOf[MouseClicked]
        if((event.peer.getButton)==MouseEvent.BUTTON3){
          val popupMenu = new PopupMenu{
            contents+=new MenuItem("削除"){
            listenTo(mouse.clicks)
            reactions+={
              case MousePressed (_,_,m,_,e)=>{
                val i:Int=tabPane.selection.index
                  if (i>=0){
                  tabPane.pages.remove(i)
                  }
               }
            }
           }
          }
          popupMenu.show(this,event.point.x,event.point.y)
        }
      }
    }
  }
  contents=tabPane
  menuBar = new MenuBar{
    contents+=new Menu("File"){
      contents+=new MenuItem(Action("add tab"){
        new Frame{
          title="Add new tab"
          contents=new ScrollPane( new BoxPanel(Orientation.Vertical){
            contents+=new ListView(rssarticles){
              listenTo(mouse.clicks)
              reactions+={
                case e : MouseClicked=>{
                  val event=e.asInstanceOf[MouseClicked]
                  if(event.clicks==2){
                    val index=peer.locationToIndex(event.point)
                    tabPane.pages+=new TabbedPane.Page(
                        rssarticles(index).sitealias,
                        new ScrollPane(new ListView(rssarticles(index).articles){
                          listenTo(mouse.clicks)
                          reactions+={
                            case e :MouseClicked=>{
                              val event=e.asInstanceOf[MouseClicked]
                              if (event.clicks==2){
                                val targeturi=rssarticles(index).articles(peer.locationToIndex(event.point)).link
                                val desktop=Desktop.getDesktop()
                                desktop.browse(new URI(targeturi))
                              }
                            }
                          }
                    }))
                  }
                }
              }
              
            }
            
          })
          visible=true
        }
        val title="テスト"
      })
      contents+=new MenuItem(Action("add feed source"){
       Dialog.showInput(message="URL",initial="entry") match{
         case Some (x)=>{
           if (isExist(x)){
             Dialog.showInput(message="TITLE",initial="tete") match{
               case Some(y)=>{
                 rssarticles=rssarticles:+RSS(x,y)
                 val file=new File("./rsstestdoc")
                 val fw=new FileWriter(file,true)
                 fw.write(y+","+x)
               }
               case None =>
             }
           }else{
             Dialog.showMessage(message="Not found")
           }
         }
         case None=>
       }
       def isExist(url:String):Boolean={
         try{
           XML.load(new URL(url))
         }catch{
           case _=>return false
         }
         return true
       }
      })
      contents+=new MenuItem(Action("Quit"){
        sys.exit(0)
      })
    }
  }
  
}
class RSS(val url:String,val sitealias:String,val title:String ,val link:String,val description:String,val articles:Seq[Article]){
  override def toString:String=sitealias
}
class Article(val title:String,val link:String,val description:String,val pubdate:String,val categories:Seq[String]=Seq.empty){
  override def toString:String=title
}
trait RSSParser{
  def apply(xml:NodeSeq,url:String,sitealias:String):RSS
}
object RSS1 extends RSSParser{
  def apply(xml:NodeSeq,url:String,sitealias:String):RSS={
    val title= (xml \ "channel" \ "title").text
    val link = (xml \ "channel" \ "link").text
    val description = (xml \ "channel" \ "description").text
    val articles = (xml \ "item").map(item=>new Article((item \ "title").text,
                                                        (item \ "link").text,
                                                        (item \ "description").text,
                                                        (item \ "dc:date").text))
    new RSS(url,sitealias,title,link,description,articles)
  }
}
object RSS2 extends RSSParser{
  
  def apply(xml:NodeSeq,url:String,sitealias:String):RSS={
    
    val title = (xml \ "title").text
    val link = (xml \ "link").text
    val description = (xml \ "description").text
    val articles=(xml \ "item").map(item=>new Article((item \ "title").text,
                                                    (item \ "link").text,
                                                    (item \ "description").text,
                                                    (item \ "pubDate").text,
                                                    ((item \ "category").map(_.text))))
                                               
    new RSS(url,sitealias,title,link,description,articles)
  }
}
object Atom extends RSSParser{
  
  def apply(xml:NodeSeq,url:String,sitealias:String):RSS={
    val title= (xml \ "title").text
    val link=(xml \ "link").text
    val description=(xml \ "subtitle").text
    val articles=(xml \ "entry").map(item=>{
      val entrytitle= (item \ "title").text
      val entrylink=(item \ "link" ).filter(link=>{val t=(link \ "@type").text;t=="text/html" || t==""}).map(link=>(link \ "@href").text).head
      val entryupdated=(item \ "updated").text
      val entrysummary=(item \ "summary").text
      new Article(entrytitle,entrylink,entrysummary,entryupdated)
      
    })
    new RSS(url,sitealias,title,link,description,articles)
  }
  
}


object RSS {
  def apply(url:String,sitealias:String):RSS={
    val xml=XML.load(new URL(url))
    if (xml.head.namespace=="http://www.w3.org/2005/Atom"){
      Atom(xml,url,sitealias)
    }else if (xml.head.label=="rss" && (xml \ "@version").text=="2.0"){
      RSS2(xml \ "channel",url,sitealias)
    }else if(xml.head.namespace=="http://purl.org/rss/1.0/"){
      RSS1(xml,url,sitealias)
    }else{
      RSS1(xml,url,sitealias)
    }
  }
}
object Main {
  def main(args:Array[String]){
    val s=Source.fromFile("./rsstestdoc")
    val rssfeedlist=for (line<-s.getLines.toList)yield line split ','
    val rssarticles=rssfeedlist.map(l=>RSS(l(1),l(0)))
    val ui=new RSSFrame(rssarticles)
    ui.visible=true
  }
}

かなり適当。RSSを取得してタブにリストとしてのっける。記事のタイトルをダブルクリックでブラウザ起動。
書きなおそう……