001 package railo.runtime.converter; 002 003 import java.io.IOException; 004 import java.io.StringReader; 005 import java.io.Writer; 006 import java.util.Date; 007 import java.util.HashSet; 008 import java.util.Iterator; 009 import java.util.List; 010 import java.util.ListIterator; 011 import java.util.Locale; 012 import java.util.Map; 013 import java.util.Set; 014 import java.util.TimeZone; 015 016 import javax.xml.parsers.FactoryConfigurationError; 017 018 import org.apache.xerces.parsers.DOMParser; 019 import org.w3c.dom.CharacterData; 020 import org.w3c.dom.Document; 021 import org.w3c.dom.Element; 022 import org.w3c.dom.Node; 023 import org.w3c.dom.NodeList; 024 import org.xml.sax.InputSource; 025 026 import railo.commons.date.TimeZoneConstants; 027 import railo.commons.lang.NumberUtil; 028 import railo.runtime.Component; 029 import railo.runtime.ComponentScope; 030 import railo.runtime.ComponentWrap; 031 import railo.runtime.PageContext; 032 import railo.runtime.coder.Base64Coder; 033 import railo.runtime.coder.CoderException; 034 import railo.runtime.component.Property; 035 import railo.runtime.engine.ThreadLocalPageContext; 036 import railo.runtime.exp.ExpressionException; 037 import railo.runtime.exp.PageException; 038 import railo.runtime.op.Caster; 039 import railo.runtime.op.Decision; 040 import railo.runtime.op.date.DateCaster; 041 import railo.runtime.orm.hibernate.HBMCreator; 042 import railo.runtime.text.xml.XMLUtil; 043 import railo.runtime.type.Array; 044 import railo.runtime.type.ArrayImpl; 045 import railo.runtime.type.Collection; 046 import railo.runtime.type.Collection.Key; 047 import railo.runtime.type.KeyImpl; 048 import railo.runtime.type.Query; 049 import railo.runtime.type.QueryImpl; 050 import railo.runtime.type.Struct; 051 import railo.runtime.type.StructImpl; 052 import railo.runtime.type.UDF; 053 import railo.runtime.type.cfc.ComponentAccess; 054 import railo.runtime.type.dt.DateTime; 055 import railo.runtime.type.dt.DateTimeImpl; 056 import railo.runtime.type.util.CollectionUtil; 057 import railo.runtime.type.util.ComponentUtil; 058 import railo.runtime.type.util.KeyConstants; 059 060 /** 061 * class to serialize and desirilize WDDX Packes 062 */ 063 public final class WDDXConverter extends ConverterSupport { 064 private static final Collection.Key REMOTING_FETCH = KeyImpl.intern("remotingFetch"); 065 066 private int deep=1; 067 private boolean xmlConform; 068 private char _; 069 private TimeZone timeZone; 070 private boolean ignoreRemotingFetch=true; 071 //private PageContext pcx; 072 073 /** 074 * constructor of the class 075 * @param timeZone 076 * @param xmlConform define if generated xml conform output or wddx conform output (wddx is not xml conform) 077 */ 078 public WDDXConverter(TimeZone timeZone, boolean xmlConform,boolean ignoreRemotingFetch) { 079 this.xmlConform=xmlConform; 080 _=(xmlConform)?'"':'\''; 081 this.timeZone=timeZone; 082 this.ignoreRemotingFetch=ignoreRemotingFetch; 083 } 084 085 /** 086 * defines timezone info will 087 * @param timeZone 088 */ 089 public void setTimeZone(TimeZone timeZone) { 090 this.timeZone=timeZone; 091 } 092 093 /** 094 * serialize a Date 095 * @param date Date to serialize 096 * @return serialized date 097 * @throws ConverterException 098 */ 099 private String _serializeDate(Date date) { 100 return _serializeDateTime(new DateTimeImpl(date)); 101 } 102 /** 103 * serialize a DateTime 104 * @param dateTime DateTime to serialize 105 * @return serialized dateTime 106 * @throws ConverterException 107 */ 108 private String _serializeDateTime(DateTime dateTime) { 109 //try { 110 111 112 String strDate = new railo.runtime.format.DateFormat(Locale.US).format(dateTime,"yyyy-m-d",TimeZoneConstants.UTC); 113 String strTime = new railo.runtime.format.TimeFormat(Locale.US).format(dateTime,"H:m:s",TimeZoneConstants.UTC); 114 115 return goIn()+"<dateTime>"+ 116 strDate+ 117 "T"+strTime+ 118 "+0:0"+ 119 "</dateTime>"; 120 121 /*} 122 catch (PageException e) { 123 throw new ConverterException(e); 124 }*/ 125 } 126 127 private String _serializeBinary(byte[] binary) { 128 return new StringBuilder("<binary length='") 129 .append(binary.length) 130 .append("'>") 131 .append(Base64Coder.encode(binary)) 132 .append("</binary>").toString(); 133 } 134 135 /** 136 * @param dateTime 137 * @return returns the time zone info 138 */ 139 private String getTimeZoneInfo(DateTime dateTime) { 140 timeZone=ThreadLocalPageContext.getTimeZone(timeZone); 141 //if(timeZone==null) return ""; 142 143 int minutes=timeZone.getOffset(dateTime.getTime())/1000/60; 144 String operator=(minutes>=0)?"+":"-"; 145 if(operator.equals("-"))minutes=minutes-(minutes+minutes); 146 int hours=minutes/60; 147 minutes=minutes%60; 148 149 return operator+hours+":"+minutes; 150 151 152 } 153 154 /** 155 * serialize a Array 156 * @param array Array to serialize 157 * @param done 158 * @return serialized array 159 * @throws ConverterException 160 */ 161 private String _serializeArray(Array array, Set<Object> done) throws ConverterException { 162 return _serializeList(array.toList(),done); 163 } 164 165 /** 166 * serialize a List (as Array) 167 * @param list List to serialize 168 * @param done 169 * @return serialized list 170 * @throws ConverterException 171 */ 172 private String _serializeList(List list, Set<Object> done) throws ConverterException { 173 StringBuffer sb=new StringBuffer(goIn()+"<array length="+_+list.size()+_+">"); 174 175 ListIterator it=list.listIterator(); 176 while(it.hasNext()) { 177 sb.append(_serialize(it.next(),done)); 178 } 179 180 sb.append(goIn()+"</array>"); 181 return sb.toString(); 182 } 183 184 /** 185 * serialize a Component 186 * @param component Component to serialize 187 * @param done 188 * @return serialized component 189 * @throws ConverterException 190 */ 191 private String _serializeComponent(Component component, Set<Object> done) throws ConverterException { 192 StringBuffer sb=new StringBuffer(); 193 ComponentAccess ca; 194 try { 195 component=new ComponentWrap(Component.ACCESS_PRIVATE, ca=ComponentUtil.toComponentAccess(component)); 196 } catch (ExpressionException e1) { 197 throw toConverterException(e1); 198 } 199 boolean isPeristent=ca.isPersistent(); 200 201 202 deep++; 203 Object member; 204 Iterator<Key> it = component.keyIterator(); 205 Collection.Key key; 206 while(it.hasNext()) { 207 key=Caster.toKey(it.next(),null); 208 member = component.get(key,null); 209 if(member instanceof UDF) continue; 210 sb.append(goIn()+"<var scope=\"this\" name="+_+key.toString()+_+">"); 211 sb.append(_serialize(member,done)); 212 sb.append(goIn()+"</var>"); 213 } 214 215 Property p; 216 Boolean remotingFetch; 217 Struct props = ignoreRemotingFetch?null:ComponentUtil.getPropertiesAsStruct(ca,false); 218 ComponentScope scope = ca.getComponentScope(); 219 it=scope.keyIterator(); 220 while(it.hasNext()) { 221 key=Caster.toKey(it.next(),null); 222 if(!ignoreRemotingFetch) { 223 p=(Property) props.get(key,null); 224 if(p!=null) { 225 remotingFetch=Caster.toBoolean(p.getDynamicAttributes().get(REMOTING_FETCH,null),null); 226 if(remotingFetch==null){ 227 if(isPeristent && HBMCreator.isRelated(p)) continue; 228 } 229 else if(!remotingFetch.booleanValue()) continue; 230 } 231 } 232 233 member = scope.get(key,null); 234 if(member instanceof UDF || key.equals(KeyConstants._this)) continue; 235 sb.append(goIn()+"<var scope=\"variables\" name="+_+key.toString()+_+">"); 236 sb.append(_serialize(member,done)); 237 sb.append(goIn()+"</var>"); 238 } 239 240 241 deep--; 242 try { 243 //return goIn()+"<struct>"+sb+"</struct>"; 244 return goIn()+"<component md5=\""+ComponentUtil.md5(component)+"\" name=\""+component.getAbsName()+"\">"+sb+"</component>"; 245 } 246 catch (Exception e) { 247 throw toConverterException(e); 248 } 249 } 250 251 /** 252 * serialize a Struct 253 * @param struct Struct to serialize 254 * @param done 255 * @return serialized struct 256 * @throws ConverterException 257 */ 258 private String _serializeStruct(Struct struct, Set<Object> done) throws ConverterException { 259 StringBuffer sb=new StringBuffer(goIn()+"<struct>"); 260 261 Iterator<Key> it = struct.keyIterator(); 262 263 deep++; 264 while(it.hasNext()) { 265 Key key = it.next(); 266 sb.append(goIn()+"<var name="+_+key.toString()+_+">"); 267 sb.append(_serialize(struct.get(key,null),done)); 268 sb.append(goIn()+"</var>"); 269 } 270 deep--; 271 272 sb.append(goIn()+"</struct>"); 273 return sb.toString(); 274 } 275 276 /** 277 * serialize a Map (as Struct) 278 * @param map Map to serialize 279 * @param done 280 * @return serialized map 281 * @throws ConverterException 282 */ 283 private String _serializeMap(Map map, Set<Object> done) throws ConverterException { 284 StringBuffer sb=new StringBuffer(goIn()+"<struct>"); 285 286 Iterator it=map.keySet().iterator(); 287 288 deep++; 289 while(it.hasNext()) { 290 Object key=it.next(); 291 sb.append(goIn()+"<var name="+_+key.toString()+_+">"); 292 sb.append(_serialize(map.get(key),done)); 293 sb.append(goIn()+"</var>"); 294 } 295 deep--; 296 297 sb.append(goIn()+"</struct>"); 298 return sb.toString(); 299 } 300 301 /** 302 * serialize a Query 303 * @param query Query to serialize 304 * @param done 305 * @return serialized query 306 * @throws ConverterException 307 */ 308 private String _serializeQuery(Query query, Set<Object> done) throws ConverterException { 309 310 Collection.Key[] keys = CollectionUtil.keys(query); 311 StringBuffer sb=new StringBuffer(goIn()+"<recordset rowCount="+_+query.getRecordcount()+_+" fieldNames="+_+railo.runtime.type.util.ListUtil.arrayToList(keys,",")+_+" type="+_+"coldfusion.sql.QueryTable"+_+">"); 312 313 314 deep++; 315 int len=query.getRecordcount(); 316 for(int i=0;i<keys.length;i++) { 317 sb.append(goIn()+"<field name="+_+keys[i].getString()+_+">"); 318 for(int y=1;y<=len;y++) { 319 try { 320 sb.append(_serialize(query.getAt(keys[i],y),done)); 321 } catch (PageException e) { 322 sb.append(_serialize(e.getMessage(),done)); 323 } 324 } 325 326 sb.append(goIn()+"</field>"); 327 } 328 deep--; 329 330 sb.append(goIn()+"</recordset>"); 331 return sb.toString(); 332 } 333 334 /** 335 * serialize a Object to his xml Format represenation 336 * @param object Object to serialize 337 * @param done 338 * @return serialized Object 339 * @throws ConverterException 340 */ 341 private String _serialize(Object object, Set<Object> done) throws ConverterException { 342 String rtn; 343 deep++; 344 // NULL 345 if(object==null) { 346 rtn= goIn()+"<null/>"; 347 deep--; 348 return rtn; 349 } 350 // String 351 if(object instanceof String) { 352 rtn= goIn()+"<string>"+XMLUtil.escapeXMLString(object.toString())+"</string>"; 353 deep--; 354 return rtn; 355 } 356 // Number 357 if(object instanceof Number) { 358 rtn= goIn()+"<number>"+((Number)object).doubleValue()+"</number>"; 359 deep--; 360 return rtn; 361 } 362 // Boolean 363 if(object instanceof Boolean) { 364 rtn= goIn()+"<boolean value="+_+((Boolean)object).booleanValue()+_+"/>"; 365 deep--; 366 return rtn; 367 } 368 // DateTime 369 if(object instanceof DateTime) { 370 rtn= _serializeDateTime((DateTime)object); 371 deep--; 372 return rtn; 373 } 374 // Date 375 if(object instanceof Date) { 376 rtn= _serializeDate((Date)object); 377 deep--; 378 return rtn; 379 } 380 // Date 381 if(Decision.isCastableToBinary(object, false)) { 382 rtn= _serializeBinary(Caster.toBinary(object,null)); 383 deep--; 384 return rtn; 385 } 386 387 Object raw = LazyConverter.toRaw(object); 388 if(done.contains(raw)){ 389 rtn= goIn()+"<null/>"; 390 deep--; 391 return rtn; 392 } 393 394 done.add(raw); 395 try { 396 // Component 397 if(object instanceof Component) { 398 rtn= _serializeComponent((Component)object,done); 399 deep--; 400 return rtn; 401 } 402 // Struct 403 if(object instanceof Struct) { 404 rtn= _serializeStruct((Struct)object,done); 405 deep--; 406 return rtn; 407 } 408 // Map 409 if(object instanceof Map) { 410 rtn= _serializeMap((Map)object,done); 411 deep--; 412 return rtn; 413 } 414 // Array 415 if(object instanceof Array) { 416 rtn= _serializeArray((Array)object,done); 417 deep--; 418 return rtn; 419 } 420 // List 421 if(object instanceof List) { 422 rtn= _serializeList((List)object,done); 423 deep--; 424 return rtn; 425 } 426 // Query 427 if(object instanceof Query) { 428 rtn= _serializeQuery((Query)object,done); 429 deep--; 430 return rtn; 431 } 432 } 433 finally{ 434 done.remove(raw); 435 } 436 // Others 437 rtn="<struct type="+_+"L"+object.getClass().getName()+";"+_+"></struct>"; 438 deep--; 439 return rtn; 440 } 441 442 @Override 443 public void writeOut(PageContext pc, Object source, Writer writer) throws ConverterException, IOException { 444 writer.write(serialize(source)); 445 writer.flush(); 446 } 447 448 /** 449 * serialize a Object to his xml Format represenation and create a valid wddx representation 450 * @param object Object to serialize 451 * @return serialized wddx package 452 * @throws ConverterException 453 */ 454 public String serialize(Object object) throws ConverterException { 455 deep=0; 456 457 StringBuffer sb=new StringBuffer(); 458 if(xmlConform)sb.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"); 459 sb.append("<wddxPacket version="+_+"1.0"+_+">"); 460 deep++; 461 sb.append(goIn()+"<header/>"); 462 sb.append(goIn()+"<data>"); 463 sb.append(_serialize(object,new HashSet<Object>())); 464 sb.append(goIn()+"</data>"); 465 deep--; 466 sb.append("</wddxPacket>"); 467 return sb.toString(); 468 } 469 470 471 /** 472 * deserialize a WDDX Package (XML String Representation) to a runtime object 473 * @param strWddx 474 * @param validate 475 * @return Object represent WDDX Package 476 * @throws ConverterException 477 * @throws IOException 478 * @throws FactoryConfigurationError 479 */ 480 public Object deserialize(String strWddx, boolean validate) throws ConverterException, IOException, FactoryConfigurationError { 481 try { 482 DOMParser parser = new DOMParser(); 483 if(validate) parser.setEntityResolver(new WDDXEntityResolver()); 484 485 parser.parse(new InputSource(new StringReader(strWddx))); 486 Document doc=parser.getDocument(); 487 488 // WDDX Package 489 NodeList docChldren = doc.getChildNodes(); 490 Node wddxPacket=doc; 491 int len = docChldren.getLength(); 492 for(int i = 0; i < len; i++) { 493 Node node=docChldren.item(i); 494 if(node.getNodeName().equalsIgnoreCase("wddxPacket")) { 495 wddxPacket=node; 496 break; 497 } 498 } 499 500 NodeList nl = wddxPacket.getChildNodes(); 501 int n = nl.getLength(); 502 503 504 for(int i = 0; i < n; i++) { 505 Node data = nl.item(i); 506 if(data.getNodeName().equals("data")) { 507 NodeList list=data.getChildNodes(); 508 len=list.getLength(); 509 for(int y=0;y<len;y++) { 510 Node node=list.item(y); 511 if(node instanceof Element) 512 return _deserialize((Element)node); 513 514 } 515 } 516 } 517 518 throw new IllegalArgumentException("Invalid WDDX Format: node 'data' not found in WDD packet"); 519 520 } 521 catch(org.xml.sax.SAXException sxe) { 522 throw new IllegalArgumentException("XML Error: " + sxe.toString()); 523 } 524 } 525 526 527 528 /** 529 * deserialize a WDDX Package (XML Element) to a runtime object 530 * @param element 531 * @return deserialized Element 532 * @throws ConverterException 533 */ 534 private Object _deserialize(Element element) throws ConverterException { 535 String nodeName=element.getNodeName().toLowerCase(); 536 537 // NULL 538 if(nodeName.equals("null")) { 539 return null; 540 } 541 // String 542 else if(nodeName.equals("string")) { 543 return _deserializeString(element); 544 /*Node data=element.getFirstChild(); 545 if(data==null) return ""; 546 547 String value=data.getNodeValue(); 548 549 if(value==null) return ""; 550 return XMLUtil.unescapeXMLString(value);*/ 551 } 552 // Number 553 else if(nodeName.equals("number")) { 554 try { 555 Node data=element.getFirstChild(); 556 if(data==null) return new Double(0); 557 return Caster.toDouble(data.getNodeValue()); 558 } catch (Exception e) { 559 throw toConverterException(e); 560 } 561 } 562 // Boolean 563 else if(nodeName.equals("boolean")) { 564 try { 565 return Caster.toBoolean(element.getAttribute("value")); 566 } catch (PageException e) { 567 throw toConverterException(e); 568 569 } 570 } 571 // Array 572 else if(nodeName.equals("array")) { 573 return _deserializeArray(element); 574 } 575 // Component 576 else if(nodeName.equals("component")) { 577 return _deserializeComponent(element); 578 } 579 // Struct 580 else if(nodeName.equals("struct")) { 581 return _deserializeStruct(element); 582 } 583 // Query 584 else if(nodeName.equals("recordset")) { 585 return _deserializeQuery(element); 586 } 587 // DateTime 588 else if(nodeName.equalsIgnoreCase("dateTime")) { 589 try { 590 return DateCaster.toDateAdvanced(element.getFirstChild().getNodeValue(),timeZone); 591 } 592 catch (Exception e) { 593 throw toConverterException(e); 594 } 595 } 596 // Query 597 else if(nodeName.equals("binary")) { 598 return _deserializeBinary(element); 599 } 600 else 601 throw new ConverterException("can't deserialize Element of type ["+nodeName+"] to a Object representation"); 602 603 } 604 605 private Object _deserializeString(Element element) { 606 NodeList childList = element.getChildNodes(); 607 int len = childList.getLength(); 608 StringBuffer sb=new StringBuffer(); 609 Node data; 610 String str; 611 for(int i=0;i<len;i++) { 612 data=childList.item(i); 613 if(data==null)continue; 614 615 //<char code="0a"/> 616 if("char".equals(data.getNodeName())) { 617 str=((Element)data).getAttribute("code"); 618 sb.append((char)NumberUtil.hexToInt(str, 10)); 619 } 620 else { 621 sb.append(str=data.getNodeValue()); 622 } 623 } 624 return sb.toString(); 625 //return XMLUtil.unescapeXMLString(sb.toString()); 626 } 627 628 /** 629 * Desirialize a Query Object 630 * @param recordset Query Object as XML Element 631 * @return Query Object 632 * @throws ConverterException 633 */ 634 private Object _deserializeQuery(Element recordset) throws ConverterException { 635 try { 636 // create Query Object 637 Query query=new QueryImpl( 638 railo.runtime.type.util.ListUtil.listToArray( 639 recordset.getAttribute("fieldNames"),',' 640 ) 641 ,Caster.toIntValue(recordset.getAttribute("rowCount")),"query" 642 ); 643 644 NodeList list = recordset.getChildNodes(); 645 int len=list.getLength(); 646 for(int i=0;i<len;i++) { 647 Node node=list.item(i); 648 if(node instanceof Element) { 649 _deserializeQueryField(query,(Element) node); 650 } 651 } 652 return query; 653 } 654 catch(PageException e) { 655 throw toConverterException(e); 656 } 657 658 } 659 660 661 662 private Object _deserializeBinary(Element el) throws ConverterException { 663 Node node = el.getFirstChild(); 664 if(node instanceof CharacterData) { 665 String data=((CharacterData)node).getData(); 666 try { 667 return Base64Coder.decode(data); 668 } catch (CoderException e) { 669 throw new ConverterException(e.getMessage()); 670 } 671 } 672 throw new ConverterException("cannot convert serialized binary back to binary data"); 673 } 674 675 /** 676 * deserilize a single Field of a query WDDX Object 677 * @param query 678 * @param field 679 * @throws ConverterException 680 * @throws PageException 681 */ 682 private void _deserializeQueryField(Query query,Element field) throws PageException, ConverterException { 683 String name=field.getAttribute("name"); 684 NodeList list = field.getChildNodes(); 685 int len=list.getLength(); 686 int count=0; 687 for(int i=0;i<len;i++) { 688 Node node=list.item(i); 689 if(node instanceof Element) { 690 query.setAt(KeyImpl.init(name),++count,_deserialize((Element) node)); 691 } 692 } 693 694 } 695 696 /** 697 * Desirialize a Component Object 698 * @param elComp Component Object as XML Element 699 * @return Component Object 700 * @throws ConverterException 701 * @throws ConverterException 702 */ 703 private Object _deserializeComponent(Element elComp) throws ConverterException { 704 // String type=elStruct.getAttribute("type"); 705 String name=elComp.getAttribute("name"); 706 String md5=elComp.getAttribute("md5"); 707 708 // TLPC 709 PageContext pc = ThreadLocalPageContext.get(); 710 711 // Load comp 712 ComponentAccess comp=null; 713 try { 714 comp = ComponentUtil.toComponentAccess(pc.loadComponent(name)); 715 if(!ComponentUtil.md5(comp).equals(md5)){ 716 throw new ConverterException("component ["+name+"] in this enviroment has not the same interface as the component to load"); 717 } 718 } 719 catch (ConverterException e) { 720 throw e; 721 } 722 catch (Exception e) { 723 throw new ConverterException(e.getMessage()); 724 } 725 726 727 NodeList list=elComp.getChildNodes(); 728 ComponentScope scope = comp.getComponentScope(); 729 int len=list.getLength(); 730 String scopeName; 731 Element var,value; 732 Collection.Key key; 733 for(int i=0;i<len;i++) { 734 Node node=list.item(i); 735 if(node instanceof Element) { 736 var=(Element)node; 737 value=getChildElement((Element)node); 738 scopeName=var.getAttribute("scope"); 739 if(value!=null) { 740 key=Caster.toKey(var.getAttribute("name"),null); 741 if(key==null) continue; 742 if("variables".equalsIgnoreCase(scopeName)) 743 scope.setEL(key,_deserialize(value)); 744 else 745 comp.setEL(key,_deserialize(value)); 746 } 747 } 748 } 749 return comp; 750 } 751 752 /** 753 * Desirialize a Struct Object 754 * @param elStruct Struct Object as XML Element 755 * @return Struct Object 756 * @throws ConverterException 757 */ 758 private Object _deserializeStruct(Element elStruct) throws ConverterException { 759 String type=elStruct.getAttribute("type"); 760 Struct struct=new StructImpl(); 761 762 NodeList list=elStruct.getChildNodes(); 763 int len=list.getLength(); 764 for(int i=0;i<len;i++) { 765 //print.ln(i); 766 767 Node node=list.item(i); 768 if(node instanceof Element) { 769 Element var=(Element)node; 770 Element value=getChildElement((Element)node); 771 if(value!=null) { 772 struct.setEL(var.getAttribute("name"),_deserialize(value)); 773 774 } 775 } 776 } 777 if(struct.size()==0 && type!=null && type.length()>0) { 778 return ""; 779 } 780 return struct; 781 } 782 783 /** 784 * Desirialize a Struct Object 785 * @param el Struct Object as XML Element 786 * @return Struct Object 787 * @throws ConverterException 788 */ 789 private Array _deserializeArray(Element el) throws ConverterException { 790 Array array=new ArrayImpl(); 791 792 NodeList list=el.getChildNodes(); 793 int len=list.getLength(); 794 for(int i=0;i<len;i++) { 795 Node node=list.item(i); 796 if(node instanceof Element) 797 try { 798 array.append(_deserialize((Element)node)); 799 } catch (PageException e) { 800 throw toConverterException(e); 801 } 802 803 } 804 return array; 805 } 806 807 /** 808 * return fitst child Element of a Element, if there are no child Elements return null 809 * @param parent parent node 810 * @return child Element 811 */ 812 private Element getChildElement(Element parent) { 813 NodeList list=parent.getChildNodes(); 814 int len=list.getLength(); 815 for(int i=0;i<len;i++) { 816 Node node=list.item(i); 817 if(node instanceof Element) { 818 return (Element)node; 819 } 820 } 821 return null; 822 } 823 824 825 /** 826 * @return return current blockquote 827 */ 828 private String goIn() { 829 //StringBuffer rtn=new StringBuffer(deep); 830 //for(int i=0;i<deep;i++) rtn.append('\t'); 831 //return rtn.toString(); 832 return ""; 833 } 834 835 @Override 836 public boolean equals(Object obj) { 837 return timeZone.equals(obj); 838 } 839 }