001 package railo.runtime.text.feed; 002 003 import java.io.IOException; 004 import java.io.InputStream; 005 006 import org.xml.sax.Attributes; 007 import org.xml.sax.InputSource; 008 import org.xml.sax.Locator; 009 import org.xml.sax.SAXException; 010 import org.xml.sax.XMLReader; 011 import org.xml.sax.ext.Locator2; 012 import org.xml.sax.helpers.DefaultHandler; 013 014 import railo.commons.io.IOUtil; 015 import railo.commons.io.SystemUtil; 016 import railo.commons.io.res.Resource; 017 import railo.commons.lang.StringUtil; 018 import railo.runtime.exp.DatabaseException; 019 import railo.runtime.exp.PageException; 020 import railo.runtime.text.xml.XMLUtil; 021 import railo.runtime.type.Collection; 022 import railo.runtime.type.Collection.Key; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.Query; 025 import railo.runtime.type.QueryImpl; 026 import railo.runtime.type.Struct; 027 import railo.runtime.type.StructImpl; 028 029 public final class RSSHandler extends DefaultHandler { 030 031 public final static String DEFAULT_SAX_PARSER="org.apache.xerces.parsers.SAXParser"; 032 033 private static final Key RSSLINK = KeyImpl.intern("RSSLINK"); 034 private static final Key CONTENT = KeyImpl.intern("CONTENT"); 035 036 private static final Key LINK = KeyImpl.intern("LINK"); 037 private static final Key DESCRIPTION = KeyImpl.intern("DESCRIPTION"); 038 039 private static Collection.Key[] COLUMNS=new Collection.Key[]{ 040 KeyImpl.intern("AUTHOREMAIL"), 041 KeyImpl.intern("AUTHORNAME"), 042 KeyImpl.intern("AUTHORURI"), 043 KeyImpl.intern("CATEGORYLABEL"), 044 KeyImpl.intern("CATEGORYSCHEME"), 045 KeyImpl.intern("CATEGORYTERM"), 046 KeyImpl.intern("COMMENTS"), 047 CONTENT, 048 KeyImpl.intern("CONTENTMODE"), 049 KeyImpl.intern("CONTENTSRC"), 050 KeyImpl.intern("CONTENTTYPE"), 051 KeyImpl.intern("CONTRIBUTOREMAIL"), 052 KeyImpl.intern("CONTRIBUTORNAME"), 053 KeyImpl.intern("CONTRIBUTORURI"), 054 KeyImpl.intern("CREATEDDATE"), 055 KeyImpl.intern("EXPIRATIONDATE"), 056 KeyImpl.intern("ID"), 057 KeyImpl.intern("IDPERMALINK"), 058 KeyImpl.intern("LINKHREF"), 059 KeyImpl.intern("LINKHREFLANG"), 060 KeyImpl.intern("LINKLENGTH"), 061 KeyImpl.intern("LINKREL"), 062 KeyImpl.intern("LINKTITLE"), 063 KeyImpl.intern("LINKTYPE"), 064 KeyImpl.intern("PUBLISHEDDATE"), 065 KeyImpl.intern("RIGHTS"), 066 RSSLINK, 067 KeyImpl.intern("SOURCE"), 068 KeyImpl.intern("SOURCEURL"), 069 KeyImpl.intern("SUMMARY"), 070 KeyImpl.intern("SUMMARYMODE"), 071 KeyImpl.intern("SUMMARYSRC"), 072 KeyImpl.intern("SUMMARYTYPE"), 073 KeyImpl.intern("TITLE"), 074 KeyImpl.intern("TITLETYPE"), 075 KeyImpl.intern("UPDATEDDATE"), 076 KeyImpl.intern("URI"), 077 KeyImpl.intern("XMLBASE") 078 }; 079 080 081 private XMLReader xmlReader; 082 083 private String lcInside; 084 private StringBuffer content=new StringBuffer(); 085 086 private boolean insideImage; 087 private boolean insideItem; 088 089 private Struct image; 090 private Struct properties; 091 private Query items; 092 093 private Collection.Key inside; 094 095 /** 096 * Constructor of the class 097 * @param res 098 * @throws IOException 099 * @throws SAXException 100 * @throws DatabaseException 101 */ 102 public RSSHandler(Resource res) throws IOException, SAXException, DatabaseException { 103 InputStream is=null; 104 try { 105 InputSource source=new InputSource(is=res.getInputStream()); 106 source.setSystemId(res.getPath()); 107 init(DEFAULT_SAX_PARSER,source); 108 } 109 finally { 110 IOUtil.closeEL(is); 111 } 112 } 113 114 /** 115 * Constructor of the class 116 * @param stream 117 * @throws IOException 118 * @throws SAXException 119 * @throws DatabaseException 120 */ 121 public RSSHandler(InputStream stream) throws IOException, SAXException, DatabaseException { 122 InputSource is=new InputSource(IOUtil.getReader(stream, SystemUtil.getCharset())); 123 init(DEFAULT_SAX_PARSER,is); 124 } 125 126 private void init(String saxParser,InputSource is) throws SAXException, IOException, DatabaseException { 127 properties=new StructImpl(); 128 items=new QueryImpl(COLUMNS,0,"query"); 129 xmlReader=XMLUtil.createXMLReader(saxParser); 130 xmlReader.setContentHandler(this); 131 xmlReader.setErrorHandler(this); 132 133 //xmlReader.setEntityResolver(new TagLibEntityResolver()); 134 xmlReader.parse(is); 135 136 //properties.setEL("encoding",is.getEncoding()); 137 138 } 139 140 public void setDocumentLocator(Locator locator) { 141 if (locator instanceof Locator2) { 142 Locator2 locator2 = (Locator2) locator; 143 properties.setEL("encoding", locator2.getEncoding()); 144 } 145 } 146 147 @Override 148 public void startElement(String uri, String name, String qName, Attributes atts) { 149 inside = KeyImpl.getInstance(qName); 150 lcInside=qName.toLowerCase(); 151 if(lcInside.equals("image")) insideImage=true; 152 else if(qName.equals("item")) { 153 items.addRow(); 154 insideItem=true; 155 } 156 else if(lcInside.equals("rss")) { 157 String version = atts.getValue("version"); 158 if(!StringUtil.isEmpty(version)) 159 properties.setEL("version", "rss_"+version); 160 } 161 162 /* / cloud 163 else if(!insideItem && lcInside.equals("cloud")) { 164 165 166 167 String url = atts.getValue("url"); 168 if(!StringUtil.isEmpty(url))items.setAtEL("LINKHREF", items.getRowCount(), url); 169 String length = atts.getValue("length"); 170 if(!StringUtil.isEmpty(length))items.setAtEL("LINKLENGTH", items.getRowCount(), length); 171 String type = atts.getValue("type"); 172 if(!StringUtil.isEmpty(type))items.setAtEL("LINKTYPE", items.getRowCount(), type); 173 }*/ 174 175 176 // enclosure 177 else if(insideItem && lcInside.equals("enclosure")) { 178 String url = atts.getValue("url"); 179 if(!StringUtil.isEmpty(url))items.setAtEL("LINKHREF", items.getRowCount(), url); 180 String length = atts.getValue("length"); 181 if(!StringUtil.isEmpty(length))items.setAtEL("LINKLENGTH", items.getRowCount(), length); 182 String type = atts.getValue("type"); 183 if(!StringUtil.isEmpty(type))items.setAtEL("LINKTYPE", items.getRowCount(), type); 184 } 185 186 else if(atts.getLength()>0) { 187 int len=atts.getLength(); 188 Struct sct=new StructImpl(); 189 for(int i=0;i<len;i++) { 190 sct.setEL(atts.getQName(i), atts.getValue(i)); 191 } 192 properties.setEL(inside, sct); 193 } 194 195 //<enclosure url="http://www.scripting.com/mp3s/weatherReportDicksPicsVol7.mp3" length="6182912" type="audio/mpeg"/> 196 } 197 198 @Override 199 public void endElement(String uri, String name, String qName) { 200 setContent(content.toString().trim()); 201 content=new StringBuffer(); 202 inside=null; 203 lcInside=""; 204 205 if(qName.equals("image")) insideImage=false; 206 if(qName.equals("item")) insideItem=false; 207 } 208 209 210 @Override 211 public void characters (char ch[], int start, int length) { 212 content.append(new String(ch,start,length)); 213 } 214 215 private void setContent(String value) { 216 if(StringUtil.isEmpty(lcInside)) return; 217 218 if(insideImage) { 219 if(image==null){ 220 image=new StructImpl(); 221 properties.setEL("image",image); 222 } 223 image.setEL(inside,value); 224 } 225 else if(insideItem) { 226 try { 227 items.setAt(toItemColumn(inside), items.getRowCount(), value); 228 } catch (PageException e) { 229 //print.err(inside); 230 } 231 232 } 233 else { 234 if(!(StringUtil.isEmpty(value,true) && properties.containsKey(inside))) 235 properties.setEL(inside,value); 236 } 237 } 238 239 private Collection.Key toItemColumn(Collection.Key key) { 240 if(key.equalsIgnoreCase(LINK)) return RSSLINK; 241 else if(key.equalsIgnoreCase(DESCRIPTION))return CONTENT; 242 return key; 243 } 244 245 /** 246 * @return the properties 247 */ 248 public Struct getProperties() { 249 return properties; 250 } 251 252 /** 253 * @return the items 254 */ 255 public Query getItems() { 256 return items; 257 } 258 259 260 /*public static void main(String[] args) throws IOException, SAXException { 261 ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); 262 Resource res = frp.getResource("/Users/mic/Projects/Railo/webroot/jm/feed/092.xml"); 263 RSSHandler rss=new RSSHandler(res); 264 print.out(rss.getProperties()); 265 print.out(rss.getItems()); 266 267 }*/ 268 }