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;
020
021import java.io.IOException;
022import java.io.OutputStream;
023import java.io.StringReader;
024import java.io.StringWriter;
025import java.util.ArrayList;
026import java.util.Iterator;
027import java.util.List;
028import java.util.Map.Entry;
029
030import javax.xml.transform.OutputKeys;
031import javax.xml.transform.Result;
032import javax.xml.transform.Transformer;
033import javax.xml.transform.dom.DOMSource;
034import javax.xml.transform.stream.StreamResult;
035
036import lucee.commons.io.IOUtil;
037import lucee.commons.io.res.Resource;
038import lucee.commons.lang.ExceptionUtil;
039import lucee.commons.lang.HTMLEntities;
040import lucee.commons.lang.StringUtil;
041import lucee.runtime.PageContext;
042import lucee.runtime.dump.DumpData;
043import lucee.runtime.dump.DumpProperties;
044import lucee.runtime.dump.DumpTable;
045import lucee.runtime.dump.DumpUtil;
046import lucee.runtime.dump.SimpleDumpData;
047import lucee.runtime.exp.CasterException;
048import lucee.runtime.exp.ExpressionException;
049import lucee.runtime.exp.PageException;
050import lucee.runtime.exp.XMLException;
051import lucee.runtime.functions.decision.IsNumeric;
052import lucee.runtime.functions.list.ListLast;
053import lucee.runtime.op.Caster;
054import lucee.runtime.text.xml.struct.XMLStruct;
055import lucee.runtime.text.xml.struct.XMLStructFactory;
056import lucee.runtime.type.Collection;
057import lucee.runtime.type.Collection.Key;
058import lucee.runtime.type.Struct;
059
060import org.w3c.dom.Attr;
061import org.w3c.dom.CDATASection;
062import org.w3c.dom.CharacterData;
063import org.w3c.dom.Comment;
064import org.w3c.dom.Document;
065import org.w3c.dom.Element;
066import org.w3c.dom.NamedNodeMap;
067import org.w3c.dom.Node;
068import org.w3c.dom.NodeList;
069import org.w3c.dom.Text;
070import org.xml.sax.InputSource;
071
072/**
073 * Cast Objects to XML Objects of different types
074 */
075public final class XMLCaster {
076
077    
078    /**
079         * casts a value to a XML Text
080         * @param doc XML Document
081         * @param o Object to cast
082         * @return XML Text Object
083         * @throws PageException
084         */
085        public static Text toText(Document doc, Object o) throws PageException {
086                if(o instanceof Text) return (Text)o;
087                else if(o instanceof CharacterData) return doc.createTextNode(((CharacterData)o).getData());
088                return doc.createTextNode(Caster.toString(o));
089        }
090        
091        public static Text toCDATASection(Document doc, Object o) throws PageException {
092                if(o instanceof CDATASection) return (CDATASection)o;
093                else if(o instanceof CharacterData) return doc.createCDATASection(((CharacterData)o).getData());
094                return doc.createCDATASection(Caster.toString(o));
095        }
096        
097        /**
098         * casts a value to a XML Text Array
099         * @param doc XML Document
100         * @param o Object to cast
101         * @return XML Text Array
102         * @throws PageException
103         */
104        public static Text[] toTextArray(Document doc,Object o) throws PageException {
105        // Node[]
106                if(o instanceof Node[]) {
107                        Node[] nodes=(Node[])o;
108                        if(_isAllOfSameType(nodes,Node.TEXT_NODE))return (Text[])nodes; 
109                        
110                        Text[] textes=new Text[nodes.length];
111                        for(int i=0;i<nodes.length;i++) {
112                                textes[i]=toText(doc,nodes[i]);
113                        }
114                        return textes;
115                }
116        // Collection
117                else if(o instanceof Collection) {
118                        Collection coll=(Collection)o;
119                        Iterator<Object> it = coll.valueIterator();
120                        List<Text> textes=new ArrayList<Text>();
121                        while(it.hasNext()) {
122                                textes.add(toText(doc,it.next()));
123                        }
124                        return textes.toArray(new Text[textes.size()]);
125                }
126        // Node Map and List
127                Node[] nodes=_toNodeArray(doc,o);
128                if(nodes!=null) return toTextArray(doc,nodes);
129        // Single Text Node
130                try {
131                        return new Text[]{toText(doc,o)};
132                } catch (ExpressionException e) {
133                        throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Text Array");
134                }
135        }
136        
137        /**
138         * casts a value to a XML Attribute Object
139         * @param doc XML Document
140         * @param o Object to cast
141         * @return XML Comment Object
142         * @throws PageException
143         */
144        public static Attr toAttr(Document doc, Object o) throws PageException {
145                if(o instanceof Attr) return (Attr)o;
146                if(o instanceof Struct && ((Struct)o).size()==1) {
147                        Struct sct=(Struct)o;
148                        Entry<Key, Object> e = sct.entryIterator().next();
149                        Attr attr= doc.createAttribute(e.getKey().getString());
150                        attr.setValue(Caster.toString(e.getValue()));
151                        return attr;
152                }
153                
154                throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Attribute");
155        }
156
157        /**
158         * casts a value to a XML Attr Array
159         * @param doc XML Document
160         * @param o Object to cast
161         * @return XML Attr Array
162         * @throws PageException
163         */
164        public static Attr[] toAttrArray(Document doc,Object o) throws PageException {
165        // Node[]
166                if(o instanceof Node[]) {
167                        Node[] nodes=(Node[])o;
168                        if(_isAllOfSameType(nodes,Node.ATTRIBUTE_NODE))return (Attr[])nodes; 
169                        
170                        Attr[] attres=new Attr[nodes.length];
171                        for(int i=0;i<nodes.length;i++) {
172                                attres[i]=toAttr(doc,nodes[i]);
173                        }
174                        return attres;
175                }
176        // Collection
177                else if(o instanceof Collection) {
178                        Collection coll=(Collection)o;
179                        Iterator<Entry<Key, Object>> it = coll.entryIterator();
180                        Entry<Key, Object> e;
181                        List<Attr> attres=new ArrayList<Attr>();
182                        Attr attr;
183                        Collection.Key k;
184                        while(it.hasNext()) {
185                                e = it.next();
186                                k=e.getKey();
187                                attr=doc.createAttribute(IsNumeric.call(null,k.getString())?"attribute-"+k.getString():k.getString());
188                                attr.setValue(Caster.toString(e.getValue()));
189                                attres.add(attr);
190                        }
191                        return attres.toArray(new Attr[attres.size()]);
192                }
193        // Node Map and List
194                Node[] nodes=_toNodeArray(doc,o);
195                if(nodes!=null) return toAttrArray(doc,nodes);
196        // Single Text Node
197                try {
198                        return new Attr[]{toAttr(doc,o)};
199                } catch (ExpressionException e) {
200                        throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Attributes Array");
201                }
202        }
203
204        /**
205         * casts a value to a XML Comment Object
206         * @param doc XML Document
207         * @param o Object to cast
208         * @return XML Comment Object
209         * @throws PageException
210         */
211        public static Comment toComment(Document doc,Object o) throws PageException {
212                if(o instanceof Comment) return (Comment)o;
213                else if(o instanceof CharacterData) return doc.createComment(((CharacterData)o).getData());
214                return doc.createComment(Caster.toString(o));
215        }
216        
217        /**
218         * casts a value to a XML Comment Array
219         * @param doc XML Document
220         * @param o Object to cast
221         * @return XML Comment Array
222         * @throws PageException
223         */
224        public static Comment[] toCommentArray(Document doc,Object o) throws PageException {
225        // Node[]
226                if(o instanceof Node[]) {
227                        Node[] nodes=(Node[])o;
228                        if(_isAllOfSameType(nodes,Node.COMMENT_NODE))return (Comment[])nodes; 
229                        
230                        Comment[] comments=new Comment[nodes.length];
231                        for(int i=0;i<nodes.length;i++) {
232                                comments[i]=toComment(doc,nodes[i]);
233                        }
234                        return comments;
235                }
236        // Collection
237                else if(o instanceof Collection) {
238                        Collection coll=(Collection)o;
239                        Iterator<Object> it = coll.valueIterator();
240                        List<Comment> comments=new ArrayList<Comment>();
241                        while(it.hasNext()) {
242                                comments.add(toComment(doc,it.next()));
243                        }
244                        return comments.toArray(new Comment[comments.size()]);
245                }
246        // Node Map and List
247                Node[] nodes=_toNodeArray(doc,o);
248                if(nodes!=null) return toCommentArray(doc,nodes);
249        // Single Text Node
250                try {
251                        return new Comment[]{toComment(doc,o)};
252                } catch (ExpressionException e) {
253                        throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Comment Array");
254                }
255        }
256
257        /**
258         * casts a value to a XML Element
259         * @param doc XML Document
260         * @param o Object to cast
261         * @return XML Element Object
262         * @throws PageException
263         */
264        public static Element toElement(Document doc,Object o) throws PageException {
265                if(o instanceof Element)return (Element)o;
266                else if(o instanceof Node)throw new ExpressionException("Object "+Caster.toClassName(o)+" must be a XML Element");
267                return doc.createElement(Caster.toString(o));
268        }
269        
270        /**
271         * casts a value to a XML Element Array
272         * @param doc XML Document
273         * @param o Object to cast
274         * @return XML Comment Array
275         * @throws PageException
276         */
277        public static Element[] toElementArray(Document doc,Object o) throws PageException {
278        // Node[]
279                if(o instanceof Node[]) {
280                        Node[] nodes=(Node[])o;
281                        if(_isAllOfSameType(nodes,Node.ELEMENT_NODE))return (Element[])nodes; 
282                        
283                        Element[] elements=new Element[nodes.length];
284                        for(int i=0;i<nodes.length;i++) {
285                                elements[i]=toElement(doc,nodes[i]);
286                        }
287                        return elements;
288                }
289        // Collection
290                else if(o instanceof Collection) {
291                        Collection coll=(Collection)o;
292                        Iterator<Object> it = coll.valueIterator();
293                        List<Element> elements=new ArrayList<Element>();
294                        while(it.hasNext()) {
295                                elements.add(toElement(doc,it.next()));
296                        }
297                        return elements.toArray(new Element[elements.size()]);
298                }
299        // Node Map and List
300                Node[] nodes=_toNodeArray(doc,o);
301                if(nodes!=null) return toElementArray(doc,nodes);
302        // Single Text Node
303                try {
304                        return new Element[]{toElement(doc,o)};
305                } catch (ExpressionException e) {
306                        throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Element Array");
307                }
308        }
309        
310        /**
311         * casts a value to a XML Node
312         * @param doc XML Document
313         * @param o Object to cast
314         * @return XML Element Object
315         * @throws PageException
316         * @deprecated replaced with toRawNode
317         */
318        public static Node toNode(Object o) throws PageException {
319                if(o instanceof XMLStruct)return ((XMLStruct)o).toNode();
320                if(o instanceof Node)return (Node)o;
321                throw new CasterException(o,"node");
322        }
323        
324        /**
325         * remove lucee node wraps (XMLStruct) from node 
326         * @param node
327         * @return raw node (without wrap)
328         */
329        public static Node toRawNode(Node node) {
330                if(node instanceof XMLStruct)return ((XMLStruct)node).toNode();
331                return node;
332        }
333        
334        public static Node toNode(Document doc,Object o, boolean clone) throws PageException {
335                Node n=null;
336                if(o instanceof XMLStruct) 
337                        n = ((XMLStruct)o).toNode();
338                else if(o instanceof Node)
339                        n = ((Node)o);
340                
341                if(n!=null)return clone?n.cloneNode(true):n;
342                
343                String nodeName=Caster.toString(o);
344                if(nodeName.length()==0)nodeName="Empty";
345                return doc.createElement(nodeName);
346        }
347
348        
349        /**
350         * casts a value to a XML Element Array
351         * @param doc XML Document
352         * @param o Object to cast
353         * @return XML Comment Array
354         * @throws PageException
355         */
356        public static Node[] toNodeArray(Document doc,Object o) throws PageException {
357                if(o instanceof Node) return new Node[]{(Node)o};
358        // Node[]
359                if(o instanceof Node[]) {
360                        return (Node[])o;
361                }
362        // Collection
363                else if(o instanceof Collection) {
364                        Collection coll=(Collection)o;
365                        Iterator<Object> it = coll.valueIterator();
366                        List<Node> nodes=new ArrayList<Node>();
367                        while(it.hasNext()) {
368                                nodes.add(toNode(doc,it.next(),false));
369                        }
370                        return nodes.toArray(new Node[nodes.size()]);
371                }
372        // Node Map and List
373                Node[] nodes=_toNodeArray(doc,o);
374                if(nodes!=null) return nodes;
375        // Single Text Node
376                try {
377                        return new Node[]{toNode(doc,o,false)};
378                } catch (ExpressionException e) {
379                        throw new XMLException("can't cast Object of type "+Caster.toClassName(o)+" to a XML Node Array");
380                }
381        }
382        
383
384
385
386        /**
387         * casts a value to a XML Object defined by type parameter
388         * @param doc XML Document
389         * @param o Object to cast
390         * @param type type to cast to
391         * @return XML Text Object
392         * @throws PageException
393         */
394        public static Node toNode(Document doc, Object o, short type) throws PageException {
395                
396                if(Node.TEXT_NODE == type) toText(doc, o);
397                else if(Node.ATTRIBUTE_NODE == type) toAttr(doc, o);
398                else if(Node.COMMENT_NODE == type) toComment(doc, o);
399                else if(Node.ELEMENT_NODE == type) toElement(doc, o);
400                
401                
402                throw new ExpressionException("invalid node type definition");
403        }
404
405        /**
406         * casts a value to a XML Object Array defined by type parameter
407         * @param doc XML Document
408         * @param o Object to cast
409         * @param type type to cast to
410         * @return XML Node Array Object
411         * @throws PageException
412         */
413        public static Node[] toNodeArray(Document doc, Object o, short type) throws PageException {
414                
415                if(Node.TEXT_NODE == type) toTextArray(doc, o);
416                else if(Node.ATTRIBUTE_NODE == type) toAttrArray(doc, o);
417                else if(Node.COMMENT_NODE == type) toCommentArray(doc, o);
418                else if(Node.ELEMENT_NODE == type) toElementArray(doc, o);
419                
420                
421                throw new ExpressionException("invalid node type definition");
422        }
423
424        /* *
425         * cast a xml node to a String
426         * @param node
427         * @return xml node as String
428         * @throws ExpressionException
429         * /
430        public static String toString(Node node) throws ExpressionException  {
431        //Transformer tf;
432                try {
433                OutputFormat format = new OutputFormat();
434                
435                StringWriter writer = new StringWriter();
436                XMLSerializer serializer = new XMLSerializer(writer, format);
437                if(node instanceof Element)serializer.serialize((Element)node);
438                else serializer.serialize(XMLUtil.getDocument(node));
439                return writer.toString();
440                
441                } catch (Exception e) {
442                    throw ExpressionException.newInstance(e);
443                }
444        }
445        
446        public static String toString(Node node,String defaultValue)  {
447        //Transformer tf;
448                try {
449                OutputFormat format = new OutputFormat();
450                
451                StringWriter writer = new StringWriter();
452                XMLSerializer serializer = new XMLSerializer(writer, format);
453                if(node instanceof Element)serializer.serialize((Element)node);
454                else serializer.serialize(XMLUtil.getDocument(node));
455                return writer.toString();
456                
457                } catch (Exception e) {
458                    return defaultValue;
459                }
460        }*/
461        
462        public static String toHTML(Node node) throws ExpressionException  {
463                if(Node.DOCUMENT_NODE==node.getNodeType()) 
464                return toHTML(XMLUtil.getRootElement(node,true));
465                
466                StringBuffer sb=new StringBuffer();
467                toHTML(node, sb);
468                return sb.toString();
469        }
470    
471    private static void toHTML(Node node,StringBuffer sb) throws ExpressionException  {
472                short type=node.getNodeType();
473        if(Node.ELEMENT_NODE==type) {
474                Element el = (Element) node;
475                String tagName=el.getTagName();
476                sb.append('<');
477                        sb.append(tagName);
478                        
479                        NamedNodeMap attrs = el.getAttributes();
480                        Attr attr;
481                        int len = attrs.getLength();
482                        for(int i=0;i<len;i++) {
483                                attr=(Attr) attrs.item(i);
484                                sb.append(' ');
485                                sb.append(attr.getName());
486                                sb.append("=\"");
487                                sb.append(attr.getValue());
488                                sb.append('"');
489                        }
490                        NodeList children = el.getChildNodes();
491                        len = children.getLength();
492                        
493                        boolean doEndTag=len!=0 || (tagName.length()==4 && (tagName.equalsIgnoreCase("head") || tagName.equalsIgnoreCase("body")));
494                
495                
496                        if(!doEndTag)sb.append(" />");
497                        else sb.append('>');
498                
499                        for(int i=0;i<len;i++) {
500                                toHTML(children.item(i),sb);
501                        }
502                
503                        if(doEndTag) {
504                                sb.append("</");
505                                sb.append(el.getTagName());
506                                sb.append('>');
507                        }
508        }
509        else if(node instanceof CharacterData) {
510                sb.append(HTMLEntities.escapeHTML(node.getNodeValue()));
511                }
512        }
513        
514        /**
515         * write a xml Dom to a file
516         * @param node
517         * @param file
518         * @throws PageException
519         */
520        public static void writeTo(Node node, Resource file) throws PageException {
521        OutputStream os=null;
522                try {
523                        os=IOUtil.toBufferedOutputStream(file.getOutputStream());
524                        writeTo(node, new StreamResult(os),false,false,null,null,null);
525                }
526                catch(IOException ioe){
527                        throw Caster.toPageException(ioe);
528                }
529                finally {
530                        IOUtil.closeEL(os);
531                }
532        }
533        
534
535        public static String toString(Node node) throws PageException {
536                StringWriter sw=new StringWriter();
537                try {
538                        writeTo(node, new StreamResult(sw),false,false,null,null,null);
539                } 
540                finally {
541                        IOUtil.closeEL(sw);
542                }
543                return sw.getBuffer().toString();
544        }
545
546        public static String toString(Node node,boolean omitXMLDecl, boolean indent) throws PageException {
547                StringWriter sw=new StringWriter();
548                try {
549                        writeTo(node, new StreamResult(sw),omitXMLDecl,indent,null,null,null);
550                } 
551                finally {
552                        IOUtil.closeEL(sw);
553                }
554                return sw.getBuffer().toString();
555        }
556        
557        
558        public static String toString(Node node,boolean omitXMLDecl,boolean indent,String publicId,String systemId,String encoding) throws PageException {
559                StringWriter sw=new StringWriter();
560                try {
561                        writeTo(node, new StreamResult(sw),omitXMLDecl,indent,publicId,systemId,encoding);
562                } 
563                finally {
564                        IOUtil.closeEL(sw);
565                }
566                return sw.getBuffer().toString();
567        }
568        
569        public static String toString(NodeList nodes,boolean omitXMLDecl, boolean indent) throws PageException {
570                StringWriter sw=new StringWriter();
571                try {
572                        int len = nodes.getLength();
573                        for(int i=0;i<len;i++){
574                                writeTo(nodes.item(i), new StreamResult(sw),omitXMLDecl,indent,null,null,null);
575                        }
576                } 
577                finally {
578                        IOUtil.closeEL(sw);
579                }
580                return sw.getBuffer().toString();
581        }
582        
583        public static String toString(Node node,String defaultValue) {
584                StringWriter sw=new StringWriter();
585                try {
586                        writeTo(node, new StreamResult(sw),false,false,null,null,null);
587                } 
588                catch(Throwable t){
589                        ExceptionUtil.rethrowIfNecessary(t);
590                        return defaultValue;
591                }
592                finally {
593                        IOUtil.closeEL(sw);
594                }
595                return sw.getBuffer().toString();
596        }
597        
598        
599        public static void writeTo(Node node,Result res,boolean omitXMLDecl,boolean indent, String publicId,String systemId,String encoding) throws PageException {
600                try {
601                        Transformer t = XMLUtil.getTransformerFactory().newTransformer();
602                        t.setOutputProperty(OutputKeys.INDENT,indent?"yes":"no");
603                        t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,omitXMLDecl?"yes":"no");
604                        //t.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); 
605                        
606                        // optional properties
607                        if(!StringUtil.isEmpty(publicId,true))t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,publicId);
608                        if(!StringUtil.isEmpty(systemId,true))t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,systemId);
609                        if(!StringUtil.isEmpty(encoding,true))t.setOutputProperty(OutputKeys.ENCODING,encoding);
610                        
611                        t.transform(new DOMSource(node), res);
612                } catch (Exception e) {
613                        throw Caster.toPageException(e);
614                }
615        }
616        
617
618    /**
619         * Casts a XML Node to a HTML Presentation
620         * @param node
621         * @param pageContext
622         * @return html output
623         */
624        public static DumpData toDumpData(Node node, PageContext pageContext, int maxlevel, DumpProperties props) {
625                if(maxlevel<=0) {
626                        return DumpUtil.MAX_LEVEL_REACHED;
627                }
628                maxlevel--;
629                // Document
630                if(node instanceof Document) {
631                        DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
632                        table.setTitle("XML Document");
633                        table.appendRow(1,new SimpleDumpData("XmlComment"),new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLCOMMENT,null).toString()));
634                        table.appendRow(1,new SimpleDumpData("XmlRoot"),        DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLROOT,null), pageContext,maxlevel,props));
635                        return table;
636                        
637                }
638                // Element
639                if(node instanceof Element) {
640                        DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
641                        table.setTitle("XML Element");
642                        table.appendRow(1,new SimpleDumpData("xmlName"),                new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNAME,null).toString()));
643                        table.appendRow(1,new SimpleDumpData("XmlNsPrefix"),    new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNSPREFIX,null).toString()));
644                        table.appendRow(1,new SimpleDumpData("XmlNsURI"),               new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNSURI,null).toString()));
645                        table.appendRow(1,new SimpleDumpData("XmlText"),                DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLTEXT,null), pageContext,maxlevel,props));
646                        table.appendRow(1,new SimpleDumpData("XmlComment"),     new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLCOMMENT,null).toString()));
647                        table.appendRow(1,new SimpleDumpData("XmlAttributes"),DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLATTRIBUTES,null), pageContext,maxlevel,props));
648                        table.appendRow(1,new SimpleDumpData("XmlChildren"),    DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLCHILDREN,null), pageContext,maxlevel,props));
649                        return table;
650                        
651                }
652                // Text
653                if(node instanceof Text) {
654                        DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
655                        table.setTitle("XML Text");
656                        Text txt=(Text) node;
657                        
658                        table.appendRow(1,new SimpleDumpData("XmlText"),new SimpleDumpData(txt.getData()));
659                        return table;
660                        
661                }
662                // Attr
663                if(node instanceof Attr) {
664                        DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
665                        table.setTitle("XML Attr");
666                        table.appendRow(1,new SimpleDumpData("xmlName"),                new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNAME,null).toString()));
667                        table.appendRow(1,new SimpleDumpData("XmlValue"),       DumpUtil.toDumpData(((Attr)node).getValue(), pageContext,maxlevel,props));
668                        table.appendRow(1,new SimpleDumpData("XmlType"),        new SimpleDumpData(XMLUtil.getTypeAsString(node,true)));
669                        
670                        return table;
671                        
672                }
673                // Node
674                DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
675                table.setTitle("XML Node ("+ListLast.call(null,node.getClass().getName(),".")+")");
676                table.appendRow(1,new SimpleDumpData("xmlName"),                new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNAME,null).toString()));
677                table.appendRow(1,new SimpleDumpData("XmlNsPrefix"),    new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNSPREFIX,null).toString()));
678                table.appendRow(1,new SimpleDumpData("XmlNsURI"),               new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLNSURI,null).toString()));
679                table.appendRow(1,new SimpleDumpData("XmlText"),                DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLTEXT,null), pageContext,maxlevel,props));
680                table.appendRow(1,new SimpleDumpData("XmlComment"),     new SimpleDumpData(XMLUtil.getProperty(node,XMLUtil.XMLCOMMENT,null).toString()));
681                table.appendRow(1,new SimpleDumpData("XmlAttributes"),DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLATTRIBUTES,null), pageContext,maxlevel,props));
682                table.appendRow(1,new SimpleDumpData("XmlChildren"),    DumpUtil.toDumpData(XMLUtil.getProperty(node,XMLUtil.XMLCHILDREN,null), pageContext,maxlevel,props));
683                        
684                table.appendRow(1,new SimpleDumpData("XmlType"),        new SimpleDumpData(XMLUtil.getTypeAsString(node,true)));
685                
686                return table;   
687        }
688        
689        /**
690         * casts a value to a XML named Node Map
691         * @param doc XML Document
692         * @param o Object to cast
693         * @return XML named Node Map Object
694         */
695        private static Node[] _toNodeArray(Document doc,Object o) {
696                if(o instanceof Node) return new Node[]{(Node)o};
697        // Node[]
698                if(o instanceof Node[]) return ((Node[])o);
699        // NamedNodeMap
700                else if(o instanceof NamedNodeMap) {
701                        NamedNodeMap map=(NamedNodeMap)o;
702                        int len=map.getLength();
703                        Node[] nodes=new Node[len];
704                        for(int i=0;i<len;i++) {
705                                nodes[i]=map.item(i);
706                        }
707                        return nodes;
708                }
709        // XMLAttributes
710                else if(o instanceof XMLAttributes) {
711                        return _toNodeArray(doc, ((XMLAttributes)o).toNamedNodeMap());
712                }
713        // NodeList
714                else if(o instanceof NodeList)  {
715                        NodeList list=(NodeList)o;
716                        int len=list.getLength();
717                        Node[] nodes=new Node[len];
718                        for(int i=0;i<nodes.length;i++) {
719                                nodes[i]=list.item(i);
720                        }
721                        return nodes;
722                }
723                return null;
724        }
725        
726        /**
727         * Check if all Node are of the type defnined by para,meter 
728         * @param nodes nodes to check
729         * @param type to compare
730         * @return are all of the same type
731         */
732        private static boolean _isAllOfSameType(Node[] nodes, short type) {
733                for(int i=0;i<nodes.length;i++) {
734                        if(nodes[i].getNodeType()!=type)return false;
735                }
736                return true;
737        }
738
739        /**
740         * creates a XMLCollection Object from a Node
741         * @param node
742         * @param caseSensitive
743         * @return xmlstruct from node
744         */
745        public static XMLStruct toXMLStruct(Node node, boolean caseSensitive) {
746            return XMLStructFactory.newInstance(node,caseSensitive);
747        }
748        
749        public static Element toRawElement(Object value, Element defaultValue) {
750                if(value instanceof Node) {
751                        Node node=XMLCaster.toRawNode((Node) value);
752                        if(node instanceof Document) return ((Document) node).getDocumentElement();
753                        if(node instanceof Element) return (Element) node;
754                        return defaultValue;
755                }
756                try {
757                        return XMLUtil.parse(new InputSource(new StringReader(Caster.toString(value))),null,false).getDocumentElement();
758                } catch (Throwable t) {
759                        ExceptionUtil.rethrowIfNecessary(t);
760                        return defaultValue;
761                }
762        }
763
764}