package railo.runtime.text.xml; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; 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.op.Caster; import railo.runtime.text.xml.struct.XMLObject; import railo.runtime.text.xml.struct.XMLStruct; import railo.runtime.type.Collection; import railo.runtime.type.KeyImpl; 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.util.ArraySupport; import railo.runtime.type.util.ArrayUtil; import railo.runtime.util.ArrayIterator; /** * */ public final class XMLNodeList extends ArraySupport implements NodeList, XMLObject{ private boolean caseSensitive; private Document doc; private Node parent; private String filter; /** * @param parent Parent Node * @param caseSensitive */ public XMLNodeList(Node parent, boolean caseSensitive) { this(parent,caseSensitive,null); } public XMLNodeList(Node parent, boolean caseSensitive, String filter) { if(parent instanceof XMLStruct) { XMLStruct xmlNode = ((XMLStruct)parent); this.parent=xmlNode.toNode(); this.caseSensitive=xmlNode.getCaseSensitive(); } else { this.parent=parent; this.caseSensitive=caseSensitive; } this.doc=this.parent.getOwnerDocument(); this.filter=filter; } @Override public int getLength() { return XMLUtil.childNodesLength(parent,Node.ELEMENT_NODE,caseSensitive,filter); } @Override public Node item(int index) { return XMLCaster.toXMLStruct(getChildNode(index),caseSensitive); } @Override public int size() { return getLength(); } @Override public Collection.Key[] keys() { Collection.Key[] keys=new Collection.Key[getLength()]; for(int i=1;i<=keys.length;i++) { keys[i-1]=KeyImpl.init(i+""); } return keys; } @Override public int[] intKeys() { int[] keys=new int[getLength()]; for(int i=1;i<=keys.length;i++) { keys[i-1]=i; } return keys; } public Object removeEL(Collection.Key key) { return removeEL(Caster.toIntValue(key.getString(),-1)); } @Override public Object remove(Collection.Key key) throws PageException { return removeE(Caster.toIntValue(key.getString())); } @Override public Object removeEL(int index) { int len=size(); if(index<1 || index>len) return null; try { return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive); } catch (Exception e) { return null; } } @Override public Object removeE(int index) throws PageException { int len=size(); if(index<1 || index>len) throw new ExpressionException("can't remove value form XML Node List at index "+index+ ", valid indexes goes from 1 to "+len); return XMLCaster.toXMLStruct(parent.removeChild(XMLCaster.toRawNode(item(index-1))),caseSensitive); } @Override public void clear() { Node[] nodes=getChildNodesAsArray(); for(int i=0;i<nodes.length;i++) { parent.removeChild(XMLCaster.toRawNode(nodes[i])); } } @Override public Object get(String key) throws ExpressionException { return getE(Caster.toIntValue(key)); } @Override public Object get(Collection.Key key) throws ExpressionException { return get(key.getString()); } @Override public Object getE(int key) throws ExpressionException { Object rtn= item(key-1); if(rtn==null) throw new ExpressionException("invalid index ["+key+"] for XML Node List , indexes goes from [0-"+size()+"]"); return rtn; } @Override public Object get(String key, Object defaultValue) { int index=Caster.toIntValue(key,Integer.MIN_VALUE); if(index==Integer.MIN_VALUE) return defaultValue; return get(index,defaultValue); } @Override public Object get(Collection.Key key, Object defaultValue) { return get(key.getString(),defaultValue); } @Override public Object get(int key, Object defaultValue) { Object rtn= item(key-1); if(rtn==null) return defaultValue; return rtn; } @Override public Object set(String key, Object value) throws PageException { return setE(Caster.toIntValue(key),value); } @Override public Object set(Collection.Key key, Object value) throws PageException { return set(key.getString(), value); } @Override public Object setE(int index, Object value) throws PageException { // check min Index if(index<1) throw new ExpressionException("invalid index ["+index+"] to set a child node, valid indexes start at 1"); Node[] nodes=getChildNodesAsArray(); // if index Greater len append if(index>nodes.length) return append(value); // remove all children clear(); // set all children before new Element for(int i=1;i<index;i++) { append(nodes[i-1]); } // set new Element append(XMLCaster.toNode(doc,value,true)); // set all after new Element for(int i=index;i<nodes.length;i++) { append(nodes[i]); } return value; } @Override public Object setEL(String key, Object value) { int index=Caster.toIntValue(key,Integer.MIN_VALUE); if(index==Integer.MIN_VALUE) return null; return setEL(index,value); } @Override public Object setEL(Collection.Key key, Object value) { return setEL(key.getString(), value); } @Override public Object setEL(int index, Object value) { try { return setE(index,value); } catch (PageException e) { return null; } } @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()); } public Iterator<Object> valueIterator() { Object[] values=new Object[getLength()]; for(int i=0;i<values.length;i++) { values[i]=item(i); } return new ArrayIterator(values); } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { maxlevel--; DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000"); table.setTitle("Array (XML Node List)"); int len=size(); for(int i=1;i<=len;i++) { table.appendRow(1,new SimpleDumpData(i),DumpUtil.toDumpData(item(i-1), pageContext,maxlevel,dp)); } return table; } @Override public Object append(Object o) throws PageException { return parent.appendChild(XMLCaster.toNode(doc,o,true)); } public Object appendEL(Object o) { try { return append(o); } catch (Exception e) { return null; } } @Override public Object clone() { return duplicate(true); } @Override public Collection duplicate(boolean deepCopy) { return new XMLNodeList(parent.cloneNode(deepCopy),caseSensitive); } @Override public int getDimension() { return 1; } @Override public boolean insert(int index, Object value) throws PageException { // check min Index if(index<1) throw new ExpressionException("invalid index ["+index+"] to insert a child node, valid indexes start at 1"); Node[] nodes=getChildNodesAsArray(); // if index Greater len append if(index>nodes.length) { append(value); return true; } // remove all children clear(); // set all children before new Element for(int i=1;i<index;i++) { append(nodes[i-1]); } // set new Element append(XMLCaster.toNode(doc,value,true)); // set all after new Element for(int i=index;i<=nodes.length;i++) { append(nodes[i-1]); } return true; } @Override public Object prepend(Object o) throws PageException { Node[] nodes=getChildNodesAsArray(); // remove all children clear(); // set new Element append(XMLCaster.toNode(doc,o,true)); // set all after new Element for(int i=0;i<nodes.length;i++) { append(nodes[i]); } return o; } @Override public void resize(int to) throws ExpressionException { if(to>size())throw new ExpressionException("can't resize a XML Node List Array with empty Elements"); } @Override public void sort(String sortType, String sortOrder) throws ExpressionException { throw new ExpressionException("can't sort a XML Node List Array","sorttype:"+sortType+";sortorder:"+sortOrder); } @Override public void sort(Comparator comp) throws ExpressionException { throw new ExpressionException("can't sort a XML Node List Array"); } @Override public Object[] toArray() { return getChildNodesAsArray(); } public ArrayList toArrayList() { Object[] arr=toArray(); ArrayList list=new ArrayList(); for(int i=0;i>arr.length;i++) { list.add(arr[i]); } return list; } /** * @return returns a output from the content as plain Text */ public String toPlain() { StringBuffer sb=new StringBuffer(); int length=size(); for(int i=1;i<=length;i++) { sb.append(i); sb.append(": "); sb.append(get(i,null)); sb.append("\n"); } return sb.toString(); } private NodeList getChildNodes() { return XMLUtil.getChildNodes(parent,Node.ELEMENT_NODE,caseSensitive,filter); } private Node getChildNode(int index) { return XMLUtil.getChildNode(parent,Node.ELEMENT_NODE,caseSensitive,filter,index); } private Node[] getChildNodesAsArray() { return XMLUtil.getChildNodesAsArray(parent,Node.ELEMENT_NODE,caseSensitive,filter); } @Override public boolean containsKey(String key) { return get(key,null)!=null; } @Override public boolean containsKey(Collection.Key key) { return get(key,null)!=null; } @Override public boolean containsKey(int key) { return get(key,null)!=null; } @Override public boolean getCaseSensitive() { return caseSensitive; } @Override public String castToString() throws ExpressionException { throw new ExpressionException("Can't cast XML NodeList to String"); } @Override public String castToString(String defaultValue) { return defaultValue; } @Override public boolean castToBooleanValue() throws ExpressionException { throw new ExpressionException("Can't cast XML NodeList 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 NodeList 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 NodeList to a Date"); } @Override public DateTime castToDateTime(DateTime defaultValue) { return defaultValue; } @Override public int compareTo(boolean b) throws ExpressionException { throw new ExpressionException("can't compare XML NodeList with a boolean value"); } @Override public int compareTo(DateTime dt) throws PageException { throw new ExpressionException("can't compare XML NodeList with a DateTime Object"); } @Override public int compareTo(double d) throws PageException { throw new ExpressionException("can't compare XML NodeList with a numeric value"); } @Override public int compareTo(String str) throws PageException { throw new ExpressionException("can't compare XML NodeList with a String"); } @Override public long sizeOf() { return ArrayUtil.sizeOf((List)this); } }