package railo.runtime.text.xml; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.xalan.processor.TransformerFactoryImpl; import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl; import org.ccil.cowan.tagsoup.Parser; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.CharacterData; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; import railo.commons.io.IOUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.StringUtil; import railo.runtime.PageContext; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.exp.XMLException; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.text.xml.struct.XMLMultiElementStruct; import railo.runtime.text.xml.struct.XMLStruct; import railo.runtime.text.xml.struct.XMLStructFactory; import railo.runtime.type.Array; import railo.runtime.type.ArrayImpl; import railo.runtime.type.Collection; import railo.runtime.type.Collection.Key; import railo.runtime.type.KeyImpl; import railo.runtime.type.Struct; /** * */ public final class XMLUtil { public static final Collection.Key XMLCOMMENT = KeyImpl.intern("xmlcomment"); public static final Collection.Key XMLTEXT = KeyImpl.intern("xmltext"); public static final Collection.Key XMLCDATA = KeyImpl.intern("xmlcdata"); public static final Collection.Key XMLCHILDREN = KeyImpl.intern("xmlchildren"); public static final Collection.Key XMLNODES = KeyImpl.intern("xmlnodes"); public static final Collection.Key XMLNSURI = KeyImpl.intern("xmlnsuri"); public static final Collection.Key XMLNSPREFIX = KeyImpl.intern("xmlnsprefix"); public static final Collection.Key XMLROOT = KeyImpl.intern("xmlroot"); public static final Collection.Key XMLPARENT = KeyImpl.intern("xmlparent"); public static final Collection.Key XMLNAME = KeyImpl.intern("xmlname"); public static final Collection.Key XMLTYPE = KeyImpl.intern("xmltype"); public static final Collection.Key XMLVALUE = KeyImpl.intern("xmlvalue"); public static final Collection.Key XMLATTRIBUTES = KeyImpl.intern("xmlattributes"); /* private static final Collection.Key = KeyImpl.getInstance(); private static final Collection.Key = KeyImpl.getInstance(); private static final Collection.Key = KeyImpl.getInstance(); private static final Collection.Key = KeyImpl.getInstance(); private static final Collection.Key = KeyImpl.getInstance(); private static final Collection.Key = KeyImpl.getInstance(); */ //static DOMParser parser = new DOMParser(); private static DocumentBuilder docBuilder; //private static DocumentBuilderFactory factory; private static TransformerFactory transformerFactory; public static String unescapeXMLString(String str) { StringBuffer rtn=new StringBuffer(); int posStart=-1; int posFinish=-1; while((posStart=str.indexOf('&',posStart))!=-1) { int last=posFinish+1; posFinish=str.indexOf(';',posStart); if(posFinish==-1)break; rtn.append(str.substring(last,posStart)); if(posStart+1<posFinish) { rtn.append(unescapeXMLEntity(str.substring(posStart+1,posFinish))); } else { rtn.append("&;"); } posStart=posFinish+1; } rtn.append(str.substring(posFinish+1)); return rtn.toString(); } public static String unescapeXMLString2(String str) { StringBuffer sb=new StringBuffer(); int index,last=0,indexSemi; while((index=str.indexOf('&',last))!=-1) { sb.append(str.substring(last,index)); indexSemi=str.indexOf(';',index+1); if(indexSemi==-1) { sb.append('&'); last=index+1; } else if(index+1==indexSemi) { sb.append("&;"); last=index+2; } else { sb.append(unescapeXMLEntity(str.substring(index+1,indexSemi))); last=indexSemi+1; } } sb.append(str.substring(last)); return sb.toString(); } private static String unescapeXMLEntity(String str) { if("lt".equals(str)) return "<"; if("gt".equals(str)) return ">"; if("amp".equals(str)) return "&"; if("apos".equals(str)) return "'"; if("quot".equals(str)) return "\""; return "&"+str+";"; } public static String escapeXMLString(String xmlStr) { char c; StringBuffer sb=new StringBuffer(); int len=xmlStr.length(); for(int i=0;i<len;i++) { c=xmlStr.charAt(i); if(c=='<') sb.append("<"); else if(c=='>') sb.append(">"); else if(c=='&') sb.append("&"); //else if(c=='\'') sb.append("&"); else if(c=='"') sb.append("""); //else if(c>127) sb.append("&#"+((int)c)+";"); else sb.append(c); } return sb.toString(); } /** * @return returns a singelton TransformerFactory */ public static TransformerFactory getTransformerFactory() { // Saxon //if(transformerFactory==null)transformerFactory=new com.icl.saxon.TransformerFactoryImpl(); // Xalan if(transformerFactory==null)transformerFactory=new TransformerFactoryImpl(); // Trax //if(transformerFactory==null)transformerFactory=new com.jclark.xsl.trax.TransformerFactoryImpl(); // Trax //if(transformerFactory==null)transformerFactory=new jd.xml.xslt.trax.TransformerFactoryImpl(); // Caucho //if(transformerFactory==null)transformerFactory=new Xsl(); // xsltc //if(transformerFactory==null)transformerFactory=new org.apache.xalan.xsltc.trax.TransformerFactoryImpl(); return transformerFactory; } /** * parse XML/HTML String to a XML DOM representation * @param xml XML InputSource * @param isHtml is a HTML or XML Object * @return parsed Document * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ public static final Document parse(InputSource xml,InputSource validator, boolean isHtml) throws SAXException, IOException { if(!isHtml) { // try to load org.apache.xerces.jaxp.DocumentBuilderFactoryImpl, oracle impl sucks DocumentBuilderFactory factory = null; try{ factory = new DocumentBuilderFactoryImpl(); } catch(Throwable t) { factory = DocumentBuilderFactory.newInstance(); } //print.o(factory); if(validator==null) { XMLUtil.setAttributeEL(factory,XMLConstants.NON_VALIDATING_DTD_EXTERNAL, Boolean.FALSE); XMLUtil.setAttributeEL(factory,XMLConstants.NON_VALIDATING_DTD_GRAMMAR, Boolean.FALSE); } else { XMLUtil.setAttributeEL(factory,XMLConstants.VALIDATION_SCHEMA, Boolean.TRUE); XMLUtil.setAttributeEL(factory,XMLConstants.VALIDATION_SCHEMA_FULL_CHECKING, Boolean.TRUE); } factory.setNamespaceAware(true); factory.setValidating(validator!=null); try { DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(new XMLEntityResolverDefaultHandler(validator)); builder.setErrorHandler(new ThrowingErrorHandler(true,true,false)); return builder.parse(xml); } catch (ParserConfigurationException e) { throw new SAXException(e); } /*DOMParser parser = new DOMParser(); print.out("parse"); parser.setEntityResolver(new XMLEntityResolverDefaultHandler(validator)); parser.parse(xml); return parser.getDocument();*/ } XMLReader reader = new Parser(); reader.setFeature(Parser.namespacesFeature, true); reader.setFeature(Parser.namespacePrefixesFeature, true); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMResult result = new DOMResult(); transformer.transform(new SAXSource(reader, xml), result); return XMLUtil.getDocument(result.getNode()); } catch (Exception e) { throw new SAXException(e); } } private static void setAttributeEL(DocumentBuilderFactory factory,String name, Object value) { try{ factory.setAttribute(name, value); } catch(Throwable t){ //SystemOut.printDate("attribute ["+name+"] is not allowed for ["+factory.getClass().getName()+"]"); } } /** * sets a node to a node (Expression Less) * @param node * @param key * @param value * @return Object set */ public static Object setPropertyEL(Node node, Collection.Key key, Object value) { try { return setProperty(node,key,value); } catch (PageException e) { return null; } } public static Object setProperty(Node node, Collection.Key key, Object value,boolean caseSensitive, Object defaultValue) { try { return setProperty(node,key,value,caseSensitive); } catch (PageException e) { return defaultValue; } } /** * sets a node to a node * @param node * @param key * @param value * @return Object set * @throws PageException */ public static Object setProperty(Node node, Collection.Key k, Object value) throws PageException { return setProperty(node, k, value, isCaseSensitve(node)); } public static Object setProperty(Node node, Collection.Key k, Object value,boolean caseSensitive) throws PageException { Document doc=(node instanceof Document)?(Document)node:node.getOwnerDocument(); // Comment if(k.equals(XMLCOMMENT)) { removeChildren(XMLCaster.toRawNode(node),Node.COMMENT_NODE,false); node.appendChild(XMLCaster.toRawNode(XMLCaster.toComment(doc,value))); } // NS URI else if(k.equals(XMLNSURI)) { // TODO impl throw new ExpressionException("XML NS URI can't be set","not implemented"); } // Prefix else if(k.equals(XMLNSPREFIX)) { // TODO impl throw new ExpressionException("XML NS Prefix can't be set","not implemented"); //node.setPrefix(Caster.toString(value)); } // Root else if(k.equals(XMLROOT)) { doc.appendChild(XMLCaster.toNode(doc,value,false)); } // Parent else if(k.equals(XMLPARENT)) { Node parent = getParentNode(node,caseSensitive); Key name = KeyImpl.init(parent.getNodeName()); parent = getParentNode(parent,caseSensitive); if(parent==null) throw new ExpressionException("there is no parent element, you are already on the root element"); return setProperty(parent, name, value, caseSensitive); } // Name else if(k.equals(XMLNAME)) { throw new XMLException("You can't assign a new value for the property [xmlname]"); } // Type else if(k.equals(XMLTYPE)) { throw new XMLException("You can't change type of a xml node [xmltype]"); } // value else if(k.equals(XMLVALUE)) { node.setNodeValue(Caster.toString(value)); } // Attributes else if(k.equals(XMLATTRIBUTES)) { Element parent=XMLCaster.toElement(doc,node); Attr[] attres=XMLCaster.toAttrArray(doc,value); //print.ln("=>"+value); for(int i=0;i<attres.length;i++) { if(attres[i]!=null) { parent.setAttributeNode(attres[i]); //print.ln(attres[i].getName()+"=="+attres[i].getValue()); } } } // Text else if(k.equals(XMLTEXT)) { removeChildCharacterData(XMLCaster.toRawNode(node),false); node.appendChild(XMLCaster.toRawNode(XMLCaster.toText(doc,value))); } // CData else if(k.equals(XMLCDATA)) { removeChildCharacterData(XMLCaster.toRawNode(node),false); node.appendChild(XMLCaster.toRawNode(XMLCaster.toCDATASection(doc,value))); } // Children else if(k.equals(XMLCHILDREN) || k.equals(XMLNODES)) { Node[] nodes=XMLCaster.toNodeArray(doc,value); removeChildren(XMLCaster.toRawNode(node),Node.ELEMENT_NODE,false); for(int i=0;i<nodes.length;i++) { if(nodes[i]==node) throw new XMLException("can't assign a XML Node to himself"); if(nodes[i]!=null)node.appendChild(XMLCaster.toRawNode(nodes[i])); } } else { boolean isIndex=false; Node child = XMLCaster.toNode(doc,value,false); if(!k.getString().equalsIgnoreCase(child.getNodeName()) && !(isIndex=Decision.isInteger(k))) { throw new XMLException("if you assign a XML Element to a XMLStruct , assignment property must have same name like XML Node Name", "Property Name is "+k.getString()+" and XML Element Name is "+child.getNodeName()); } Node n; // by index if(isIndex) { NodeList list = XMLUtil.getChildNodes(node.getParentNode(), Node.ELEMENT_NODE,true,node.getNodeName()); int len = list.getLength(); int index=Caster.toIntValue(k); if(index>len || index<1){ String detail=len>1? "your index is "+index+", but there are only "+len+" child elements": "your index is "+index+", but there is only "+len+" child element"; throw new XMLException("index is out of range", detail); } n=list.item(index-1); XMLUtil.replaceChild(child, n); return value; } NodeList list = XMLUtil.getChildNodes(node, Node.ELEMENT_NODE); int len = list.getLength(); // by name for(int i=0;i<len;i++) { n=list.item(i); if(nameEqual(n, k.getString(), caseSensitive)) { XMLUtil.replaceChild(child, n); return value; } } node.appendChild(XMLCaster.toRawNode(child)); } return value; } public static void replaceChild(Node newChild, Node oldChild) { Node nc = XMLCaster.toRawNode(newChild); Node oc = XMLCaster.toRawNode(oldChild); Node p = oc.getParentNode(); if(nc!=oc)p.replaceChild(nc, oc); } public static Object getProperty(Node node, Collection.Key key, Object defaultValue) { return getProperty(node, key,isCaseSensitve(node),defaultValue); } /** * returns a property from a XMl Node (Expression Less) * @param node * @param key * @param caseSensitive * @return Object matching key */ public static Object getProperty(Node node, Collection.Key k,boolean caseSensitive, Object defaultValue) { try { return getProperty(node, k,caseSensitive); } catch (SAXException e) { return defaultValue; } } public static Object getProperty(Node node, Collection.Key key) throws SAXException { return getProperty(node, key,isCaseSensitve(node)); } /** * returns a property from a XMl Node * @param node * @param key * @param caseSensitive * @return Object matching key * @throws SAXException */ public static Object getProperty(Node node, Collection.Key k,boolean caseSensitive) throws SAXException { //String lcKey=StringUtil.toLowerCase(key); if(k.getLowerString().startsWith("xml")) { // Comment if(k.equals(XMLCOMMENT)) { StringBuffer sb=new StringBuffer(); NodeList list = node.getChildNodes(); int len=list.getLength(); for(int i=0;i<len;i++) { Node n=list.item(i); if(n instanceof Comment) { sb.append(((Comment)n).getData()); } } return sb.toString(); } // NS URI if(k.equals(XMLNSURI)) { undefinedInRoot(k,node); return param(node.getNamespaceURI(),""); } // Prefix if(k.equals(XMLNSPREFIX)) { undefinedInRoot(k,node); return param(node.getPrefix(),""); } // Root else if(k.equals(XMLROOT)) { Element re = getRootElement(node,caseSensitive); if(re==null) throw new SAXException("Attribute ["+k.getString()+"] not found in XML, XML is empty"); return param(re,""); } // Parent else if(k.equals(XMLPARENT)) { Node parent = getParentNode(node,caseSensitive); if(parent==null) { if(node.getNodeType()==Node.DOCUMENT_NODE) throw new SAXException("Attribute ["+k.getString()+"] not found in XML, there is no parent element, you are already at the root element"); throw new SAXException("Attribute ["+k.getString()+"] not found in XML, there is no parent element"); } return parent; } // Name else if(k.equals(XMLNAME)) { return node.getNodeName(); } // Value else if(k.equals(XMLVALUE)) { return StringUtil.toStringEmptyIfNull(node.getNodeValue()); } // type else if(k.equals(XMLTYPE)) { return getTypeAsString(node,true); } // Attributes else if(k.equals(XMLATTRIBUTES)) { NamedNodeMap attr = node.getAttributes(); if(attr==null)throw undefined(k,node); return new XMLAttributes(node,caseSensitive); } // Text else if(k.equals(XMLTEXT)) { undefinedInRoot(k,node); StringBuffer sb=new StringBuffer(); NodeList list = node.getChildNodes(); int len=list.getLength(); for(int i=0;i<len;i++) { Node n=list.item(i); if(n instanceof Text || n instanceof CDATASection) { sb.append(((CharacterData)n).getData()); } } return sb.toString(); } else if(k.equals(XMLCDATA)) { undefinedInRoot(k,node); StringBuffer sb=new StringBuffer(); NodeList list = node.getChildNodes(); int len=list.getLength(); for(int i=0;i<len;i++) { Node n=list.item(i); if(n instanceof Text || n instanceof CDATASection) { sb.append(((CharacterData)n).getData()); } } return sb.toString(); } // children else if(k.equals(XMLCHILDREN) || k.equals(XMLNODES)) { return new XMLNodeList(node,caseSensitive); } } if(node instanceof Document) { node=((Document)node).getDocumentElement(); if(node==null) throw new SAXException("Attribute ["+k.getString()+"] not found in XML, XML is empty"); //if((!caseSensitive && node.getNodeName().equalsIgnoreCase(k.getString())) || (caseSensitive && node.getNodeName().equals(k.getString()))) { if(nameEqual(node, k.getString(), caseSensitive)) { return XMLStructFactory.newInstance(node,caseSensitive); } } else if(node.getNodeType()==Node.ELEMENT_NODE && Decision.isInteger(k)){ int index=Caster.toIntValue(k,0); int count=0; Node parent = node.getParentNode(); String nodeName=node.getNodeName(); Element[] children = XMLUtil.getChildElementsAsArray(parent); for(int i=0;i<children.length;i++){ if(XMLUtil.nameEqual(children[i],nodeName,caseSensitive)) count++; if(count==index) return XMLCaster.toXMLStruct(children[i],caseSensitive); } String detail; if(count==0)detail="there are no Elements with this name"; else if(count==1)detail="there is only 1 Element with this name"; else detail="there are only "+count+" Elements with this name"; throw new SAXException("invalid index ["+k.getString()+"] for Element with name ["+node.getNodeName()+"], "+detail); } else { List<Node> children = XMLUtil.getChildNodesAsList(node,Node.ELEMENT_NODE,caseSensitive,null); int len=children.size(); Array array=null;//new ArrayImpl(); Element el; XMLStruct sct=null,first=null; for(int i=0;i<len;i++) { el=(Element) children.get(i);// XMLCaster.toXMLStruct(getChildNode(index),caseSensitive); if(XMLUtil.nameEqual(el,k.getString(),caseSensitive)) { sct = XMLCaster.toXMLStruct(el,caseSensitive); if(array!=null) { array.appendEL(sct); } else if(first!=null) { array=new ArrayImpl(); array.appendEL(first); array.appendEL(sct); } else { first=sct; } } } if(array!=null) { try { return new XMLMultiElementStruct(array,false); } catch (PageException e) {} } if(first!=null) return first; } throw new SAXException("Attribute ["+k.getString()+"] not found"); } private static SAXException undefined(Key key, Node node) { if(node.getNodeType()==Node.DOCUMENT_NODE) return new SAXException("you cannot address ["+key+"] on the Document Object, to address ["+key+"] from the root Node use [{variable-name}.xmlRoot."+key+"]"); return new SAXException(key+" is undefined"); } private static void undefinedInRoot(Key key, Node node) throws SAXException { if(node.getNodeType()==Node.DOCUMENT_NODE) throw undefined(key, node); } /** * check if given name is equal to name of the element (with and without namespace) * @param node * @param k * @param caseSensitive * @return */ public static boolean nameEqual(Node node, String name, boolean caseSensitive) { if(name==null) return false; if(caseSensitive){ return name.equals(node.getNodeName()) || name.equals(node.getLocalName()); } return name.equalsIgnoreCase(node.getNodeName()) || name.equalsIgnoreCase(node.getLocalName()); } public static boolean isCaseSensitve(Node node) { if(node instanceof XMLStruct) return ((XMLStruct)node).isCaseSensitive(); return true; } /** * removes child from a node * @param node * @param key * @param caseSensitive * @return removed property */ public static Object removeProperty(Node node, Collection.Key k,boolean caseSensitive) { //String lcKeyx=k.getLowerString(); if(k.getLowerString().startsWith("xml")) { // Comment if(k.equals(XMLCOMMENT)) { StringBuffer sb=new StringBuffer(); NodeList list = node.getChildNodes(); int len=list.getLength(); for(int i=0;i<len;i++) { Node n=list.item(i); if(n instanceof Comment) { sb.append(((Comment)n).getData()); node.removeChild(XMLCaster.toRawNode(n)); } } return sb.toString(); } // Text else if(k.equals(XMLTEXT)) { StringBuffer sb=new StringBuffer(); NodeList list = node.getChildNodes(); int len=list.getLength(); for(int i=0;i<len;i++) { Node n=list.item(i); if(n instanceof Text || n instanceof CDATASection) { sb.append(((CharacterData)n).getData()); node.removeChild(XMLCaster.toRawNode(n)); } } return sb.toString(); } // children else if(k.equals(XMLCHILDREN) || k.equals(XMLNODES)) { NodeList list=node.getChildNodes(); for(int i=list.getLength()-1;i>=0;i--) { node.removeChild(XMLCaster.toRawNode(list.item(i))); } return list; } } NodeList nodes = node.getChildNodes(); Array array=new ArrayImpl(); for(int i=nodes.getLength()-1;i>=0;i--) { Object o=nodes.item(i); if(o instanceof Element) { Element el=(Element) o; if(nameEqual(el, k.getString(), caseSensitive)) { array.appendEL(XMLCaster.toXMLStruct(el,caseSensitive)); node.removeChild(XMLCaster.toRawNode(el)); } } } if(array.size()>0) { try { return new XMLMultiElementStruct(array,false); } catch (PageException e) {} } return null; } private static Object param(Object o1, Object o2) { if(o1==null)return o2; return o1; } /** * return the root Element from a node * @param node node to get root element from * @param caseSensitive * @return Root Element */ public static Element getRootElement(Node node, boolean caseSensitive) { Document doc=null; if(node instanceof Document) doc=(Document) node; else doc=node.getOwnerDocument(); Element el = doc.getDocumentElement(); if(el==null) return null; return (Element)XMLStructFactory.newInstance(el,caseSensitive); } public static Node getParentNode(Node node, boolean caseSensitive) { Node parent = node.getParentNode(); if(parent==null) return null; return XMLStructFactory.newInstance(parent,caseSensitive); } /** * returns a new Empty XMl Document * @return new Document * @throws ParserConfigurationException * @throws FactoryConfigurationError */ public static Document newDocument() throws ParserConfigurationException, FactoryConfigurationError { if(docBuilder==null) { docBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder(); } return docBuilder.newDocument(); } /** * return the Owner Document of a Node List * @param nodeList * @return XML Document * @throws XMLException */ public static Document getDocument(NodeList nodeList) throws XMLException { if(nodeList instanceof Document) return (Document)nodeList; int len=nodeList.getLength(); for(int i=0;i<len;i++) { Node node=nodeList.item(i); if(node!=null) return node.getOwnerDocument(); } throw new XMLException("can't get Document from NodeList, in NoteList are no Nodes"); } /** * return the Owner Document of a Node * @param node * @return XML Document */ public static Document getDocument(Node node) { if(node instanceof Document) return (Document)node; return node.getOwnerDocument(); } /** * removes child elements from a specific type * @param node node to remove elements from * @param type Type Definition to remove (Constant value from class Node) * @param deep remove also in sub nodes */ private synchronized static void removeChildren(Node node, short type, boolean deep) { NodeList list = node.getChildNodes(); for(int i=list.getLength();i>=0;i--) { Node n=list.item(i); if(n ==null )continue; if(n.getNodeType()==type)node.removeChild(XMLCaster.toRawNode(n)); else if(deep)removeChildren(n,type,deep); } } /** * remove children from type CharacterData from a node, this includes Text,Comment and CDataSection nodes * @param node * @param type * @param deep */ private synchronized static void removeChildCharacterData(Node node, boolean deep) { NodeList list = node.getChildNodes(); for(int i=list.getLength();i>=0;i--) { Node n=list.item(i); if(n ==null )continue; if(n instanceof CharacterData)node.removeChild(XMLCaster.toRawNode(n)); else if(deep)removeChildCharacterData(n,deep); } } /** * return all Children of a node by a defined type as Node List * @param node node to get children from * @param type type of returned node * @param filter * @param caseSensitive * @return all matching child node */ public synchronized static ArrayNodeList getChildNodes(Node node, short type) { return getChildNodes(node, type, false, null); } public synchronized static int childNodesLength(Node node, short type, boolean caseSensitive, String filter) { NodeList nodes=node.getChildNodes(); int len=nodes.getLength(); Node n; int count=0; for(int i=0;i<len;i++) { try { n=nodes.item(i); if(n!=null && n.getNodeType()==type){ if(filter==null || (caseSensitive?filter.equals(n.getLocalName()):filter.equalsIgnoreCase(n.getLocalName()))) count++; } } catch(Throwable t){} } return count; } public synchronized static ArrayNodeList getChildNodes(Node node, short type, boolean caseSensitive, String filter) { ArrayNodeList rtn=new ArrayNodeList(); NodeList nodes=node.getChildNodes(); int len=nodes.getLength(); Node n; for(int i=0;i<len;i++) { try { n=nodes.item(i); if(n!=null && n.getNodeType()==type){ if(filter==null || (caseSensitive?filter.equals(n.getLocalName()):filter.equalsIgnoreCase(n.getLocalName()))) rtn.add(n); } } catch(Throwable t){} } return rtn; } public synchronized static List<Node> getChildNodesAsList(Node node, short type, boolean caseSensitive, String filter) { List<Node> rtn=new ArrayList<Node>(); NodeList nodes=node.getChildNodes(); int len=nodes.getLength(); Node n; for(int i=0;i<len;i++) { try { n=nodes.item(i); if(n!=null && n.getNodeType()==type){ if(filter==null || (caseSensitive?filter.equals(n.getLocalName()):filter.equalsIgnoreCase(n.getLocalName()))) rtn.add(n); } } catch(Throwable t){} } return rtn; } public synchronized static Node getChildNode(Node node, short type, boolean caseSensitive, String filter, int index) { NodeList nodes=node.getChildNodes(); int len=nodes.getLength(); Node n; int count=0; for(int i=0;i<len;i++) { try { n=nodes.item(i); if(n!=null && n.getNodeType()==type){ if(filter==null || (caseSensitive?filter.equals(n.getLocalName()):filter.equalsIgnoreCase(n.getLocalName()))) { if(count==index) return n; count++; } } } catch(Throwable t){} } return null; } /** * return all Children of a node by a defined type as Node Array * @param node node to get children from * @param type type of returned node * @param filter * @param caseSensitive * @return all matching child node */ public static Node[] getChildNodesAsArray(Node node, short type) { ArrayNodeList nodeList=getChildNodes(node, type); return nodeList.toArray(new Node[nodeList.getLength()]); } public static Node[] getChildNodesAsArray(Node node, short type, boolean caseSensitive, String filter) { ArrayNodeList nodeList=getChildNodes(node, type,caseSensitive,filter); return nodeList.toArray(new Node[nodeList.getLength()]); } /** * return all Element Children of a node * @param node node to get children from * @return all matching child node */ public static Element[] getChildElementsAsArray(Node node) { ArrayNodeList nodeList=getChildNodes(node,Node.ELEMENT_NODE); return nodeList.toArray(new Element[nodeList.getLength()]); } /** * transform a XML Object to a other format, with help of a XSL Stylesheet * @param xml xml to convert * @param xsl xsl used to convert * @return resulting string * @throws TransformerException * @throws SAXException * @throws IOException */ public static String transform(InputSource xml, InputSource xsl) throws TransformerException, SAXException, IOException { return transform( parse( xml, null , false ), xsl, null ); } /** * transform a XML Object to a other format, with help of a XSL Stylesheet * @param xml xml to convert * @param xsl xsl used to convert * @param parameters parameters used to convert * @return resulting string * @throws TransformerException * @throws SAXException * @throws IOException */ public static String transform(InputSource xml, InputSource xsl, Map parameters) throws TransformerException, SAXException, IOException { return transform( parse( xml, null , false ), xsl, parameters ); } /** * transform a XML Document to a other format, with help of a XSL Stylesheet * @param xml xml to convert * @param xsl xsl used to convert * @return resulting string * @throws TransformerException * @throws SAXException * @throws IOException */ public static String transform( Document doc, InputSource xsl ) throws TransformerException { return transform( doc, xsl, null ); } /** * transform a XML Document to a other format, with help of a XSL Stylesheet * @param xml xml to convert * @param xsl xsl used to convert * @param parameters parameters used to convert * @return resulting string * @throws TransformerException * @throws SAXException * @throws IOException */ public static String transform(Document doc, InputSource xsl, Map parameters) throws TransformerException { StringWriter sw = new StringWriter(); TransformerFactory factory = XMLUtil.getTransformerFactory(); factory.setErrorListener(SimpleErrorListener.THROW_FATAL); Transformer transformer = factory.newTransformer(new StreamSource(xsl.getCharacterStream())); if (parameters != null) { Iterator it = parameters.entrySet().iterator(); while ( it.hasNext() ) { Map.Entry e = (Map.Entry) it.next(); transformer.setParameter(e.getKey().toString(), e.getValue()); } } transformer.transform(new DOMSource(doc), new StreamResult(sw)); return sw.toString(); } /** * returns the Node Type As String * @param node * @param cftype * @return */ public static String getTypeAsString(Node node, boolean cftype) { String suffix=cftype?"":"_NODE"; switch(node.getNodeType()) { case Node.ATTRIBUTE_NODE: return "ATTRIBUTE"+suffix; case Node.CDATA_SECTION_NODE: return "CDATA_SECTION"+suffix; case Node.COMMENT_NODE: return "COMMENT"+suffix; case Node.DOCUMENT_FRAGMENT_NODE: return "DOCUMENT_FRAGMENT"+suffix; case Node.DOCUMENT_NODE: return "DOCUMENT"+suffix; case Node.DOCUMENT_TYPE_NODE: return "DOCUMENT_TYPE"+suffix; case Node.ELEMENT_NODE: return "ELEMENT"+suffix; case Node.ENTITY_NODE: return "ENTITY"+suffix; case Node.ENTITY_REFERENCE_NODE: return "ENTITY_REFERENCE"+suffix; case Node.NOTATION_NODE: return "NOTATION"+suffix; case Node.PROCESSING_INSTRUCTION_NODE: return "PROCESSING_INSTRUCTION"+suffix; case Node.TEXT_NODE: return "TEXT"+suffix; default: return "UNKNOW"+suffix; } } public synchronized static Element getChildWithName(String name, Element el) { Element[] children = XMLUtil.getChildElementsAsArray(el); for(int i=0;i<children.length;i++) { if(name.equalsIgnoreCase(children[i].getNodeName())) return children[i]; } return null; } public static InputSource toInputSource(Resource res) throws IOException { String str = IOUtil.toString((res), (Charset)null); return new InputSource(new StringReader(str)); } public static InputSource toInputSource(PageContext pc, Object value) throws IOException, ExpressionException { if(value instanceof InputSource) { return (InputSource) value; } if(value instanceof String) { return toInputSource(pc, (String)value); } if(value instanceof StringBuffer) { return toInputSource(pc, value.toString()); } if(value instanceof Resource) { String str = IOUtil.toString(((Resource)value), (Charset)null); return new InputSource(new StringReader(str)); } if(value instanceof File) { String str = IOUtil.toString(ResourceUtil.toResource(((File)value)),(Charset)null); return new InputSource(new StringReader(str)); } if(value instanceof InputStream) { InputStream is = (InputStream)value; try { String str = IOUtil.toString(is, (Charset)null); return new InputSource(new StringReader(str)); } finally { IOUtil.closeEL(is); } } if(value instanceof Reader) { Reader reader = (Reader)value; try { String str = IOUtil.toString(reader); return new InputSource(new StringReader(str)); } finally { IOUtil.closeEL(reader); } } if(value instanceof byte[]) { return new InputSource(new ByteArrayInputStream((byte[])value)); } throw new ExpressionException("cat cast object of type ["+Caster.toClassName(value)+"] to a Input for xml parser"); } public static InputSource toInputSource(PageContext pc, String xml) throws IOException, ExpressionException { return toInputSource(pc, xml,true); } public static InputSource toInputSource(PageContext pc, String xml, boolean canBePath) throws IOException, ExpressionException { // xml text xml=xml.trim(); if(!canBePath || xml.startsWith("<")) { return new InputSource(new StringReader(xml)); } // xml link pc=ThreadLocalPageContext.get(pc); Resource res = ResourceUtil.toResourceExisting(pc, xml); return toInputSource(pc, res); } public static Struct validate(InputSource xml, InputSource schema, String strSchema) throws XMLException { return new XMLValidator(schema,strSchema).validate(xml); } /** * adds a child at the first place * @param parent * @param child */ public static void prependChild(Element parent, Element child) { Node first = parent.getFirstChild(); if(first==null)parent.appendChild(child); else { parent.insertBefore(child, first); } } public static void setFirst(Node parent, Node node) { Node first = parent.getFirstChild(); if(first!=null) parent.insertBefore(node, first); else parent.appendChild(node); } public static XMLReader createXMLReader(String oprionalDefaultSaxParser) throws SAXException { try{ return XMLReaderFactory.createXMLReader(oprionalDefaultSaxParser); } catch(Throwable t){ return XMLReaderFactory.createXMLReader(); } } }