001 package railo.runtime.tag; 002 003 import java.io.IOException; 004 import java.io.Reader; 005 import java.io.StringReader; 006 import java.util.ArrayList; 007 008 import org.xml.sax.InputSource; 009 import org.xml.sax.SAXException; 010 011 import railo.commons.io.IOUtil; 012 import railo.commons.io.res.Resource; 013 import railo.commons.io.res.type.http.HTTPResource; 014 import railo.commons.io.res.util.ResourceUtil; 015 import railo.commons.lang.Pair; 016 import railo.commons.lang.StringUtil; 017 import railo.runtime.exp.ApplicationException; 018 import railo.runtime.exp.ExpressionException; 019 import railo.runtime.exp.PageException; 020 import railo.runtime.ext.tag.TagImpl; 021 import railo.runtime.functions.dateTime.GetHttpTimeString; 022 import railo.runtime.net.proxy.ProxyData; 023 import railo.runtime.net.proxy.ProxyDataImpl; 024 import railo.runtime.op.Caster; 025 import railo.runtime.op.Decision; 026 import railo.runtime.text.feed.FeedHandler; 027 import railo.runtime.text.feed.FeedQuery; 028 import railo.runtime.text.xml.XMLUtil; 029 import railo.runtime.type.Array; 030 import railo.runtime.type.Query; 031 import railo.runtime.type.Struct; 032 import railo.runtime.type.util.ListUtil; 033 034 public final class Feed extends TagImpl { 035 036 private static final int ACTION_READ = 0; 037 private static final int ACTION_CREATE = 1; 038 039 private static final int TYPE_AUTO = 0; 040 private static final int TYPE_RSS = 1; 041 private static final int TYPE_ATOM = 2; 042 043 044 045 private int action=ACTION_READ; 046 private Struct columnMap=null; 047 private Resource enclosureDir=null; 048 private boolean ignoreEnclosureError=false; 049 private Object name=null; 050 private Resource outputFile=null; 051 private boolean overwrite=false; 052 private boolean overwriteEnclosure=false; 053 private Object properties=null; 054 private Object query=null; 055 private Resource source=null; 056 private int timeout=-1; 057 private int type=TYPE_AUTO; 058 private String userAgent=null; 059 private String xmlVar=null; 060 061 private String proxyPassword=null; 062 private int proxyPort=80; 063 private String proxyServer=null; 064 private String proxyUser=null; 065 private String charset=null; 066 067 @Override 068 public void release() { 069 charset=null; 070 action=ACTION_READ; 071 columnMap=null; 072 enclosureDir=null; 073 ignoreEnclosureError=false; 074 name=null; 075 outputFile=null; 076 overwrite=false; 077 overwriteEnclosure=false; 078 properties=null; 079 query=null; 080 source=null; 081 timeout=-1; 082 userAgent=null; 083 xmlVar=null; 084 085 proxyPassword=null; 086 proxyPort=80; 087 proxyServer=null; 088 proxyUser=null; 089 090 type=TYPE_AUTO; 091 super.release(); 092 } 093 /** set the value charset 094 * Character set name for the file contents. 095 * @param charset value to set 096 **/ 097 public void setCharset(String charset) { 098 this.charset=charset.trim(); 099 } 100 101 /** 102 * @param action the action to set 103 * @throws ApplicationException 104 */ 105 public void setAction(String strAction) throws ApplicationException { 106 107 strAction=StringUtil.toLowerCase(strAction.trim()); 108 if("read".equals(strAction)) action=ACTION_READ; 109 else if("create".equals(strAction)) action=ACTION_CREATE; 110 111 else throw new ApplicationException("invalid action definition ["+strAction+"], valid action definitions are " + 112 "[create,read]"); 113 } 114 115 public void setType(String strType) throws ApplicationException { 116 117 strType=StringUtil.toLowerCase(strType.trim()); 118 if("rss".equals(strType)) type=TYPE_RSS; 119 else if("atom".equals(strType)) type=TYPE_ATOM; 120 121 else throw new ApplicationException("invalid type definition ["+strType+"], valid type definitions are " + 122 "[atom,rss]"); 123 } 124 /** 125 * @param columnMap the columnMap to set 126 */ 127 public void setColumnmap(Struct columnMap) { 128 this.columnMap = columnMap; 129 } 130 /** 131 * @param enclosureDir the enclosureDir to set 132 * @throws ExpressionException 133 */ 134 public void setEnclosuredir(String strEnclosureDir) throws ExpressionException { 135 this.enclosureDir = ResourceUtil.toResourceExisting(pageContext, strEnclosureDir); 136 } 137 /** 138 * @param ignoreEnclosureError the ignoreEnclosureError to set 139 */ 140 public void setIgnoreenclosureerror(boolean ignoreEnclosureError) { 141 this.ignoreEnclosureError = ignoreEnclosureError; 142 } 143 /** 144 * @param name the name to set 145 */ 146 public void setName(Object name) { 147 this.name = name; 148 } 149 /** 150 * @param outputFile the outputFile to set 151 * @throws ExpressionException 152 */ 153 public void setOutputfile(String strOutputFile) throws ExpressionException { 154 this.outputFile = ResourceUtil.toResourceExistingParent(pageContext, strOutputFile); 155 } 156 /** 157 * @param overwrite the overwrite to set 158 */ 159 public void setOverwrite(boolean overwrite) { 160 this.overwrite = overwrite; 161 } 162 /** 163 * @param overwriteEnclosure the overwriteEnclosure to set 164 */ 165 public void setOverwriteenclosure(boolean overwriteEnclosure) { 166 this.overwriteEnclosure = overwriteEnclosure; 167 } 168 /** 169 * @param properties the properties to set 170 */ 171 public void setProperties(Object properties) { 172 this.properties = properties; 173 } 174 /** 175 * @param query the query to set 176 */ 177 public void setQuery(Object query) { 178 this.query = query; 179 } 180 /** 181 * @param source the source to set 182 * @throws ExpressionException 183 */ 184 public void setSource(String strSource) throws ExpressionException { 185 // when using toExistingResource execution fails because proxy is missed at this time 186 this.source = ResourceUtil.toResourceNotExisting(pageContext, strSource); 187 } 188 /** 189 * @param timeout the timeout to set 190 */ 191 public void setTimeout(double timeout) { 192 this.timeout = (int) timeout; 193 } 194 /** 195 * @param userAgent the userAgent to set 196 */ 197 public void setUseragent(String userAgent) { 198 this.userAgent = userAgent; 199 } 200 /** 201 * @param xmlVar the xmlVar to set 202 */ 203 public void setXmlvar(String xmlVar) { 204 this.xmlVar = xmlVar; 205 } 206 /** 207 * @param proxyPassword the proxyPassword to set 208 */ 209 public void setProxypassword(String proxyPassword) { 210 this.proxyPassword = proxyPassword; 211 } 212 213 /** 214 * @param proxyPort the proxyPort to set 215 */ 216 public void setProxyport(double proxyPort) { 217 this.proxyPort = (int) proxyPort; 218 } 219 220 /** 221 * @param proxyServer the proxyServer to set 222 */ 223 public void setProxyserver(String proxyServer) { 224 this.proxyServer = proxyServer; 225 } 226 /** 227 * @param proxyUser the proxyUser to set 228 */ 229 public void setProxyuser(String proxyUser) { 230 this.proxyUser = proxyUser; 231 } 232 233 234 235 @Override 236 public int doStartTag() throws PageException { 237 if(source instanceof HTTPResource) { 238 HTTPResource httpSource = (HTTPResource)source; 239 if(!StringUtil.isEmpty(proxyServer,true)){ 240 ProxyData data=new ProxyDataImpl(proxyServer,proxyPort,proxyUser,proxyPassword); 241 httpSource.setProxyData(data); 242 } 243 if(!StringUtil.isEmpty(userAgent)) 244 httpSource.setUserAgent(userAgent); 245 if(timeout>-1)httpSource.setTimeout(timeout*1000); 246 } 247 248 try { 249 if(ACTION_CREATE==action) doActionCreate(); 250 else if(ACTION_READ==action) doActionRead(); 251 } 252 catch(Exception e) { 253 throw Caster.toPageException(e); 254 } 255 return SKIP_BODY; 256 } 257 258 private void doActionCreate() throws PageException { 259 260 // name 261 Query qry; 262 Struct props; 263 boolean splitString=true; 264 if(name!=null) { 265 Struct data; 266 if(name instanceof String){ 267 data=Caster.toStruct(pageContext.getVariable(Caster.toString(name))); 268 } 269 else data = Caster.toStruct(name,false); 270 271 qry = FeedQuery.toQuery(data,false); 272 props = FeedProperties.toProperties(data); 273 splitString=false; 274 } 275 else if(query!=null && properties!=null) { 276 qry = FeedQuery.toQuery(Caster.toQuery(query)); 277 props = FeedProperties.toProperties(Caster.toStruct(properties,false)); 278 } 279 else { 280 throw new ApplicationException("missing attribute [name] or attributes [query] and [properties]"); 281 } 282 283 StringBuffer xml=new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 284 285 if(type==TYPE_AUTO){ 286 String version=Caster.toString(props.get("version","rss"),"rss"); 287 type=StringUtil.startsWithIgnoreCase(version, "rss")?TYPE_RSS:TYPE_ATOM; 288 } 289 if(type==TYPE_RSS) { 290 createRSS(xml,qry,props,splitString); 291 } 292 else { 293 createAtom(xml, qry, props, splitString); 294 } 295 296 // variable 297 if(!StringUtil.isEmpty(xmlVar)) { 298 pageContext.setVariable(xmlVar, xml); 299 } 300 //file 301 if(outputFile!=null){ 302 if(outputFile.exists() && !overwrite) 303 throw new ApplicationException("destiniation file ["+outputFile+"] already exist"); 304 305 306 307 if(StringUtil.isEmpty(charset)) charset=pageContext.getConfig().getResourceCharset(); 308 309 try { 310 IOUtil.write(outputFile, xml.toString(),charset,false); 311 } catch (IOException e) { 312 throw Caster.toPageException(e); 313 } 314 } 315 316 317 318 319 320 /* 321 <cffeed 322 action = "create" 323 name = "#structure#" 324 One or both of the following: 325 outputFile = "path" 326 xmlVar = "variable name" 327 optional 328 overwrite = "no|yes"> 329 330 <cffeed 331 action = "create" 332 properties = "#metadata structure#" 333 query = "#items/entries query name#" 334 One or both of the following: 335 outputFile = "path" 336 xmlVar = "variable name" 337 optional 338 columnMap = "mapping structure" 339 overwrite = "no|yes"> 340 */ 341 342 } 343 344 private void createAtom(StringBuffer xml, Query query, Struct props,boolean splitString) throws PageException { 345 int rows=query.getRowCount(); 346 347 append(xml,0,"<feed xmlns=\"http://www.w3.org/2005/Atom\">"); 348 349 propTag(props,xml,1,new String[]{"title"},"title", 350 new String[][]{ 351 new String[]{"type","type"} 352 } 353 ); 354 propTag(props,xml,1,new String[]{"subtitle"},"subtitle", 355 new String[][]{ 356 new String[]{"type","type"} 357 } 358 ); 359 propTag(props,xml,1,new String[]{"updated"},"updated",null); 360 propTag(props,xml,1,new String[]{"id"},"id",null); 361 propTag(props,xml,1,new String[]{"link"},"link", 362 new String[][]{ 363 new String[]{"rel","rel"}, 364 new String[]{"type","type"}, 365 new String[]{"hreflang","hreflang"}, 366 new String[]{"href","href"} 367 } 368 ); 369 propTag(props,xml,1,new String[]{"rights"},"rights",null); 370 propTag(props,xml,1,new String[]{"generator"},"generator", 371 new String[][]{ 372 new String[]{"uri","uri"}, 373 new String[]{"version","version"} 374 } 375 ); 376 377 // items 378 for(int row=1;row<=rows;row++) { 379 append(xml,1,"<entry>"); 380 381 tag(xml,2, 382 new Pair<String,Object>("title",query.getAt(FeedQuery.TITLE, row, null)), 383 new Pair[]{ 384 new Pair<String,Object>("type",query.getAt(FeedQuery.TITLETYPE, row, null)) 385 },false,splitString 386 ); 387 tag(xml,2, 388 new Pair<String,Object>("link",null), 389 new Pair[]{ 390 new Pair<String,Object>("href",query.getAt(FeedQuery.LINKHREF, row, null)), 391 new Pair<String,Object>("hreflang",query.getAt(FeedQuery.LINKHREFLANG, row, null)), 392 new Pair<String,Object>("length",query.getAt(FeedQuery.LINKLENGTH, row, null)), 393 new Pair<String,Object>("rel",query.getAt(FeedQuery.LINKREL, row, null)), 394 new Pair<String,Object>("title",query.getAt(FeedQuery.LINKTITLE, row, null)), 395 new Pair<String,Object>("type",query.getAt(FeedQuery.LINKTYPE, row, null)) 396 },false,splitString 397 ); 398 tag(xml,2,new Pair<String,Object>("id",query.getAt(FeedQuery.ID, row, null)),null,true,false); 399 tag(xml,2,new Pair<String,Object>("updated",query.getAt(FeedQuery.UPDATEDDATE, row, null)),null,true,false); 400 tag(xml,2,new Pair<String,Object>("published",query.getAt(FeedQuery.PUBLISHEDDATE, row, null)),null,true,false); 401 tag(xml,2, 402 new Pair<String,Object>("author",null), 403 new Pair[]{ 404 new Pair<String,Object>("email",query.getAt(FeedQuery.AUTHOREMAIL, row, null)), 405 new Pair<String,Object>("name",query.getAt(FeedQuery.AUTHORNAME, row, null)), 406 new Pair<String,Object>("uri",query.getAt(FeedQuery.AUTHORURI, row, null)) 407 },false,splitString 408 ); 409 tag(xml,2, 410 new Pair<String,Object>("category",null), 411 new Pair[]{ 412 new Pair<String,Object>("label",query.getAt(FeedQuery.CATEGORYLABEL, row, null)), 413 new Pair<String,Object>("scheme",query.getAt(FeedQuery.CATEGORYSCHEME, row, null)), 414 new Pair<String,Object>("term",query.getAt(FeedQuery.CATEGORYTERM, row, null)), 415 },false,splitString 416 ); 417 tag(xml,2, 418 new Pair<String,Object>("contributor",null), 419 new Pair[]{ 420 new Pair<String,Object>("email",query.getAt(FeedQuery.CONTRIBUTOREMAIL, row, null)), 421 new Pair<String,Object>("name",query.getAt(FeedQuery.CONTRIBUTORNAME, row, null)), 422 new Pair<String,Object>("uri",query.getAt(FeedQuery.CONTRIBUTORURI, row, null)) 423 },false,splitString 424 ); 425 tag(xml,2, 426 new Pair<String,Object>("content",query.getAt(FeedQuery.CONTENT, row, null)), 427 new Pair[]{ 428 new Pair<String,Object>("src",query.getAt(FeedQuery.CONTENTSRC, row, null)), 429 new Pair<String,Object>("type",query.getAt(FeedQuery.CONTENTTYPE, row, null)), 430 new Pair<String,Object>("type",query.getAt(FeedQuery.CONTENTTYPE, row, null)) 431 },false,splitString 432 ); 433 tag(xml,2,new Pair<String,Object>("rights",query.getAt(FeedQuery.RIGHTS, row, null)),null,true,false); 434 tag(xml,2, 435 new Pair<String,Object>("summary",query.getAt(FeedQuery.SUMMARY, row, null)), 436 new Pair[]{ 437 new Pair<String,Object>("type",query.getAt(FeedQuery.SUMMARYTYPE, row, null)) 438 },false,splitString 439 ); 440 441 append(xml,1,"</entry>"); 442 } 443 444 445 446 447 append(xml,0,"</feed>"); 448 449 } 450 private void createRSS(StringBuffer xml, Query query, Struct props, boolean splitString) throws PageException { 451 int rows=query.getRowCount(); 452 453 append(xml,0,"<rss xmlns:taxo=\"http://purl.org/rss/1.0/modules/taxonomy/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); 454 append(xml,1,"<channel>"); 455 456 // title 457 propTag(props,xml,2,new String[]{"title"},"title",null); 458 propTag(props,xml,2,new String[]{"link"},"link",null); 459 propTag(props,xml,2,new String[]{"description","subtitle"},"description",null); 460 propTag(props,xml,2,new String[]{"language"},"language",null); 461 propTag(props,xml,2,new String[]{"copyright"},"copyright",null); 462 propTag(props,xml,2,new String[]{"managingEditor"},"managingEditor",null); 463 propTag(props,xml,2,new String[]{"webMaster"},"webMaster",null); 464 propTag(props,xml,2,new String[]{"pubDate"},"pubDate",null); 465 propTag(props,xml,2,new String[]{"lastBuildDate"},"lastBuildDate",null); 466 propTag(props,xml,2,new String[]{"category"},"category", 467 new String[][]{ 468 new String[]{"domain","domain"} 469 } 470 ); 471 propTag(props,xml,2,new String[]{"generator"},"generator",null); 472 propTag(props,xml,2,new String[]{"docs"},"docs",null); 473 propTag(props,xml,2,new String[]{"cloud"},"cloud", 474 new String[][]{ 475 new String[]{"domain","domain"}, 476 new String[]{"port","port"}, 477 new String[]{"path","path"}, 478 new String[]{"registerProcedure","registerProcedure"}, 479 new String[]{"protocol","protocol"} 480 } 481 ); 482 propTag(props,xml,2,new String[]{"ttl"},"ttl",null); 483 propTag(props,xml,2,new String[]{"image"},"image", 484 new String[][]{ 485 new String[]{"url","url"}, 486 new String[]{"title","title"}, 487 new String[]{"link","link"}, 488 new String[]{"width","width"}, 489 new String[]{"height","height"}, 490 new String[]{"description","description"} 491 } 492 ,true); 493 propTag(props,xml,2,new String[]{"textInput"},"textInput", 494 new String[][]{ 495 new String[]{"title","title"}, 496 new String[]{"description","description"}, 497 new String[]{"name","name"}, 498 new String[]{"link","link"} 499 } 500 ,true); 501 propTag(props,xml,2,new String[]{"skipHours"},"skipHours",null); 502 propTag(props,xml,2,new String[]{"skipDays"},"skipDays",null); 503 504 // items 505 for(int row=1;row<=rows;row++) { 506 append(xml,2,"<item>"); 507 508 tag(xml,3,new Pair<String,Object>("title",(query.getAt(FeedQuery.TITLE, row, null))),null,true,false); 509 tag(xml,3,new Pair<String,Object>("description",(query.getAt(FeedQuery.CONTENT, row, null))),null,true,false); 510 tag(xml,3,new Pair<String,Object>("link",query.getAt(FeedQuery.RSSLINK, row, null)),null,false,false); 511 tag(xml,3,new Pair<String,Object>("author",query.getAt(FeedQuery.AUTHOREMAIL, row, null)),null,false,false); 512 tag(xml,3, 513 new Pair<String,Object>("category",query.getAt(FeedQuery.CATEGORYLABEL, row, null)), 514 new Pair[]{ 515 new Pair<String,Object>("domain",query.getAt(FeedQuery.CATEGORYSCHEME, row, null)) 516 },false,splitString 517 ); 518 tag(xml,3,new Pair<String,Object>("comments",query.getAt(FeedQuery.COMMENTS, row, null)),null,false,false); 519 tag(xml,3, 520 new Pair<String,Object>("enclosure",null), 521 new Pair[]{ 522 new Pair<String,Object>("url",query.getAt(FeedQuery.LINKHREF, row, null)), 523 new Pair<String,Object>("length",query.getAt(FeedQuery.LINKLENGTH, row, null)), 524 new Pair<String,Object>("type",query.getAt(FeedQuery.LINKTYPE, row, null)) 525 },false,splitString 526 ); 527 tag(xml,3, 528 new Pair<String,Object>("guid",query.getAt(FeedQuery.ID, row, null)), 529 new Pair[]{ 530 new Pair<String,Object>("isPermaLink",query.getAt(FeedQuery.IDPERMALINK, row, null)) 531 },false,splitString 532 ); 533 tag(xml,3,new Pair<String,Object>("pubDate",query.getAt(FeedQuery.PUBLISHEDDATE, row, null)),null,false,splitString); 534 tag(xml,3, 535 new Pair<String,Object>("source",query.getAt(FeedQuery.SOURCE, row, null)), 536 new Pair[]{ 537 new Pair<String,Object>("url",query.getAt(FeedQuery.SOURCEURL, row, null)) 538 },false,false 539 ); 540 541 542 543 544 545 append(xml,2,"</item>"); 546 } 547 548 append(xml,1,"</channel>"); 549 append(xml,0,"</rss>"); 550 551 } 552 553 private void propTag(Struct props,StringBuffer xml, int count,String[] srcNames,String trgName,String[][] attrNames) throws PageException { 554 propTag(props, xml, count, srcNames, trgName, attrNames,false); 555 } 556 557 558 private void propTag(Struct props,StringBuffer xml, int count,String[] srcNames,String trgName,String[][] attrNames, boolean childrenAsTag) throws PageException { 559 Object value; 560 for(int i=0;i<srcNames.length;i++) { 561 value=props.get(srcNames[i], null); 562 563 if(value instanceof Array){ 564 Array arr = (Array)value; 565 int size = arr.size(); 566 for(int y=1;y<=size;y++) { 567 propTag(xml, count, arr.get(y, null), trgName, attrNames, childrenAsTag); 568 } 569 break; 570 } 571 if(value !=null) { 572 propTag(xml, count, value, trgName, attrNames, childrenAsTag); 573 break; 574 } 575 } 576 } 577 578 private boolean propTag(StringBuffer xml, int count,Object value,String trgName,String[][] attrNames, boolean childrenAsTag) throws PageException { 579 if(!StringUtil.isEmpty(value)){ 580 Pair[] attrs; 581 if(value instanceof Struct && attrNames!=null) { 582 Struct sct = (Struct)value; 583 Object attrValue; 584 ArrayList al=new ArrayList(); 585 for(int i=0;i<attrNames.length;i++) { 586 attrValue=sct.get(attrNames[i][0], null); 587 if(attrValue!=null) { 588 al.add(new Pair<String,Object>(attrNames[i][1],attrValue)); 589 } 590 } 591 attrs=(Pair[]) al.toArray(new Pair[al.size()]); 592 } 593 else attrs=null; 594 tag(xml,count,new Pair<String,Object>(trgName,FeedQuery.getValue(value)),attrs,false,false,childrenAsTag); 595 return true; 596 } 597 return false; 598 599 } 600 private void tag(StringBuffer xml, int count, Pair<String,Object> tag, Pair<String,Object>[] attrs,boolean required,boolean splitString) throws PageException { 601 tag(xml, count, tag, attrs, required, splitString,false); 602 } 603 604 private void tag(StringBuffer xml, int count, Pair<String,Object> tag, Pair<String,Object>[] attrs,boolean required,boolean splitString, boolean childrenAsTag) throws PageException { 605 if(!required && StringUtil.isEmpty(tag.getValue())){ 606 if(attrs==null || attrs.length==0)return; 607 int c=0; 608 for(int i=0;i<attrs.length;i++){ 609 if(!StringUtil.isEmpty(attrs[i].getValue())) c++; 610 611 } 612 if(c==0)return; 613 } 614 615 if(tag.getValue() instanceof Array){ 616 Array arr=(Array) tag.getValue(); 617 int len=arr.size(); 618 for(int i=1;i<=len;i++) { 619 _tag(xml, tag.getName(),arr.get(i, null), attrs, count, i,false,childrenAsTag); 620 } 621 return; 622 623 } 624 if(splitString && tag.getValue() instanceof String) { 625 String strValue=(String) tag.getValue(); 626 Array arr = ListUtil.listToArray(strValue, ','); 627 if(arr.size()>1){ 628 int len=arr.size(); 629 for(int i=1;i<=len;i++) { 630 _tag(xml, tag.getName(),arr.get(i, null), attrs, count, i,true,childrenAsTag); 631 } 632 return; 633 } 634 } 635 _tag(xml, tag.getName(), tag.getValue(), attrs, count, 0,false,childrenAsTag); 636 637 638 } 639 640 private void _tag(StringBuffer xml, String tagName,Object tagValue, Pair<String,Object>[] attrs,int count, int index, boolean splitString, boolean childrenAsTag) throws PageException { 641 for(int i=0;i<count;i++)xml.append("\t"); 642 xml.append('<'); 643 xml.append(tagName); 644 645 Object attrValue; 646 if(attrs!=null && !childrenAsTag){ 647 for(int i=0;i<attrs.length;i++){ 648 attrValue=attrs[i].getValue(); 649 if(index>0){ 650 if(attrValue instanceof Array)attrValue=((Array)attrValue).get(index,null); 651 else if(splitString && attrValue instanceof String){ 652 Array arr = ListUtil.listToArray((String)attrValue, ','); 653 attrValue=arr.get(index,null); 654 } 655 } 656 if(StringUtil.isEmpty(attrValue)) continue; 657 658 xml.append(' '); 659 xml.append(attrs[i].getName()); 660 xml.append("=\""); 661 xml.append(XMLUtil.escapeXMLString(toString(attrValue))); 662 xml.append("\""); 663 } 664 } 665 666 xml.append('>'); 667 xml.append(toString(tagValue)); 668 if(attrs!=null && attrs.length>0 && childrenAsTag){ 669 xml.append('\n'); 670 for(int i=0;i<attrs.length;i++){ 671 attrValue=attrs[i].getValue(); 672 if(index>0){ 673 if(attrValue instanceof Array)attrValue=((Array)attrValue).get(index,null); 674 else if(splitString && attrValue instanceof String){ 675 Array arr = ListUtil.listToArray((String)attrValue, ','); 676 attrValue=arr.get(index,null); 677 } 678 } 679 if(StringUtil.isEmpty(attrValue)) continue; 680 681 for(int y=0;y<count+1;y++)xml.append("\t"); 682 xml.append('<'); 683 xml.append(attrs[i].getName()); 684 xml.append('>'); 685 //xml.append(XMLUtil.escapeXMLString(toString(attrValue))); 686 xml.append(toString(attrValue)); 687 xml.append("</"); 688 xml.append(attrs[i].getName()); 689 xml.append(">\n"); 690 } 691 for(int y=0;y<count;y++)xml.append("\t"); 692 } 693 694 695 696 697 xml.append("</"); 698 xml.append(tagName); 699 xml.append(">\n"); 700 701 } 702 703 704 private String toString(Object value) throws PageException { 705 if(Decision.isDateAdvanced(value, false)) return GetHttpTimeString.invoke(Caster.toDatetime(value, pageContext.getTimeZone())); 706 return XMLUtil.escapeXMLString(Caster.toString(value)); 707 } 708 709 private static void append(StringBuffer xml, int count, String value) { 710 for(int i=0;i<count;i++)xml.append("\t"); 711 xml.append(value); 712 xml.append("\n"); 713 } 714 715 private void doActionRead() throws IOException, SAXException, PageException { 716 required("Feed", "read", "source", source); 717 718 if(outputFile!=null && outputFile.exists() && !overwrite) 719 throw new ApplicationException("outputFile file ["+outputFile+"] already exists"); 720 721 722 String charset=null; 723 724 // plain output 725 // xmlVar 726 if(outputFile!=null) { 727 IOUtil.copy(source, outputFile); 728 } 729 // outputFile 730 String strFeed=null; 731 if(!StringUtil.isEmpty(xmlVar)) { 732 strFeed = IOUtil.toString(outputFile!=null?outputFile:source,charset); 733 pageContext.setVariable(xmlVar, strFeed); 734 } 735 // Input Source 736 InputSource is=null; 737 Reader r=null; 738 if(strFeed!=null)is=new InputSource(new StringReader(strFeed)); 739 else if(outputFile!=null)is=new InputSource(r=IOUtil.getReader(outputFile, charset)); 740 else is=new InputSource(r=IOUtil.getReader(source, charset)); 741 is.setSystemId(source.getPath()); 742 743 try{ 744 FeedHandler feed=new FeedHandler(source); 745 Struct data = feed.getData(); 746 //print.e(data.keys()); 747 //print.e(data); 748 // properties 749 if(properties!=null) { 750 String strProp = Caster.toString(properties,null); 751 if(strProp==null)throw new ApplicationException("attribute [properties] should be of type string"); 752 pageContext.setVariable(strProp, FeedProperties.toProperties(data)); 753 } 754 755 // query or enclosure 756 railo.runtime.type.Query qry=null; 757 if(query!=null || enclosureDir!=null){ 758 qry=FeedQuery.toQuery(data,feed.hasDC()); 759 } 760 761 // query 762 if(query!=null) { 763 String strQuery = Caster.toString(query,null); 764 if(strQuery==null)throw new ApplicationException("attribute [query] should be of type string"); 765 pageContext.setVariable(strQuery, qry); 766 } 767 // enclosure 768 769 if(enclosureDir!=null) { 770 int rows=qry.getRowCount(); 771 String strUrl=null; 772 Resource src,dest; 773 for(int row=1;row<=rows;row++) { 774 strUrl=Caster.toString(qry.getAt(FeedQuery.LINKHREF, row, null),null); 775 if(!StringUtil.isEmpty(strUrl)){ 776 src=ResourceUtil.toResourceNotExisting(pageContext, strUrl); 777 dest=enclosureDir.getRealResource(src.getName()); 778 if(!ignoreEnclosureError && !overwriteEnclosure && dest.exists()) 779 throw new ApplicationException("enclosure file ["+dest+"] already exists"); 780 try { 781 IOUtil.copy(src, dest); 782 } 783 catch(IOException ioe) { 784 if(!ignoreEnclosureError)throw ioe; 785 } 786 } 787 } 788 } 789 790 // name 791 if(name!=null) { 792 String strName = Caster.toString(name,null); 793 if(strName==null)throw new ApplicationException("attribute [name] should be of type string"); 794 pageContext.setVariable(strName, data); 795 } 796 797 798 799 } 800 finally { 801 IOUtil.closeEL(r); 802 } 803 } 804 }