001 package railo.runtime.text.feed; 002 003 import java.io.IOException; 004 import java.io.InputStream; 005 import java.util.HashMap; 006 import java.util.Iterator; 007 import java.util.Map; 008 import java.util.Map.Entry; 009 import java.util.Stack; 010 011 import org.xml.sax.Attributes; 012 import org.xml.sax.InputSource; 013 import org.xml.sax.Locator; 014 import org.xml.sax.SAXException; 015 import org.xml.sax.XMLReader; 016 import org.xml.sax.ext.Locator2; 017 import org.xml.sax.helpers.DefaultHandler; 018 019 import railo.commons.io.IOUtil; 020 import railo.commons.io.SystemUtil; 021 import railo.commons.io.res.Resource; 022 import railo.commons.lang.StringUtil; 023 import railo.runtime.op.Caster; 024 import railo.runtime.text.xml.XMLUtil; 025 import railo.runtime.type.Array; 026 import railo.runtime.type.ArrayImpl; 027 import railo.runtime.type.CastableArray; 028 import railo.runtime.type.Collection; 029 import railo.runtime.type.Collection.Key; 030 import railo.runtime.type.KeyImpl; 031 import railo.runtime.type.Struct; 032 import railo.runtime.type.StructImpl; 033 import railo.runtime.type.util.KeyConstants; 034 035 public final class FeedHandler extends DefaultHandler { 036 037 public final static String DEFAULT_SAX_PARSER="org.apache.xerces.parsers.SAXParser"; 038 039 040 private XMLReader xmlReader; 041 042 //private StringBuffer content=new StringBuffer(); 043 044 private int deep=0; 045 private FeedStruct data; 046 private String path=""; 047 private Collection.Key inside; 048 private Stack<FeedStruct> parents=new Stack<FeedStruct>(); 049 private FeedDeclaration decl; 050 private Map<String,String> root=new HashMap<String,String>(); 051 private boolean hasDC; 052 private boolean isAtom; 053 054 private boolean inAuthor; 055 056 private boolean inEntry; 057 058 059 /** 060 * Constructor of the class 061 * @param res 062 * @throws IOException 063 * @throws SAXException 064 */ 065 public FeedHandler(Resource res) throws IOException, SAXException { 066 InputStream is=null; 067 try { 068 InputSource source=new InputSource(is=res.getInputStream()); 069 source.setSystemId(res.getPath()); 070 071 init(DEFAULT_SAX_PARSER,source); 072 } 073 finally { 074 IOUtil.closeEL(is); 075 } 076 } 077 public FeedHandler(InputSource is) throws IOException, SAXException { 078 init(DEFAULT_SAX_PARSER,is); 079 080 } 081 082 /** 083 * Constructor of the class 084 * @param stream 085 * @throws IOException 086 * @throws SAXException 087 */ 088 public FeedHandler(InputStream stream) throws IOException, SAXException { 089 InputSource is=new InputSource(IOUtil.getReader(stream, SystemUtil.getCharset())); 090 init(DEFAULT_SAX_PARSER,is); 091 } 092 093 private void init(String saxParser,InputSource is) throws SAXException, IOException { 094 //print.out("is:"+is); 095 hasDC=false; 096 data=new FeedStruct(); 097 xmlReader=XMLUtil.createXMLReader(saxParser); 098 xmlReader.setContentHandler(this); 099 xmlReader.setErrorHandler(this); 100 xmlReader.setDTDHandler(new DummyDTDHandler()); 101 xmlReader.parse(is); 102 } 103 104 /** 105 * @return the hasDC 106 */ 107 public boolean hasDC() { 108 return hasDC; 109 } 110 public void setDocumentLocator(Locator locator) { 111 if (locator instanceof Locator2) { 112 Locator2 locator2 = (Locator2) locator; 113 root.put("encoding", locator2.getEncoding()); 114 } 115 } 116 117 @Override 118 public void startElement(String uri, String name, String qName, Attributes atts) { 119 deep++; 120 121 122 if("entry".equals(name))inEntry=true; 123 else if("author".equals(name))inAuthor=true; 124 125 if(qName.startsWith("dc:")){ 126 name="dc_"+name; 127 hasDC=true; 128 } 129 //print.o("iniside("+deep+"):"+name+"->"+uri); 130 131 132 inside = KeyImpl.getInstance(name); 133 if(StringUtil.isEmpty(path))path=name; 134 else { 135 path+="."+name; 136 } 137 if(decl==null){ 138 String decName=name; 139 String version = atts.getValue("version"); 140 if("feed".equals(decName)) { 141 if(!StringUtil.isEmpty(version))decName="atom_"+version; 142 else decName="atom_1.0"; 143 } 144 else { 145 if(!StringUtil.isEmpty(version))decName+="_"+version; 146 } 147 decl=FeedDeclaration.getInstance(decName); 148 root.put("version",decName); 149 isAtom=decl.getType().equals("atom"); 150 151 } 152 153 154 FeedStruct sct=new FeedStruct(path,inside,uri); 155 156 // attributes 157 Map<String,String> attrs = getAttributes(atts, path); 158 if(attrs!=null){ 159 Entry<String, String> entry; 160 Iterator<Entry<String, String>> it = attrs.entrySet().iterator(); 161 sct.setHasAttribute(true); 162 while(it.hasNext()){ 163 entry = it.next(); 164 sct.setEL(entry.getKey(), entry.getValue()); 165 } 166 } 167 168 // assign 169 if(!isAtom || deep<4) { 170 Object obj = data.get(inside, null); 171 if(obj instanceof Array) { 172 ((Array)obj).appendEL(sct); 173 } 174 else if(obj instanceof FeedStruct){ 175 Array arr = new ArrayImpl(); 176 arr.appendEL(obj); 177 arr.appendEL(sct); 178 data.setEL(inside, arr); 179 } 180 else if(obj instanceof String){ 181 // wenn wert schon existiert wird castableArray in setContent erstellt 182 } 183 else { 184 El el= decl.getDeclaration().get(path); 185 if(el!=null && (el.getQuantity()==El.QUANTITY_0_N || el.getQuantity()==El.QUANTITY_1_N)){ 186 Array arr = new ArrayImpl(); 187 arr.appendEL(sct); 188 data.setEL(inside, arr); 189 } 190 else data.setEL(inside, sct); 191 192 } 193 } 194 parents.add(data); 195 data=sct; 196 197 //<enclosure url="http://www.scripting.com/mp3s/weatherReportDicksPicsVol7.mp3" length="6182912" type="audio/mpeg"/> 198 } 199 200 201 public void endElement(String uri, String name, String qName) { 202 if("entry".equals(name))inEntry=false; 203 else if("author".equals(name))inAuthor=false; 204 deep--; 205 if(isAtom && deep>=(inEntry && inAuthor?4:3)) { 206 String content = data.getString(); 207 Key[] keys = data.keys(); 208 StringBuilder sb=new StringBuilder(); 209 sb.append("<"); 210 sb.append(qName); 211 212 // xmlns 213 if(!parents.peek().getUri().equals(uri)) { 214 sb.append(" xmlns=\""); 215 sb.append(uri); 216 sb.append("\""); 217 } 218 219 for(int i=0;i<keys.length;i++){ 220 sb.append(" "); 221 sb.append(keys[i].getString()); 222 sb.append("=\""); 223 sb.append(Caster.toString(data.get(keys[i],""),"")); 224 sb.append("\""); 225 226 } 227 228 229 if(!StringUtil.isEmpty(content)) { 230 sb.append(">"); 231 sb.append(content); 232 sb.append("</"+qName+">"); 233 } 234 else sb.append("/>"); 235 236 237 238 239 240 241 data= parents.pop(); 242 data.append(sb.toString().trim()); 243 //setContent(sb.toString().trim()); 244 245 path=data.getPath(); 246 inside=data.getInside(); 247 return; 248 } 249 250 251 252 //setContent(content.toString().trim()); 253 setContent(data.getString().trim()); 254 255 256 257 data=parents.pop(); 258 path=data.getPath(); 259 inside=data.getInside(); 260 } 261 262 public void characters (char ch[], int start, int length) { 263 data.append(new String(ch,start,length)); 264 //content.append(new String(ch,start,length)); 265 } 266 267 private void setContent(String value) { 268 //print.out(path+":"+inside); 269 if(StringUtil.isEmpty(inside)) return; 270 271 if(data.hasAttribute()) { 272 if(!StringUtil.isEmpty(value))setEl(data,KeyConstants._value,value); 273 } 274 else { 275 FeedStruct parent=parents.peek(); 276 setEl(parent,inside,value); 277 } 278 279 } 280 281 private void setEl(Struct sct, Collection.Key key, String value) { 282 Object existing = sct.get(key,null); 283 284 if(existing instanceof CastableArray){ 285 ((CastableArray)existing).appendEL(value); 286 } 287 else if(existing instanceof String){ 288 CastableArray ca=new CastableArray(existing); 289 ca.appendEL(existing); 290 ca.appendEL(value); 291 sct.setEL(key,ca); 292 } 293 else 294 sct.setEL(key,Caster.toString(value)); 295 296 297 /*if(existing instanceof Struct)sct.setEL(key,value); 298 else if(existing instanceof Array)((Array)existing).appendEL(value); 299 else if(existing!=null){ 300 CastableArray ca=new CastableArray(existing); 301 ca.appendEL(existing); 302 ca.appendEL(value); 303 sct.setEL(key,ca); 304 } 305 else*/ 306 } 307 308 private Map<String,String> getAttributes(Attributes attrs, String path) { 309 El el =decl.getDeclaration().get(path); 310 311 int len=attrs.getLength(); 312 if((el==null || el.getAttrs()==null) && len==0) return null; 313 314 Map<String,String> map=new HashMap<String,String>(); 315 if(el!=null) { 316 Attr[] defaults = el.getAttrs(); 317 if(defaults!=null) { 318 for(int i=0;i<defaults.length;i++) { 319 if(defaults[i].hasDefaultValue()) 320 map.put(defaults[i].getName(), defaults[i].getDefaultValue()); 321 } 322 } 323 } 324 for(int i=0;i<len;i++) { 325 map.put(attrs.getQName(i), attrs.getValue(i)); 326 } 327 return map; 328 } 329 330 331 /** 332 * @return the properties 333 */ 334 public Struct getData() { 335 return data; 336 } 337 338 339 340 341 @Override 342 public void endDocument() throws SAXException { 343 super.endDocument(); 344 Struct def=new StructImpl(); 345 Key[] entryLevel = decl.getEntryLevel(); 346 for(int i=0;i<entryLevel.length;i++) { 347 data=(FeedStruct) data.get(entryLevel[i],def); 348 } 349 data.putAll(root); 350 } 351 352 353 }