001 package railo.runtime.text.xml; 002 003 import java.util.ArrayList; 004 import java.util.Iterator; 005 006 import org.w3c.dom.Attr; 007 import org.w3c.dom.DOMException; 008 import org.w3c.dom.Document; 009 import org.w3c.dom.NamedNodeMap; 010 import org.w3c.dom.Node; 011 012 import railo.runtime.PageContext; 013 import railo.runtime.dump.DumpData; 014 import railo.runtime.dump.DumpProperties; 015 import railo.runtime.dump.DumpTable; 016 import railo.runtime.dump.DumpUtil; 017 import railo.runtime.dump.SimpleDumpData; 018 import railo.runtime.exp.ExpressionException; 019 import railo.runtime.exp.PageException; 020 import railo.runtime.exp.XMLException; 021 import railo.runtime.op.Caster; 022 import railo.runtime.type.Collection; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.Struct; 025 import railo.runtime.type.dt.DateTime; 026 import railo.runtime.type.it.EntryIterator; 027 import railo.runtime.type.it.KeyIterator; 028 import railo.runtime.type.it.StringIterator; 029 import railo.runtime.type.it.ValueIterator; 030 import railo.runtime.type.util.ListUtil; 031 import railo.runtime.type.util.StructSupport; 032 033 /** 034 * represent a Struct and a NamedNodeMap 035 */ 036 public final class XMLAttributes extends StructSupport implements Struct,NamedNodeMap { 037 038 039 private final NamedNodeMap nodeMap; 040 private final Document owner; 041 private final Node parent; 042 private final boolean caseSensitive; 043 044 /** 045 * constructor of the class (readonly) 046 * @param nodeMap 047 */ 048 public XMLAttributes(Node parent, boolean caseSensitive) { 049 this.owner=parent.getOwnerDocument(); 050 this.parent=parent; 051 this.nodeMap=parent.getAttributes(); 052 this.caseSensitive=caseSensitive; 053 } 054 055 @Override 056 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 057 Collection.Key[] keys=keys(); 058 maxlevel--; 059 DumpTable table = new DumpTable("xml","#999966","#cccc99","#000000"); 060 table.setTitle("Struct (XML Attributes)"); 061 062 int maxkeys=dp.getMaxKeys(); 063 int index=0; 064 Collection.Key k; 065 for(int i=0;i<keys.length;i++) { 066 k=keys[i]; 067 068 if(DumpUtil.keyValid(dp,maxlevel, k)){ 069 if(maxkeys<=index++)break; 070 table.appendRow(1,new SimpleDumpData(k.getString()),DumpUtil.toDumpData(get(k.getString(),null), pageContext,maxlevel,dp)); 071 } 072 } 073 return table; 074 } 075 076 077 @Override 078 public int size() { 079 return nodeMap.getLength(); 080 } 081 082 @Override 083 public Collection.Key[] keys() { 084 int len=nodeMap.getLength(); 085 ArrayList<Collection.Key> list =new ArrayList<Collection.Key>(); 086 for(int i=0;i<len;i++) { 087 Node item = nodeMap.item(i); 088 if(item instanceof Attr) 089 list.add(KeyImpl.init(((Attr)item).getName())); 090 } 091 return list.toArray(new Collection.Key[list.size()]); 092 } 093 094 @Override 095 public Object remove(Collection.Key k) throws PageException { 096 String key=k.getString(); 097 Node rtn=null; 098 if(!caseSensitive){ 099 int len = nodeMap.getLength(); 100 String nn; 101 for(int i=len-1;i>=0;i--) { 102 nn=nodeMap.item(i).getNodeName(); 103 if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn); 104 } 105 } 106 else rtn=nodeMap.removeNamedItem(toName(key)); 107 108 if(rtn!=null) return rtn.getNodeValue(); 109 throw new ExpressionException("can't remove element with name ["+key+"], element doesn't exist"); 110 } 111 112 @Override 113 public Object removeEL(Collection.Key k) { 114 String key=k.getString(); 115 Node rtn=null; 116 if(!caseSensitive){ 117 int len = nodeMap.getLength(); 118 String nn; 119 for(int i=len-1;i>=0;i--) { 120 nn=nodeMap.item(i).getNodeName(); 121 if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn); 122 } 123 } 124 else rtn=nodeMap.removeNamedItem(toName(key)); 125 126 if(rtn!=null) return rtn.getNodeValue(); 127 return null; 128 } 129 130 @Override 131 public void clear() { 132 Collection.Key[] keys=keys(); 133 for(int i=0;i<keys.length;i++) { 134 nodeMap.removeNamedItem(keys[i].getString()); 135 } 136 } 137 138 @Override 139 public Object get(Collection.Key key) throws ExpressionException { 140 Node rtn = nodeMap.getNamedItem(key.getString()); 141 if(rtn!=null) return rtn.getNodeValue(); 142 143 Collection.Key[] keys=keys(); 144 for(int i=0;i<keys.length;i++) { 145 if(key.equalsIgnoreCase(keys[i])) 146 return nodeMap.getNamedItem(keys[i].getString()).getNodeValue(); 147 } 148 throw new ExpressionException("No Attribute "+key.getString()+" defined for tag","attributes are ["+ListUtil.arrayToList(keys,", ")+"]"); 149 } 150 151 @Override 152 public Object get(Collection.Key key, Object defaultValue) { 153 try { 154 return get(key); 155 } catch (PageException e) { 156 return defaultValue; 157 } 158 } 159 160 @Override 161 public Object set(Collection.Key key, Object value) throws PageException { 162 if(owner==null) return value; 163 164 try { 165 Attr attr=owner.createAttribute(toName(key.getString())); 166 attr.setValue(Caster.toString(value)); 167 nodeMap.setNamedItem(attr); 168 169 } 170 catch(DOMException de) { 171 throw new XMLException(de); 172 } 173 174 175 176 177 return value; 178 } 179 180 private String toName(String name) { 181 return toName(name,name); 182 } 183 private String toName(String name, String defaultValue) { 184 if(caseSensitive) return name; 185 186 Node n = nodeMap.getNamedItem(name); 187 if(n!=null) return n.getNodeName(); 188 189 int len = nodeMap.getLength(); 190 String nn; 191 for(int i=0;i<len;i++) { 192 nn=nodeMap.item(i).getNodeName(); 193 if(name.equalsIgnoreCase(nn)) return nn; 194 } 195 return defaultValue; 196 } 197 198 @Override 199 public Object setEL(Collection.Key key, Object value) { 200 if(owner==null) return value; 201 try { 202 Attr attr=owner.createAttribute(toName(key.getString())); 203 attr.setValue(Caster.toString(value)); 204 nodeMap.setNamedItem(attr); 205 } 206 catch(Exception e) { 207 return null; 208 } 209 return value; 210 } 211 212 @Override 213 public Iterator<Collection.Key> keyIterator() { 214 return new KeyIterator(keys()); 215 } 216 217 @Override 218 public Iterator<String> keysAsStringIterator() { 219 return new StringIterator(keys()); 220 } 221 222 @Override 223 public Iterator<Entry<Key, Object>> entryIterator() { 224 return new EntryIterator(this,keys()); 225 } 226 227 @Override 228 public Iterator<Object> valueIterator() { 229 return new ValueIterator(this,keys()); 230 } 231 232 @Override 233 public int getLength() { 234 return nodeMap.getLength(); 235 } 236 237 @Override 238 public Node item(int index) { 239 return nodeMap.item(index); 240 } 241 242 @Override 243 public Node getNamedItem(String name) { 244 return nodeMap.getNamedItem(name); 245 } 246 247 @Override 248 public Node removeNamedItem(String name) throws DOMException { 249 return nodeMap.removeNamedItem(name); 250 } 251 252 @Override 253 public Node setNamedItem(Node arg) throws DOMException { 254 return nodeMap.setNamedItem(arg); 255 } 256 257 @Override 258 public Node setNamedItemNS(Node arg) throws DOMException { 259 return nodeMap.setNamedItemNS(arg); 260 } 261 262 @Override 263 public Node getNamedItemNS(String namespaceURI, String localName) { 264 return nodeMap.getNamedItemNS(namespaceURI,localName); 265 } 266 267 @Override 268 public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException { 269 return nodeMap.removeNamedItemNS(namespaceURI, localName); 270 } 271 272 @Override 273 public Collection duplicate(boolean deepCopy) { 274 return new XMLAttributes(parent.cloneNode(deepCopy),caseSensitive); 275 } 276 277 278 /** 279 * @return returns named Node map 280 */ 281 public NamedNodeMap toNamedNodeMap() { 282 return nodeMap; 283 } 284 285 @Override 286 public boolean containsKey(Collection.Key key) { 287 return get(key,null)!=null; 288 } 289 290 @Override 291 public String castToString() throws ExpressionException { 292 throw new ExpressionException("Can't cast XML NamedNodeMap to String"); 293 } 294 295 @Override 296 public String castToString(String defaultValue) { 297 return defaultValue; 298 } 299 300 @Override 301 public boolean castToBooleanValue() throws ExpressionException { 302 throw new ExpressionException("Can't cast XML NamedNodeMap to a boolean value"); 303 } 304 305 @Override 306 public Boolean castToBoolean(Boolean defaultValue) { 307 return defaultValue; 308 } 309 310 311 @Override 312 public double castToDoubleValue() throws ExpressionException { 313 throw new ExpressionException("Can't cast XML NamedNodeMap to a number value"); 314 } 315 316 @Override 317 public double castToDoubleValue(double defaultValue) { 318 return defaultValue; 319 } 320 321 322 @Override 323 public DateTime castToDateTime() throws ExpressionException { 324 throw new ExpressionException("Can't cast XML NamedNodeMap to a date value"); 325 } 326 327 @Override 328 public DateTime castToDateTime(DateTime defaultValue) { 329 return defaultValue; 330 } 331 332 @Override 333 public int compareTo(boolean b) throws ExpressionException { 334 throw new ExpressionException("can't compare XML NamedNodeMap with a boolean value"); 335 } 336 337 @Override 338 public int compareTo(DateTime dt) throws PageException { 339 throw new ExpressionException("can't compare XML NamedNodeMap with a DateTime Object"); 340 } 341 342 @Override 343 public int compareTo(double d) throws PageException { 344 throw new ExpressionException("can't compare XML NamedNodeMap with a numeric value"); 345 } 346 347 @Override 348 public int compareTo(String str) throws PageException { 349 throw new ExpressionException("can't compare XML NamedNodeMap with a String"); 350 } 351 }