001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.text.xml.struct; 020 021import java.lang.reflect.Method; 022import java.util.Date; 023import java.util.Iterator; 024import java.util.Map; 025 026import lucee.commons.collection.MapFactory; 027import lucee.runtime.PageContext; 028import lucee.runtime.dump.DumpData; 029import lucee.runtime.dump.DumpProperties; 030import lucee.runtime.dump.DumpUtil; 031import lucee.runtime.exp.ExpressionException; 032import lucee.runtime.exp.PageException; 033import lucee.runtime.exp.PageRuntimeException; 034import lucee.runtime.exp.XMLException; 035import lucee.runtime.op.Caster; 036import lucee.runtime.op.Operator; 037import lucee.runtime.text.xml.XMLAttributes; 038import lucee.runtime.text.xml.XMLCaster; 039import lucee.runtime.text.xml.XMLNodeList; 040import lucee.runtime.text.xml.XMLUtil; 041import lucee.runtime.type.Collection; 042import lucee.runtime.type.KeyImpl; 043import lucee.runtime.type.dt.DateTime; 044import lucee.runtime.type.it.EntryIterator; 045import lucee.runtime.type.it.KeyIterator; 046import lucee.runtime.type.it.StringIterator; 047import lucee.runtime.type.it.ValueIterator; 048import lucee.runtime.type.util.ArrayUtil; 049import lucee.runtime.type.util.StructSupport; 050 051import org.w3c.dom.DOMException; 052import org.w3c.dom.Document; 053import org.w3c.dom.Element; 054import org.w3c.dom.NamedNodeMap; 055import org.w3c.dom.Node; 056import org.w3c.dom.NodeList; 057import org.w3c.dom.UserDataHandler; 058import org.xml.sax.SAXException; 059 060/** 061 * 062 */ 063public class XMLNodeStruct extends StructSupport implements XMLStruct { 064 065 private Node node; 066 protected boolean caseSensitive; 067 068 /** 069 * constructor of the class 070 * @param node Node 071 * @param caseSensitive 072 */ 073 protected XMLNodeStruct(Node node, boolean caseSensitive) { 074 if(node instanceof XMLStruct)node=((XMLStruct)node).toNode(); 075 this.node=node; 076 this.caseSensitive=caseSensitive; 077 } 078 079 @Override 080 public Object remove(Key key) throws PageException { 081 Object o= XMLUtil.removeProperty(node,key,caseSensitive); 082 if(o!=null)return o; 083 throw new ExpressionException("node has no child with name ["+key+"]"); 084 } 085 086 @Override 087 public Object removeEL(Key key) { 088 return XMLUtil.removeProperty(node,key,caseSensitive); 089 } 090 091 @Override 092 public Object get(Collection.Key key) throws PageException { 093 try { 094 return XMLUtil.getProperty(node,key,caseSensitive); 095 } catch (SAXException e) { 096 throw new XMLException(e); 097 } 098 } 099 100 @Override 101 public Object set(Collection.Key key, Object value) throws PageException { 102 return XMLUtil.setProperty(node,key,value,caseSensitive); 103 } 104 105 /** 106 * @return retun the inner map 107 */ 108 public Map<String,Node> getMap() { 109 NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hier ok? 110 Map<String,Node> map=MapFactory.<String,Node>getConcurrentMap(); 111 int len=elements.getLength(); 112 113 for(int i=0;i<len;i++) { 114 Node node=elements.item(i); 115 map.put(node.getNodeName(),node); 116 } 117 return map; 118 } 119 120 @Override 121 public Collection duplicate(boolean deepCopy) { 122 return new XMLNodeStruct(node.cloneNode(deepCopy),caseSensitive); 123 } 124 125 126 127 128 129 130 @Override 131 public Node cloneNode(boolean deep) { 132 return new XMLNodeStruct(node.cloneNode(deep),caseSensitive); 133 } 134 135 136 @Override 137 public short getNodeType() { 138 return node.getNodeType(); 139 } 140 141 @Override 142 public void normalize() { 143 node.normalize(); 144 } 145 146 @Override 147 public boolean hasAttributes() { 148 return node.hasAttributes(); 149 } 150 151 @Override 152 public boolean hasChildNodes() { 153 return node.hasChildNodes(); 154 } 155 156 @Override 157 public String getLocalName() { 158 return node.getLocalName(); 159 } 160 161 @Override 162 public String getNamespaceURI() { 163 return node.getNamespaceURI(); 164 } 165 166 @Override 167 public String getNodeName() { 168 return node.getNodeName(); 169 } 170 171 @Override 172 public String getNodeValue() throws DOMException { 173 return node.getNodeValue(); 174 } 175 176 @Override 177 public String getPrefix() { 178 return node.getPrefix(); 179 } 180 181 @Override 182 public void setNodeValue(String nodeValue) throws DOMException { 183 node.setNodeValue(nodeValue); 184 } 185 186 @Override 187 public void setPrefix(String prefix) throws DOMException { 188 node.setPrefix(prefix); 189 } 190 191 @Override 192 public Document getOwnerDocument() { 193 if(node instanceof Document) return (Document) node; 194 return node.getOwnerDocument(); 195 } 196 197 @Override 198 public NamedNodeMap getAttributes() { 199 return new XMLAttributes(node,caseSensitive); 200 } 201 202 @Override 203 public Node getFirstChild() { 204 return node.getFirstChild(); 205 } 206 207 @Override 208 public Node getLastChild() { 209 return node.getLastChild(); 210 } 211 212 @Override 213 public Node getNextSibling() { 214 return node.getNextSibling(); 215 } 216 217 @Override 218 public Node getParentNode() { 219 return node.getParentNode(); 220 } 221 222 @Override 223 public Node getPreviousSibling() { 224 return node.getPreviousSibling(); 225 } 226 227 228 229 @Override 230 public NodeList getChildNodes() { 231 return node.getChildNodes(); 232 } 233 234 @Override 235 public boolean isSupported(String feature, String version) { 236 return node.isSupported(feature, version); 237 } 238 239 @Override 240 public Node appendChild(Node newChild) throws DOMException { 241 return node.appendChild(newChild); 242 } 243 244 @Override 245 public Node removeChild(Node oldChild) throws DOMException { 246 return node.removeChild(XMLCaster.toRawNode(oldChild)); 247 } 248 249 @Override 250 public Node insertBefore(Node newChild, Node refChild) throws DOMException { 251 return node.insertBefore(newChild, refChild); 252 } 253 254 @Override 255 public Node replaceChild(Node newChild, Node oldChild) throws DOMException { 256 return node.replaceChild(XMLCaster.toRawNode(newChild), XMLCaster.toRawNode(oldChild)); 257 } 258 259 @Override 260 public int size() { 261 NodeList list = node.getChildNodes(); 262 int len=list.getLength(); 263 int count=0; 264 for(int i=0;i<len;i++) { 265 if(list.item(i) instanceof Element) count++; 266 } 267 return count; 268 } 269 270 public Collection.Key[] keys() { 271 NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE,false,null);// TODO ist das false hie ok 272 Collection.Key[] arr=new Collection.Key[elements.getLength()]; 273 for(int i=0;i<arr.length;i++) { 274 arr[i]=KeyImpl.init(elements.item(i).getNodeName()); 275 } 276 return arr; 277 } 278 279 @Override 280 public void clear() { 281 /*NodeList elements=XMLUtil.getChildNodes(node,Node.ELEMENT_NODE); 282 int len=elements.getLength(); 283 for(int i=0;i<len;i++) { 284 node.removeChild(elements.item(i)); 285 }*/ 286 } 287 288 @Override 289 public Object get(Collection.Key key, Object defaultValue) { 290 return XMLUtil.getProperty(node,key,caseSensitive,defaultValue); 291 } 292 293 @Override 294 public Object setEL(Key key, Object value) { 295 return XMLUtil.setProperty(node,key,value,caseSensitive,null); 296 } 297 298 @Override 299 public Iterator<Collection.Key> keyIterator() { 300 return new KeyIterator(keys()); 301 } 302 303 @Override 304 public Iterator<String> keysAsStringIterator() { 305 return new StringIterator(keys()); 306 } 307 308 @Override 309 public Iterator<Entry<Key, Object>> entryIterator() { 310 return new EntryIterator(this,keys()); 311 } 312 313 @Override 314 public Iterator<Object> valueIterator() { 315 return new ValueIterator(this,keys()); 316 } 317 318 @Override 319 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 320 return DumpUtil.toDumpData(node, pageContext,maxlevel,dp); 321 } 322 323 @Override 324 public final Node toNode() { 325 return node; 326 } 327 328 /** 329 * @return Returns the caseSensitive. 330 */ 331 public boolean getCaseSensitive() { 332 return caseSensitive; 333 } 334 335 @Override 336 public boolean containsKey(Collection.Key key) { 337 return get(key,null)!=null; 338 } 339 340 @Override 341 public XMLNodeList getXMLNodeList() { 342 return new XMLNodeList(node,getCaseSensitive(),Node.ELEMENT_NODE); 343 } 344 345 @Override 346 public String castToString() throws PageException { 347 return XMLCaster.toString(this.node); 348 } 349 350 @Override 351 public String castToString(String defaultValue) { 352 return XMLCaster.toString(this.node,defaultValue); 353 } 354 355 @Override 356 public boolean castToBooleanValue() throws ExpressionException { 357 throw new ExpressionException("Can't cast XML Node to a boolean value"); 358 } 359 360 @Override 361 public Boolean castToBoolean(Boolean defaultValue) { 362 return defaultValue; 363 } 364 365 366 @Override 367 public double castToDoubleValue() throws ExpressionException { 368 throw new ExpressionException("Can't cast XML Node to a number value"); 369 } 370 371 @Override 372 public double castToDoubleValue(double defaultValue) { 373 return defaultValue; 374 } 375 376 377 @Override 378 public DateTime castToDateTime() throws ExpressionException { 379 throw new ExpressionException("Can't cast XML Node to a Date"); 380 } 381 382 @Override 383 public DateTime castToDateTime(DateTime defaultValue) { 384 return defaultValue; 385 } 386 387 @Override 388 public int compareTo(boolean b) throws PageException { 389 return Operator.compare(castToString(), b); 390 } 391 392 @Override 393 public int compareTo(DateTime dt) throws PageException { 394 return Operator.compare(castToString(), (Date)dt); 395 } 396 397 @Override 398 public int compareTo(double d) throws PageException { 399 return Operator.compare(castToString(), d); 400 } 401 402 @Override 403 public int compareTo(String str) throws PageException { 404 return Operator.compare(castToString(), str); 405 } 406 407 public String getBaseURI() { 408 // not supported 409 return null; 410 } 411 412 public short compareDocumentPosition(Node other) throws DOMException { 413 // not supported 414 return -1; 415 } 416 417 public void setTextContent(String textContent) throws DOMException { 418 //TODO not supported 419 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,"this method is not supported"); 420 } 421 422 public boolean isSameNode(Node other) { 423 return this==other; 424 } 425 426 public String lookupPrefix(String namespaceURI) { 427// TODO not supported 428 return null; 429 } 430 431 public boolean isDefaultNamespace(String namespaceURI) { 432// TODO not supported 433 return false; 434 } 435 436 public String lookupNamespaceURI(String prefix) { 437// TODO not supported 438 return null; 439 } 440 441 public boolean isEqualNode(Node node) { 442// TODO not supported 443 return this==node; 444 } 445 446 public Object getFeature(String feature, String version) { 447 // TODO not supported 448 return null; 449 } 450 451 public Object getUserData(String key) { 452 // dynamic load to support jre 1.4 and 1.5 453 try { 454 Method m = node.getClass().getMethod("getUserData", new Class[]{key.getClass()}); 455 return m.invoke(node, new Object[]{key}); 456 } 457 catch (Exception e) { 458 throw new PageRuntimeException(Caster.toPageException(e)); 459 } 460 } 461 462 public String getTextContent() throws DOMException { 463 // dynamic load to support jre 1.4 and 1.5 464 try { 465 Method m = node.getClass().getMethod("getTextContent", new Class[]{}); 466 return Caster.toString(m.invoke(node, ArrayUtil.OBJECT_EMPTY)); 467 } 468 catch (Exception e) { 469 throw new PageRuntimeException(Caster.toPageException(e)); 470 } 471 } 472 473 public Object setUserData(String key, Object data, UserDataHandler handler) { 474 // dynamic load to support jre 1.4 and 1.5 475 try { 476 Method m = node.getClass().getMethod("setUserData", new Class[]{key.getClass(),data.getClass(),handler.getClass()}); 477 return m.invoke(node, new Object[]{key,data,handler}); 478 } 479 catch (Exception e) { 480 throw new PageRuntimeException(Caster.toPageException(e)); 481 } 482 } 483 484 public boolean isCaseSensitive() { 485 return caseSensitive; 486 } 487 488 public boolean equals(Object obj) { 489 if(!(obj instanceof XMLNodeStruct)) 490 return super.equals(obj); 491 XMLNodeStruct other = ((XMLNodeStruct)obj); 492 return other.caseSensitive=caseSensitive && other.node.equals(node); 493 } 494 495 496 497}