001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.modeler.util;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.io.OutputStream;
022    import java.io.StringReader;
023    
024    import javax.xml.parsers.DocumentBuilder;
025    import javax.xml.parsers.DocumentBuilderFactory;
026    import javax.xml.parsers.ParserConfigurationException;
027    import javax.xml.transform.OutputKeys;
028    import javax.xml.transform.Transformer;
029    import javax.xml.transform.TransformerException;
030    import javax.xml.transform.TransformerFactory;
031    import javax.xml.transform.dom.DOMSource;
032    import javax.xml.transform.stream.StreamResult;
033    
034    import org.w3c.dom.Document;
035    import org.w3c.dom.NamedNodeMap;
036    import org.w3c.dom.Node;
037    import org.xml.sax.EntityResolver;
038    import org.xml.sax.InputSource;
039    import org.xml.sax.SAXException;
040    
041    
042    /**
043     *  Few simple utils to read DOM
044     *
045     * @author Costin Manolache
046     */
047    public class DomUtil {
048        private static org.apache.commons.logging.Log log=
049            org.apache.commons.logging.LogFactory.getLog( DomUtil.class );
050    
051        // -------------------- DOM utils --------------------
052    
053        /** Get the trimed text content of a node or null if there is no text
054         */
055        public static String getContent(Node n ) {
056            if( n==null ) return null;
057            Node n1=DomUtil.getChild(n, Node.TEXT_NODE);
058    
059            if( n1==null ) return null;
060    
061            String s1=n1.getNodeValue();
062            return s1.trim();
063        }
064    
065        /** Get the first element child.
066         * @param parent lookup direct childs
067         * @param name name of the element. If null return the first element.
068         */
069        public static Node getChild( Node parent, String name ) {
070            if( parent==null ) return null;
071            Node first=parent.getFirstChild();
072            if( first==null ) return null;
073    
074            for (Node node = first; node != null;
075                 node = node.getNextSibling()) {
076                //System.out.println("getNode: " + name + " " + node.getNodeName());
077                if( node.getNodeType()!=Node.ELEMENT_NODE)
078                    continue;
079                if( name != null &&
080                    name.equals( node.getNodeName() ) ) {
081                    return node;
082                }
083                if( name == null ) {
084                    return node;
085                }
086            }
087            return null;
088        }
089    
090        public static String getAttribute(Node element, String attName ) {
091            NamedNodeMap attrs=element.getAttributes();
092            if( attrs==null ) return null;
093            Node attN=attrs.getNamedItem(attName);
094            if( attN==null ) return null;
095            return attN.getNodeValue();
096        }
097    
098        public static void setAttribute(Node node, String attName, String val) {
099            NamedNodeMap attributes=node.getAttributes();
100            Node attNode=node.getOwnerDocument().createAttribute(attName);
101            attNode.setNodeValue( val );
102            attributes.setNamedItem(attNode);
103        }
104        
105        public static void removeAttribute( Node node, String attName ) {
106            NamedNodeMap attributes=node.getAttributes();
107            attributes.removeNamedItem(attName);                
108        }
109        
110        
111        /** Set or replace the text value 
112         */ 
113        public static void setText(Node node, String val) {
114            Node chld=DomUtil.getChild(node, Node.TEXT_NODE);
115            if( chld == null ) {
116                Node textN=node.getOwnerDocument().createTextNode(val);
117                node.appendChild(textN);
118                return;
119            }
120            // change the value
121            chld.setNodeValue(val);           
122        }
123    
124        /** Find the first direct child with a given attribute.
125         * @param parent
126         * @param elemName name of the element, or null for any 
127         * @param attName attribute we're looking for
128         * @param attVal attribute value or null if we just want any
129         */ 
130        public static Node findChildWithAtt(Node parent, String elemName,
131                                            String attName, String attVal) {
132            
133            Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE);
134            if( attVal== null ) {
135                while( child!= null &&
136                        ( elemName==null || elemName.equals( child.getNodeName())) && 
137                        DomUtil.getAttribute(child, attName) != null ) {
138                    child=getNext(child, elemName, Node.ELEMENT_NODE );
139                }
140            } else {
141                while( child!= null && 
142                        ( elemName==null || elemName.equals( child.getNodeName())) && 
143                        ! attVal.equals( DomUtil.getAttribute(child, attName)) ) {
144                    child=getNext(child, elemName, Node.ELEMENT_NODE );
145                }
146            }
147            return child;        
148        }    
149        
150    
151        /** Get the first child's content ( ie it's included TEXT node ).
152         */
153        public static String getChildContent( Node parent, String name ) {
154            Node first=parent.getFirstChild();
155            if( first==null ) return null;
156            for (Node node = first; node != null;
157                 node = node.getNextSibling()) {
158                //System.out.println("getNode: " + name + " " + node.getNodeName());
159                if( name.equals( node.getNodeName() ) ) {
160                    return getContent( node );
161                }
162            }
163            return null;
164        }
165    
166        /** Get the first direct child with a given type
167         */
168        public static Node getChild( Node parent, int type ) {
169            Node n=parent.getFirstChild();
170            while( n!=null && type != n.getNodeType() ) {
171                n=n.getNextSibling();
172            }
173            if( n==null ) return null;
174            return n;
175        }
176    
177        /** Get the next sibling with the same name and type
178         */
179        public static Node getNext( Node current ) {
180            String name=current.getNodeName();
181            int type=current.getNodeType();
182            return getNext( current, name, type);
183        }
184    
185        /** Return the next sibling with a given name and type
186         */ 
187        public static Node getNext( Node current, String name, int type) {
188            Node first=current.getNextSibling();
189            if( first==null ) return null;
190    
191            for (Node node = first; node != null;
192                 node = node.getNextSibling()) {
193                
194                if( type >= 0 && node.getNodeType() != type ) continue;
195                //System.out.println("getNode: " + name + " " + node.getNodeName());
196                if( name==null )
197                    return node;
198                if( name.equals( node.getNodeName() ) ) {
199                    return node;
200                }
201            }
202            return null;
203        }
204    
205        public static class NullResolver implements EntityResolver {
206            public InputSource resolveEntity (String publicId,
207                                                       String systemId)
208                throws SAXException, IOException
209            {
210                if( log.isTraceEnabled())
211                    log.trace("ResolveEntity: " + publicId + " " + systemId);
212                return new InputSource(new StringReader(""));
213            }
214        }
215    
216        public static void setAttributes( Object o, Node parent)
217        {
218            NamedNodeMap attrs=parent.getAttributes();
219            if( attrs==null ) return;
220    
221            for (int i=0; i<attrs.getLength(); i++ ) {
222                Node n=attrs.item(i);
223                String name=n.getNodeName();
224                String value=n.getNodeValue();
225    
226                if( log.isTraceEnabled() )
227                    log.trace("Attribute " + parent.getNodeName() + " " +
228                                name + "=" + value);
229                try {
230                    IntrospectionUtils.setProperty(o, name, value);
231                } catch( Exception ex ) {
232                    ex.printStackTrace();
233                }
234            }
235        }
236    
237        /** Read XML as DOM.
238         */
239        public static Document readXml(InputStream is)
240            throws SAXException, IOException, ParserConfigurationException
241        {
242            DocumentBuilderFactory dbf =
243                DocumentBuilderFactory.newInstance();
244    
245            dbf.setValidating(false);
246            dbf.setIgnoringComments(false);
247            dbf.setIgnoringElementContentWhitespace(true);
248            //dbf.setCoalescing(true);
249            //dbf.setExpandEntityReferences(true);
250    
251            DocumentBuilder db = null;
252            db = dbf.newDocumentBuilder();
253            db.setEntityResolver( new NullResolver() );
254    
255            // db.setErrorHandler( new MyErrorHandler());
256    
257            Document doc = db.parse(is);
258            return doc;
259        }
260    
261        public static void writeXml( Node n, OutputStream os )
262                throws TransformerException
263        {
264            TransformerFactory tf=TransformerFactory.newInstance();
265            //identity
266            Transformer t=tf.newTransformer();
267            t.setOutputProperty(OutputKeys.INDENT, "yes");
268            t.transform(new DOMSource( n ), new StreamResult( os ));
269        }
270    }