package railo.runtime.text.xml; import java.util.ArrayList; import java.util.Iterator; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import railo.runtime.PageContext; import railo.runtime.dump.DumpData; import railo.runtime.dump.DumpProperties; import railo.runtime.dump.DumpTable; import railo.runtime.dump.DumpUtil; import railo.runtime.dump.SimpleDumpData; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.exp.XMLException; import railo.runtime.op.Caster; import railo.runtime.type.Collection; import railo.runtime.type.KeyImpl; import railo.runtime.type.Struct; import railo.runtime.type.dt.DateTime; import railo.runtime.type.it.EntryIterator; import railo.runtime.type.it.KeyIterator; import railo.runtime.type.it.StringIterator; import railo.runtime.type.it.ValueIterator; import railo.runtime.type.util.ListUtil; import railo.runtime.type.util.StructSupport; /** * represent a Struct and a NamedNodeMap */ public final class XMLAttributes extends StructSupport implements Struct,NamedNodeMap { private final NamedNodeMap nodeMap; private final Document owner; private final Node parent; private final boolean caseSensitive; /** * constructor of the class (readonly) * @param nodeMap */ public XMLAttributes(Node parent, boolean caseSensitive) { this.owner=parent.getOwnerDocument(); this.parent=parent; this.nodeMap=parent.getAttributes(); this.caseSensitive=caseSensitive; } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { Collection.Key[] keys=keys(); maxlevel--; DumpTable table = new DumpTable("xml","#999966","#cccc99","#000000"); table.setTitle("Struct (XML Attributes)"); int maxkeys=dp.getMaxKeys(); int index=0; Collection.Key k; for(int i=0;i<keys.length;i++) { k=keys[i]; if(DumpUtil.keyValid(dp,maxlevel, k)){ if(maxkeys<=index++)break; table.appendRow(1,new SimpleDumpData(k.getString()),DumpUtil.toDumpData(get(k.getString(),null), pageContext,maxlevel,dp)); } } return table; } @Override public int size() { return nodeMap.getLength(); } @Override public Collection.Key[] keys() { int len=nodeMap.getLength(); ArrayList<Collection.Key> list =new ArrayList<Collection.Key>(); for(int i=0;i<len;i++) { Node item = nodeMap.item(i); if(item instanceof Attr) list.add(KeyImpl.init(((Attr)item).getName())); } return list.toArray(new Collection.Key[list.size()]); } @Override public Object remove(Collection.Key k) throws PageException { String key=k.getString(); Node rtn=null; if(!caseSensitive){ int len = nodeMap.getLength(); String nn; for(int i=len-1;i>=0;i--) { nn=nodeMap.item(i).getNodeName(); if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn); } } else rtn=nodeMap.removeNamedItem(toName(key)); if(rtn!=null) return rtn.getNodeValue(); throw new ExpressionException("can't remove element with name ["+key+"], element doesn't exist"); } @Override public Object removeEL(Collection.Key k) { String key=k.getString(); Node rtn=null; if(!caseSensitive){ int len = nodeMap.getLength(); String nn; for(int i=len-1;i>=0;i--) { nn=nodeMap.item(i).getNodeName(); if(key.equalsIgnoreCase(nn)) rtn=nodeMap.removeNamedItem(nn); } } else rtn=nodeMap.removeNamedItem(toName(key)); if(rtn!=null) return rtn.getNodeValue(); return null; } @Override public void clear() { Collection.Key[] keys=keys(); for(int i=0;i<keys.length;i++) { nodeMap.removeNamedItem(keys[i].getString()); } } @Override public Object get(Collection.Key key) throws ExpressionException { Node rtn = nodeMap.getNamedItem(key.getString()); if(rtn!=null) return rtn.getNodeValue(); Collection.Key[] keys=keys(); for(int i=0;i<keys.length;i++) { if(key.equalsIgnoreCase(keys[i])) return nodeMap.getNamedItem(keys[i].getString()).getNodeValue(); } throw new ExpressionException("No Attribute "+key.getString()+" defined for tag","attributes are ["+ListUtil.arrayToList(keys,", ")+"]"); } @Override public Object get(Collection.Key key, Object defaultValue) { try { return get(key); } catch (PageException e) { return defaultValue; } } @Override public Object set(Collection.Key key, Object value) throws PageException { if(owner==null) return value; try { Attr attr=owner.createAttribute(toName(key.getString())); attr.setValue(Caster.toString(value)); nodeMap.setNamedItem(attr); } catch(DOMException de) { throw new XMLException(de); } return value; } private String toName(String name) { return toName(name,name); } private String toName(String name, String defaultValue) { if(caseSensitive) return name; Node n = nodeMap.getNamedItem(name); if(n!=null) return n.getNodeName(); int len = nodeMap.getLength(); String nn; for(int i=0;i<len;i++) { nn=nodeMap.item(i).getNodeName(); if(name.equalsIgnoreCase(nn)) return nn; } return defaultValue; } @Override public Object setEL(Collection.Key key, Object value) { if(owner==null) return value; try { Attr attr=owner.createAttribute(toName(key.getString())); attr.setValue(Caster.toString(value)); nodeMap.setNamedItem(attr); } catch(Exception e) { return null; } return value; } @Override public Iterator<Collection.Key> keyIterator() { return new KeyIterator(keys()); } @Override public Iterator<String> keysAsStringIterator() { return new StringIterator(keys()); } @Override public Iterator<Entry<Key, Object>> entryIterator() { return new EntryIterator(this,keys()); } @Override public Iterator<Object> valueIterator() { return new ValueIterator(this,keys()); } @Override public int getLength() { return nodeMap.getLength(); } @Override public Node item(int index) { return nodeMap.item(index); } @Override public Node getNamedItem(String name) { return nodeMap.getNamedItem(name); } @Override public Node removeNamedItem(String name) throws DOMException { return nodeMap.removeNamedItem(name); } @Override public Node setNamedItem(Node arg) throws DOMException { return nodeMap.setNamedItem(arg); } @Override public Node setNamedItemNS(Node arg) throws DOMException { return nodeMap.setNamedItemNS(arg); } @Override public Node getNamedItemNS(String namespaceURI, String localName) { return nodeMap.getNamedItemNS(namespaceURI,localName); } @Override public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException { return nodeMap.removeNamedItemNS(namespaceURI, localName); } @Override public Collection duplicate(boolean deepCopy) { return new XMLAttributes(parent.cloneNode(deepCopy),caseSensitive); } /** * @return returns named Node map */ public NamedNodeMap toNamedNodeMap() { return nodeMap; } @Override public boolean containsKey(Collection.Key key) { return get(key,null)!=null; } @Override public String castToString() throws ExpressionException { throw new ExpressionException("Can't cast XML NamedNodeMap to String"); } @Override public String castToString(String defaultValue) { return defaultValue; } @Override public boolean castToBooleanValue() throws ExpressionException { throw new ExpressionException("Can't cast XML NamedNodeMap to a boolean value"); } @Override public Boolean castToBoolean(Boolean defaultValue) { return defaultValue; } @Override public double castToDoubleValue() throws ExpressionException { throw new ExpressionException("Can't cast XML NamedNodeMap to a number value"); } @Override public double castToDoubleValue(double defaultValue) { return defaultValue; } @Override public DateTime castToDateTime() throws ExpressionException { throw new ExpressionException("Can't cast XML NamedNodeMap to a date value"); } @Override public DateTime castToDateTime(DateTime defaultValue) { return defaultValue; } @Override public int compareTo(boolean b) throws ExpressionException { throw new ExpressionException("can't compare XML NamedNodeMap with a boolean value"); } @Override public int compareTo(DateTime dt) throws PageException { throw new ExpressionException("can't compare XML NamedNodeMap with a DateTime Object"); } @Override public int compareTo(double d) throws PageException { throw new ExpressionException("can't compare XML NamedNodeMap with a numeric value"); } @Override public int compareTo(String str) throws PageException { throw new ExpressionException("can't compare XML NamedNodeMap with a String"); } }