001 package railo.runtime.text.xml; 002 003 import java.util.ArrayList; 004 import java.util.Comparator; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.Map.Entry; 008 009 import org.w3c.dom.Document; 010 import org.w3c.dom.Node; 011 import org.w3c.dom.NodeList; 012 013 import railo.runtime.PageContext; 014 import railo.runtime.dump.DumpData; 015 import railo.runtime.dump.DumpProperties; 016 import railo.runtime.dump.DumpTable; 017 import railo.runtime.dump.DumpUtil; 018 import railo.runtime.dump.SimpleDumpData; 019 import railo.runtime.exp.ExpressionException; 020 import railo.runtime.exp.PageException; 021 import railo.runtime.op.Caster; 022 import railo.runtime.text.xml.struct.XMLObject; 023 import railo.runtime.text.xml.struct.XMLStruct; 024 import railo.runtime.type.Collection; 025 import railo.runtime.type.KeyImpl; 026 import railo.runtime.type.dt.DateTime; 027 import railo.runtime.type.it.EntryIterator; 028 import railo.runtime.type.it.KeyIterator; 029 import railo.runtime.type.it.StringIterator; 030 import railo.runtime.type.util.ArraySupport; 031 import railo.runtime.type.util.ArrayUtil; 032 import railo.runtime.util.ArrayIterator; 033 034 /** 035 * 036 */ 037 public final class XMLNodeList extends ArraySupport implements NodeList, XMLObject{ 038 039 private boolean caseSensitive; 040 private Document doc; 041 private Node parent; 042 private String filter; 043 044 /** 045 * @param parent Parent Node 046 * @param caseSensitive 047 */ 048 public XMLNodeList(Node parent, boolean caseSensitive) { 049 this(parent,caseSensitive,null); 050 } 051 public XMLNodeList(Node parent, boolean caseSensitive, String filter) { 052 if(parent instanceof XMLStruct) { 053 XMLStruct xmlNode = ((XMLStruct)parent); 054 this.parent=xmlNode.toNode(); 055 this.caseSensitive=xmlNode.getCaseSensitive(); 056 } 057 else { 058 this.parent=parent; 059 this.caseSensitive=caseSensitive; 060 } 061 this.doc=this.parent.getOwnerDocument(); 062 this.filter=filter; 063 } 064 065 @Override 066 public int getLength() { 067 return XMLUtil.childNodesLength(parent,Node.ELEMENT_NODE,caseSensitive,filter); 068 } 069 070 @Override 071 public Node item(int index) { 072 return XMLCaster.toXMLStruct(getChildNode(index),caseSensitive); 073 } 074 075 @Override 076 public int size() { 077 return getLength(); 078 } 079 080 @Override 081 public Collection.Key[] keys() { 082 Collection.Key[] keys=new Collection.Key[getLength()]; 083 for(int i=1;i<=keys.length;i++) { 084 keys[i-1]=KeyImpl.init(i+""); 085 } 086 return keys; 087 } 088 089 @Override 090 public int[] intKeys() { 091 int[] keys=new int[getLength()]; 092 for(int i=1;i<=keys.length;i++) { 093 keys[i-1]=i; 094 } 095 return keys; 096 } 097 098 public Object removeEL(Collection.Key key) { 099 return removeEL(Caster.toIntValue(key.getString(),-1)); 100 } 101 102 103 @Override 104 public Object remove(Collection.Key key) throws PageException { 105 return removeE(Caster.toIntValue(key.getString())); 106 } 107 108 @Override 109 public Object removeEL(int index) { 110 int len=size(); 111 if(index<1 || index>len) return null; 112 try { 113 return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive); 114 } 115 catch (Exception e) { 116 return null; 117 } 118 } 119 120 @Override 121 public Object removeE(int index) throws PageException { 122 int len=size(); 123 if(index<1 || index>len) 124 throw new ExpressionException("can't remove value form XML Node List at index "+index+ 125 ", valid indexes goes from 1 to "+len); 126 return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive); 127 } 128 129 @Override 130 public void clear() { 131 Node[] nodes=getChildNodesAsArray(); 132 for(int i=0;i<nodes.length;i++) { 133 parent.removeChild(XMLCaster.toRawNode(nodes[i])); 134 } 135 } 136 137 138 @Override 139 public Object get(String key) throws ExpressionException { 140 return getE(Caster.toIntValue(key)); 141 } 142 143 @Override 144 public Object get(Collection.Key key) throws ExpressionException { 145 return get(key.getString()); 146 } 147 148 @Override 149 public Object getE(int key) throws ExpressionException { 150 Object rtn= item(key-1); 151 if(rtn==null) throw new ExpressionException("invalid index ["+key+"] for XML Node List , indexes goes from [0-"+size()+"]"); 152 return rtn; 153 } 154 155 @Override 156 public Object get(String key, Object defaultValue) { 157 int index=Caster.toIntValue(key,Integer.MIN_VALUE); 158 if(index==Integer.MIN_VALUE) return defaultValue; 159 return get(index,defaultValue); 160 } 161 162 @Override 163 public Object get(Collection.Key key, Object defaultValue) { 164 return get(key.getString(),defaultValue); 165 } 166 167 @Override 168 public Object get(int key, Object defaultValue) { 169 Object rtn= item(key-1); 170 if(rtn==null) return defaultValue; 171 return rtn; 172 } 173 174 @Override 175 public Object set(String key, Object value) throws PageException { 176 return setE(Caster.toIntValue(key),value); 177 } 178 179 @Override 180 public Object set(Collection.Key key, Object value) throws PageException { 181 return set(key.getString(), value); 182 } 183 184 @Override 185 public Object setE(int index, Object value) throws PageException { 186 // check min Index 187 if(index<1) 188 throw new ExpressionException("invalid index ["+index+"] to set a child node, valid indexes start at 1"); 189 190 Node[] nodes=getChildNodesAsArray(); 191 192 // if index Greater len append 193 if(index>nodes.length) return append(value); 194 195 // remove all children 196 clear(); 197 198 // set all children before new Element 199 for(int i=1;i<index;i++) { 200 append(nodes[i-1]); 201 } 202 203 // set new Element 204 append(XMLCaster.toNode(doc,value)); 205 206 // set all after new Element 207 for(int i=index;i<nodes.length;i++) { 208 append(nodes[i]); 209 } 210 211 return value; 212 } 213 214 @Override 215 public Object setEL(String key, Object value) { 216 int index=Caster.toIntValue(key,Integer.MIN_VALUE); 217 if(index==Integer.MIN_VALUE) return null; 218 return setEL(index,value); 219 } 220 221 @Override 222 public Object setEL(Collection.Key key, Object value) { 223 return setEL(key.getString(), value); 224 } 225 226 @Override 227 public Object setEL(int index, Object value) { 228 try { 229 return setE(index,value); 230 } catch (PageException e) { 231 return null; 232 } 233 } 234 235 @Override 236 public Iterator<Collection.Key> keyIterator() { 237 return new KeyIterator(keys()); 238 } 239 240 @Override 241 public Iterator<String> keysAsStringIterator() { 242 return new StringIterator(keys()); 243 } 244 245 @Override 246 public Iterator<Entry<Key, Object>> entryIterator() { 247 return new EntryIterator(this,keys()); 248 } 249 250 public Iterator<Object> valueIterator() { 251 Object[] values=new Object[getLength()]; 252 for(int i=0;i<values.length;i++) { 253 values[i]=item(i); 254 } 255 return new ArrayIterator(values); 256 } 257 258 @Override 259 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 260 maxlevel--; 261 DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000"); 262 table.setTitle("Array (XML Node List)"); 263 int len=size(); 264 265 for(int i=1;i<=len;i++) { 266 table.appendRow(1,new SimpleDumpData(i),DumpUtil.toDumpData(item(i-1), pageContext,maxlevel,dp)); 267 } 268 return table; 269 } 270 271 @Override 272 public Object append(Object o) throws PageException { 273 return parent.appendChild(XMLCaster.toNode(doc,o)); 274 } 275 276 public Object appendEL(Object o) { 277 try { 278 return append(o); 279 } catch (Exception e) { 280 return null; 281 } 282 } 283 284 @Override 285 public Object clone() { 286 return duplicate(true); 287 } 288 289 290 @Override 291 public Collection duplicate(boolean deepCopy) { 292 return new XMLNodeList(parent.cloneNode(deepCopy),caseSensitive); 293 } 294 295 296 @Override 297 public int getDimension() { 298 return 1; 299 } 300 301 @Override 302 public boolean insert(int index, Object value) throws PageException { 303 // check min Index 304 if(index<1) 305 throw new ExpressionException("invalid index ["+index+"] to insert a child node, valid indexes start at 1"); 306 307 Node[] nodes=getChildNodesAsArray(); 308 309 // if index Greater len append 310 if(index>nodes.length) { 311 append(value); 312 return true; 313 } 314 315 // remove all children 316 clear(); 317 318 // set all children before new Element 319 for(int i=1;i<index;i++) { 320 append(nodes[i-1]); 321 } 322 323 // set new Element 324 append(XMLCaster.toNode(doc,value)); 325 326 // set all after new Element 327 for(int i=index;i<=nodes.length;i++) { 328 append(nodes[i-1]); 329 } 330 331 return true; 332 } 333 334 @Override 335 public Object prepend(Object o) throws PageException { 336 337 Node[] nodes=getChildNodesAsArray(); 338 339 // remove all children 340 clear(); 341 342 // set new Element 343 append(XMLCaster.toNode(doc,o)); 344 345 // set all after new Element 346 for(int i=0;i<nodes.length;i++) { 347 append(nodes[i]); 348 } 349 return o; 350 } 351 352 @Override 353 public void resize(int to) throws ExpressionException { 354 if(to>size())throw new ExpressionException("can't resize a XML Node List Array with empty Elements"); 355 } 356 357 @Override 358 public void sort(String sortType, String sortOrder) 359 throws ExpressionException { 360 throw new ExpressionException("can't sort a XML Node List Array","sorttype:"+sortType+";sortorder:"+sortOrder); 361 } 362 363 @Override 364 public void sort(Comparator comp) 365 throws ExpressionException { 366 throw new ExpressionException("can't sort a XML Node List Array"); 367 } 368 369 @Override 370 public Object[] toArray() { 371 return getChildNodesAsArray(); 372 } 373 374 public ArrayList toArrayList() { 375 Object[] arr=toArray(); 376 ArrayList list=new ArrayList(); 377 for(int i=0;i>arr.length;i++) { 378 list.add(arr[i]); 379 } 380 return list; 381 } 382 383 /** 384 * @return returns a output from the content as plain Text 385 */ 386 public String toPlain() { 387 StringBuffer sb=new StringBuffer(); 388 int length=size(); 389 for(int i=1;i<=length;i++) { 390 sb.append(i); 391 sb.append(": "); 392 sb.append(get(i,null)); 393 sb.append("\n"); 394 } 395 return sb.toString(); 396 } 397 398 private NodeList getChildNodes() { 399 return XMLUtil.getChildNodes(parent,Node.ELEMENT_NODE,caseSensitive,filter); 400 } 401 402 private Node getChildNode(int index) { 403 return XMLUtil.getChildNode(parent,Node.ELEMENT_NODE,caseSensitive,filter,index); 404 } 405 406 private Node[] getChildNodesAsArray() { 407 return XMLUtil.getChildNodesAsArray(parent,Node.ELEMENT_NODE,caseSensitive,filter); 408 } 409 410 @Override 411 public boolean containsKey(String key) { 412 return get(key,null)!=null; 413 } 414 415 @Override 416 public boolean containsKey(Collection.Key key) { 417 return get(key,null)!=null; 418 } 419 420 @Override 421 public boolean containsKey(int key) { 422 return get(key,null)!=null; 423 } 424 425 @Override 426 public boolean getCaseSensitive() { 427 return caseSensitive; 428 } 429 430 @Override 431 public String castToString() throws ExpressionException { 432 throw new ExpressionException("Can't cast XML NodeList to String"); 433 } 434 435 @Override 436 public String castToString(String defaultValue) { 437 return defaultValue; 438 } 439 440 @Override 441 public boolean castToBooleanValue() throws ExpressionException { 442 throw new ExpressionException("Can't cast XML NodeList to a boolean value"); 443 } 444 445 @Override 446 public Boolean castToBoolean(Boolean defaultValue) { 447 return defaultValue; 448 } 449 450 451 @Override 452 public double castToDoubleValue() throws ExpressionException { 453 throw new ExpressionException("Can't cast XML NodeList to a number value"); 454 } 455 456 @Override 457 public double castToDoubleValue(double defaultValue) { 458 return defaultValue; 459 } 460 461 462 @Override 463 public DateTime castToDateTime() throws ExpressionException { 464 throw new ExpressionException("Can't cast XML NodeList to a Date"); 465 } 466 467 @Override 468 public DateTime castToDateTime(DateTime defaultValue) { 469 return defaultValue; 470 } 471 472 @Override 473 public int compareTo(boolean b) throws ExpressionException { 474 throw new ExpressionException("can't compare XML NodeList with a boolean value"); 475 } 476 477 @Override 478 public int compareTo(DateTime dt) throws PageException { 479 throw new ExpressionException("can't compare XML NodeList with a DateTime Object"); 480 } 481 482 @Override 483 public int compareTo(double d) throws PageException { 484 throw new ExpressionException("can't compare XML NodeList with a numeric value"); 485 } 486 487 @Override 488 public int compareTo(String str) throws PageException { 489 throw new ExpressionException("can't compare XML NodeList with a String"); 490 } 491 492 @Override 493 public long sizeOf() { 494 return ArrayUtil.sizeOf((List)this); 495 } 496 }