001 package railo.runtime.text.xml.struct; 002 003 import java.lang.reflect.Method; 004 import java.util.Date; 005 import java.util.Iterator; 006 import java.util.Map; 007 008 import org.w3c.dom.DOMException; 009 import org.w3c.dom.Document; 010 import org.w3c.dom.Element; 011 import org.w3c.dom.NamedNodeMap; 012 import org.w3c.dom.Node; 013 import org.w3c.dom.NodeList; 014 import org.w3c.dom.UserDataHandler; 015 import org.xml.sax.SAXException; 016 017 import railo.commons.collections.HashTable; 018 import railo.runtime.PageContext; 019 import railo.runtime.dump.DumpData; 020 import railo.runtime.dump.DumpProperties; 021 import railo.runtime.dump.DumpUtil; 022 import railo.runtime.exp.ExpressionException; 023 import railo.runtime.exp.PageException; 024 import railo.runtime.exp.PageRuntimeException; 025 import railo.runtime.exp.XMLException; 026 import railo.runtime.op.Caster; 027 import railo.runtime.op.Operator; 028 import railo.runtime.text.xml.XMLAttributes; 029 import railo.runtime.text.xml.XMLCaster; 030 import railo.runtime.text.xml.XMLNodeList; 031 import railo.runtime.text.xml.XMLUtil; 032 import railo.runtime.type.Collection; 033 import railo.runtime.type.KeyImpl; 034 import railo.runtime.type.dt.DateTime; 035 import railo.runtime.type.util.ArrayUtil; 036 import railo.runtime.type.util.StructSupport; 037 import railo.runtime.util.ArrayIterator; 038 039 /** 040 * 041 */ 042 public class XMLNodeStruct extends StructSupport implements XMLStruct { 043 044 private Node node; 045 protected boolean caseSensitive; 046 047 /** 048 * constructor of the class 049 * @param node Node 050 * @param caseSensitive 051 */ 052 protected XMLNodeStruct(Node node, boolean caseSensitive) { 053 if(node instanceof XMLStruct)node=((XMLStruct)node).toNode(); 054 this.node=node; 055 this.caseSensitive=caseSensitive; 056 } 057 058 /** 059 * @see railo.runtime.type.Collection#remove(java.lang.String) 060 */ 061 public Object remove(String key) throws PageException { 062 Object o= XMLUtil.removeProperty(node,KeyImpl.init(key),caseSensitive); 063 if(o!=null)return o; 064 throw new ExpressionException("node has no child with name ["+key+"]"); 065 } 066 067 /** 068 * 069 * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key) 070 */ 071 public Object remove(Key key) throws PageException { 072 Object o= XMLUtil.removeProperty(node,key,caseSensitive); 073 if(o!=null)return o; 074 throw new ExpressionException("node has no child with name ["+key+"]"); 075 } 076 077 /** 078 * 079 * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key) 080 */ 081 public Object removeEL(Key key) { 082 return XMLUtil.removeProperty(node,key,caseSensitive); 083 } 084 085 /** 086 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key) 087 */ 088 public Object get(Collection.Key key) throws PageException { 089 try { 090 return XMLUtil.getProperty(node,key,caseSensitive); 091 } catch (SAXException e) { 092 throw new XMLException(e); 093 } 094 } 095 096 /** 097 * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object) 098 */ 099 public Object set(Collection.Key key, Object value) throws PageException { 100 return XMLUtil.setProperty(node,key,value,caseSensitive); 101 } 102 103 /** 104 * @return retun the inner map 105 */ 106 public Map getMap() { 107 NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hier ok? 108 Map map=new HashTable(); 109 int len=elements.getLength(); 110 111 for(int i=0;i<len;i++) { 112 Node node=elements.item(i); 113 map.put(node.getNodeName(),node); 114 } 115 return map; 116 } 117 118 /** 119 * 120 * @see railo.runtime.type.Collection#duplicate(boolean) 121 */ 122 public Collection duplicate(boolean deepCopy) { 123 return new XMLNodeStruct(node.cloneNode(deepCopy),caseSensitive); 124 } 125 126 127 128 129 130 131 /** 132 * @see org.w3c.dom.Node#cloneNode(boolean) 133 */ 134 public Node cloneNode(boolean deep) { 135 return new XMLNodeStruct(node.cloneNode(deep),caseSensitive); 136 } 137 138 139 /** 140 * @see org.w3c.dom.Node#getNodeType() 141 */ 142 public short getNodeType() { 143 return node.getNodeType(); 144 } 145 146 /** 147 * @see org.w3c.dom.Node#normalize() 148 */ 149 public void normalize() { 150 node.normalize(); 151 } 152 153 /** 154 * @see org.w3c.dom.Node#hasAttributes() 155 */ 156 public boolean hasAttributes() { 157 return node.hasAttributes(); 158 } 159 160 /** 161 * @see org.w3c.dom.Node#hasChildNodes() 162 */ 163 public boolean hasChildNodes() { 164 return node.hasChildNodes(); 165 } 166 167 /** 168 * @see org.w3c.dom.Node#getLocalName() 169 */ 170 public String getLocalName() { 171 return node.getLocalName(); 172 } 173 174 /** 175 * @see org.w3c.dom.Node#getNamespaceURI() 176 */ 177 public String getNamespaceURI() { 178 return node.getNamespaceURI(); 179 } 180 181 /** 182 * @see org.w3c.dom.Node#getNodeName() 183 */ 184 public String getNodeName() { 185 return node.getNodeName(); 186 } 187 188 /** 189 * @see org.w3c.dom.Node#getNodeValue() 190 */ 191 public String getNodeValue() throws DOMException { 192 return node.getNodeValue(); 193 } 194 195 /** 196 * @see org.w3c.dom.Node#getPrefix() 197 */ 198 public String getPrefix() { 199 return node.getPrefix(); 200 } 201 202 /** 203 * @see org.w3c.dom.Node#setNodeValue(java.lang.String) 204 */ 205 public void setNodeValue(String nodeValue) throws DOMException { 206 node.setNodeValue(nodeValue); 207 } 208 209 /** 210 * @see org.w3c.dom.Node#setPrefix(java.lang.String) 211 */ 212 public void setPrefix(String prefix) throws DOMException { 213 node.setPrefix(prefix); 214 } 215 216 /** 217 * @see org.w3c.dom.Node#getOwnerDocument() 218 */ 219 public Document getOwnerDocument() { 220 if(node instanceof Document) return (Document) node; 221 return node.getOwnerDocument(); 222 } 223 224 /** 225 * @see org.w3c.dom.Node#getAttributes() 226 */ 227 public NamedNodeMap getAttributes() { 228 return new XMLAttributes(node.getAttributes(),caseSensitive); 229 } 230 231 /** 232 * @see org.w3c.dom.Node#getFirstChild() 233 */ 234 public Node getFirstChild() { 235 return node.getFirstChild(); 236 } 237 238 /** 239 * @see org.w3c.dom.Node#getLastChild() 240 */ 241 public Node getLastChild() { 242 return node.getLastChild(); 243 } 244 245 /** 246 * @see org.w3c.dom.Node#getNextSibling() 247 */ 248 public Node getNextSibling() { 249 return node.getNextSibling(); 250 } 251 252 /** 253 * @see org.w3c.dom.Node#getParentNode() 254 */ 255 public Node getParentNode() { 256 return node.getParentNode(); 257 } 258 259 /** 260 * @see org.w3c.dom.Node#getPreviousSibling() 261 */ 262 public Node getPreviousSibling() { 263 return node.getPreviousSibling(); 264 } 265 266 267 268 /** 269 * @see org.w3c.dom.Node#getChildNodes() 270 */ 271 public NodeList getChildNodes() { 272 return node.getChildNodes(); 273 } 274 275 /** 276 * @see org.w3c.dom.Node#isSupported(java.lang.String, java.lang.String) 277 */ 278 public boolean isSupported(String feature, String version) { 279 return node.isSupported(feature, version); 280 } 281 282 /** 283 * @see org.w3c.dom.Node#appendChild(org.w3c.dom.Node) 284 */ 285 public Node appendChild(Node newChild) throws DOMException { 286 return node.appendChild(newChild); 287 } 288 289 /** 290 * @see org.w3c.dom.Node#removeChild(org.w3c.dom.Node) 291 */ 292 public Node removeChild(Node oldChild) throws DOMException { 293 return node.removeChild(XMLCaster.toRawNode(oldChild)); 294 } 295 296 /** 297 * @see org.w3c.dom.Node#insertBefore(org.w3c.dom.Node, org.w3c.dom.Node) 298 */ 299 public Node insertBefore(Node newChild, Node refChild) throws DOMException { 300 return node.insertBefore(newChild, refChild); 301 } 302 303 /** 304 * @see org.w3c.dom.Node#replaceChild(org.w3c.dom.Node, org.w3c.dom.Node) 305 */ 306 public Node replaceChild(Node newChild, Node oldChild) throws DOMException { 307 return node.replaceChild(XMLCaster.toRawNode(newChild), XMLCaster.toRawNode(oldChild)); 308 } 309 310 /** 311 * @see railo.runtime.type.Collection#size() 312 */ 313 public int size() { 314 NodeList list = node.getChildNodes(); 315 int len=list.getLength(); 316 int count=0; 317 for(int i=0;i<len;i++) { 318 if(list.item(i) instanceof Element) count++; 319 } 320 return count; 321 } 322 323 public String[] keysAsString() { 324 NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hier OK? 325 String[] arr=new String[elements.getLength()]; 326 for(int i=0;i<arr.length;i++) { 327 arr[i]=elements.item(i).getNodeName(); 328 } 329 return arr; 330 } 331 332 public Collection.Key[] keys() { 333 NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hie ok 334 Collection.Key[] arr=new Collection.Key[elements.getLength()]; 335 for(int i=0;i<arr.length;i++) { 336 arr[i]=KeyImpl.init(elements.item(i).getNodeName()); 337 } 338 return arr; 339 } 340 341 /** 342 * @see railo.runtime.type.Collection#clear() 343 */ 344 public void clear() { 345 /*NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE); 346 int len=elements.getLength(); 347 for(int i=0;i<len;i++) { 348 node.removeChild(elements.item(i)); 349 }*/ 350 } 351 352 /** 353 * 354 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object) 355 */ 356 public Object get(Collection.Key key, Object defaultValue) { 357 return XMLUtil.getPropertyEL(node,key,caseSensitive); 358 } 359 360 /** 361 * 362 * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object) 363 */ 364 public Object setEL(Key key, Object value) { 365 return XMLUtil.setPropertyEL(node,key,value,caseSensitive); 366 } 367 368 /** 369 * @see railo.runtime.type.Collection#keyIterator() 370 */ 371 public Iterator keyIterator() { 372 return new ArrayIterator(keysAsString()); 373 } 374 375 /** 376 * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int) 377 */ 378 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 379 return DumpUtil.toDumpData(node, pageContext,maxlevel,dp); 380 } 381 382 /** 383 * @see railo.runtime.text.xml.struct.XMLStruct#toNode() 384 */ 385 public final Node toNode() { 386 return node; 387 } 388 389 /** 390 * @return Returns the caseSensitive. 391 */ 392 public boolean getCaseSensitive() { 393 return caseSensitive; 394 } 395 396 /** 397 * 398 * @see railo.runtime.type.Collection#containsKey(railo.runtime.type.Collection.Key) 399 */ 400 public boolean containsKey(Collection.Key key) { 401 return get(key,null)!=null; 402 } 403 404 /** 405 * @see railo.runtime.text.xml.struct.XMLStruct#getXMLNodeList() 406 */ 407 public XMLNodeList getXMLNodeList() { 408 return new XMLNodeList(node,getCaseSensitive()); 409 } 410 411 /** 412 * @see railo.runtime.op.Castable#castToString() 413 */ 414 public String castToString() throws PageException { 415 return XMLCaster.toString(this.node); 416 } 417 418 /** 419 * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String) 420 */ 421 public String castToString(String defaultValue) { 422 return XMLCaster.toString(this.node,defaultValue); 423 } 424 425 /** 426 * @see railo.runtime.op.Castable#castToBooleanValue() 427 */ 428 public boolean castToBooleanValue() throws ExpressionException { 429 throw new ExpressionException("Can't cast XML Node to a boolean value"); 430 } 431 432 /** 433 * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean) 434 */ 435 public Boolean castToBoolean(Boolean defaultValue) { 436 return defaultValue; 437 } 438 439 440 /** 441 * @see railo.runtime.op.Castable#castToDoubleValue() 442 */ 443 public double castToDoubleValue() throws ExpressionException { 444 throw new ExpressionException("Can't cast XML Node to a number value"); 445 } 446 447 /** 448 * @see railo.runtime.op.Castable#castToDoubleValue(double) 449 */ 450 public double castToDoubleValue(double defaultValue) { 451 return defaultValue; 452 } 453 454 455 /** 456 * @see railo.runtime.op.Castable#castToDateTime() 457 */ 458 public DateTime castToDateTime() throws ExpressionException { 459 throw new ExpressionException("Can't cast XML Node to a Date"); 460 } 461 462 /** 463 * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime) 464 */ 465 public DateTime castToDateTime(DateTime defaultValue) { 466 return defaultValue; 467 } 468 469 /** 470 * @see railo.runtime.op.Castable#compare(boolean) 471 */ 472 public int compareTo(boolean b) throws PageException { 473 return Operator.compare(castToString(), b); 474 } 475 476 /** 477 * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime) 478 */ 479 public int compareTo(DateTime dt) throws PageException { 480 return Operator.compare(castToString(), (Date)dt); 481 } 482 483 /** 484 * @see railo.runtime.op.Castable#compareTo(double) 485 */ 486 public int compareTo(double d) throws PageException { 487 return Operator.compare(castToString(), d); 488 } 489 490 /** 491 * @see railo.runtime.op.Castable#compareTo(java.lang.String) 492 */ 493 public int compareTo(String str) throws PageException { 494 return Operator.compare(castToString(), str); 495 } 496 497 /** 498 * @see org.w3c.dom.Node#getBaseURI() 499 */ 500 public String getBaseURI() { 501 // not supported 502 return null; 503 } 504 505 /** 506 * @see org.w3c.dom.Node#compareDocumentPosition(org.w3c.dom.Node) 507 */ 508 public short compareDocumentPosition(Node other) throws DOMException { 509 // not supported 510 return -1; 511 } 512 513 /* * 514 * @see org.w3c.dom.Node#getTextContent() 515 * / 516 public String getTextContent() throws DOMException { 517 switch(node.getNodeType()) { 518 case ELEMENT_NODE: 519 case ATTRIBUTE_NODE: 520 case ENTITY_NODE: 521 case ENTITY_REFERENCE_NODE: 522 case DOCUMENT_FRAGMENT_NODE: 523 NodeList list = node.getChildNodes(); 524 int len=list.getLength(); 525 StringBuffer sb=new StringBuffer(); 526 for(int i=0;i<len;i++) { 527 sb.append(list.item(i).getTextContent()); 528 } 529 return sb.toString(); 530 case TEXT_NODE: 531 case CDATA_SECTION_NODE: 532 case COMMENT_NODE: 533 case PROCESSING_INSTRUCTION_NODE: 534 return node.getNodeValue(); 535 536 } 537 return null; 538 }*/ 539 540 /** 541 * @see org.w3c.dom.Node#setTextContent(java.lang.String) 542 */ 543 public void setTextContent(String textContent) throws DOMException { 544 //TODO not supported 545 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,"this method is not supported"); 546 } 547 548 /** 549 * @see org.w3c.dom.Node#isSameNode(org.w3c.dom.Node) 550 */ 551 public boolean isSameNode(Node other) { 552 return this==other; 553 } 554 555 /** 556 * @see org.w3c.dom.Node#lookupPrefix(java.lang.String) 557 */ 558 public String lookupPrefix(String namespaceURI) { 559 // TODO not supported 560 return null; 561 } 562 563 /** 564 * @see org.w3c.dom.Node#isDefaultNamespace(java.lang.String) 565 */ 566 public boolean isDefaultNamespace(String namespaceURI) { 567 // TODO not supported 568 return false; 569 } 570 571 /** 572 * @see org.w3c.dom.Node#lookupNamespaceURI(java.lang.String) 573 */ 574 public String lookupNamespaceURI(String prefix) { 575 // TODO not supported 576 return null; 577 } 578 579 /** 580 * @see org.w3c.dom.Node#isEqualNode(org.w3c.dom.Node) 581 */ 582 public boolean isEqualNode(Node node) { 583 // TODO not supported 584 return this==node; 585 } 586 587 /** 588 * @see org.w3c.dom.Node#getFeature(java.lang.String, java.lang.String) 589 */ 590 public Object getFeature(String feature, String version) { 591 // TODO not supported 592 return null; 593 } 594 595 /** 596 * @see org.w3c.dom.Node#getUserData(java.lang.String) 597 */ 598 public Object getUserData(String key) { 599 // dynamic load to support jre 1.4 and 1.5 600 try { 601 Method m = node.getClass().getMethod("getUserData", new Class[]{key.getClass()}); 602 return m.invoke(node, new Object[]{key}); 603 } 604 catch (Exception e) { 605 throw new PageRuntimeException(Caster.toPageException(e)); 606 } 607 } 608 609 /** 610 * @see org.w3c.dom.Node#getTextContent() 611 */ 612 public String getTextContent() throws DOMException { 613 // dynamic load to support jre 1.4 and 1.5 614 try { 615 Method m = node.getClass().getMethod("getTextContent", new Class[]{}); 616 return Caster.toString(m.invoke(node, ArrayUtil.OBJECT_EMPTY)); 617 } 618 catch (Exception e) { 619 throw new PageRuntimeException(Caster.toPageException(e)); 620 } 621 } 622 623 /** 624 * @see org.w3c.dom.Node#setUserData(java.lang.String, java.lang.Object, org.w3c.dom.UserDataHandler) 625 */ 626 public Object setUserData(String key, Object data, UserDataHandler handler) { 627 // dynamic load to support jre 1.4 and 1.5 628 try { 629 Method m = node.getClass().getMethod("setUserData", new Class[]{key.getClass(),data.getClass(),handler.getClass()}); 630 return m.invoke(node, new Object[]{key,data,handler}); 631 } 632 catch (Exception e) { 633 throw new PageRuntimeException(Caster.toPageException(e)); 634 } 635 } 636 637 public boolean isCaseSensitive() { 638 return caseSensitive; 639 } 640 641 public boolean equals(Object obj) { 642 if(!(obj instanceof XMLNodeStruct)) 643 return super.equals(obj); 644 XMLNodeStruct other = ((XMLNodeStruct)obj); 645 return other.caseSensitive=caseSensitive && other.node.equals(node); 646 } 647 648 649 650 }