001    package net.sf.logdistiller.xml;
002    
003    /*
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    import java.util.Iterator;
018    import java.util.NoSuchElementException;
019    import org.w3c.dom.Element;
020    import org.w3c.dom.Node;
021    import org.w3c.dom.NodeList;
022    
023    /**
024     * Miscellaneous utilities for DOM.
025     */
026    public class DOMUtils
027    {
028        private DOMUtils()
029        {
030        }
031    
032        public static String getPCDATAByTagName( Element elmt, String tagName )
033        {
034            return getPCDATAByTagName( elmt, tagName, false );
035        }
036    
037        public static String getPCDATAByTagName( Element elmt, String tagName, boolean normalize )
038        {
039            Iterator iter = getChildElementsByTagName( elmt, tagName );
040            if ( !iter.hasNext() )
041            {
042                return null;
043            }
044            return getPCDATA( (Element) iter.next(), normalize );
045        }
046    
047        /**
048         * Computes the resulting string of a <code>#PCDATA</code> element: it can consist in the XML document of a
049         * combination of nodes Text, EntityReference and CDATASection, with Comment.
050         *
051         * @param normalize normalize the element before computing?
052         */
053        public static String getPCDATA( Element element, boolean normalize )
054        {
055            if ( normalize )
056            {
057                element.normalize();
058            }
059            StringBuffer buff = new StringBuffer();
060            NodeList list = element.getChildNodes();
061            int len = list.getLength();
062            for ( int i = 0; i < len; i++ )
063            {
064                Node n = list.item( i );
065                switch ( n.getNodeType() )
066                {
067                    case Node.TEXT_NODE:
068                    case Node.CDATA_SECTION_NODE:
069                        buff.append( n.getNodeValue() );
070                        break;
071                    case Node.ENTITY_REFERENCE_NODE:
072                        buff.append( n.getFirstChild().getNodeValue() );
073                        break;
074                    case Node.COMMENT_NODE:
075                        break; // ignore comments
076                    default: // should not occur if really #PCDATA
077                        throw new IllegalArgumentException( "element '" + element.getNodeName()
078                            + "' is not #PCDATA because it " + "contains a " + getNodeTypeAsString( n ) + " node" );
079                }
080            }
081            return buff.toString();
082        }
083    
084        public static String getPCDATA( Element elmt )
085        {
086            return getPCDATA( elmt, false );
087        }
088    
089        public static Iterator getChildElementsByTagName( Element element, String tagName )
090        {
091            return new ElementIterator( element.getChildNodes(), tagName );
092        }
093    
094        public static String getNodeTypeAsString( Node node )
095        {
096            int type = node.getNodeType();
097            switch ( type )
098            {
099                case Node.ELEMENT_NODE:
100                    return "Element";
101                case Node.ATTRIBUTE_NODE:
102                    return "Attribute";
103                case Node.TEXT_NODE:
104                    return "Text";
105                case Node.CDATA_SECTION_NODE:
106                    return "CDATASection";
107                case Node.ENTITY_REFERENCE_NODE:
108                    return "EntityReference";
109                case Node.ENTITY_NODE:
110                    return "Entity";
111                case Node.PROCESSING_INSTRUCTION_NODE:
112                    return "ProcessingInstruction";
113                case Node.COMMENT_NODE:
114                    return "Comment";
115                case Node.DOCUMENT_NODE:
116                    return "Document";
117                case Node.DOCUMENT_TYPE_NODE:
118                    return "DocumentType";
119                case Node.DOCUMENT_FRAGMENT_NODE:
120                    return "DocumentFragment";
121                case Node.NOTATION_NODE:
122                    return "Notation";
123                default:
124            }
125            return "Unknown node type: " + type;
126        }
127    
128        private static class ElementIterator
129            implements Iterator
130        {
131            private final NodeList nodeList;
132    
133            private final String tagName;
134    
135            private int index;
136    
137            private Element next;
138    
139            public ElementIterator( NodeList nodeList )
140            {
141                this( nodeList, null );
142            }
143    
144            public ElementIterator( NodeList nodeList, String tagName )
145            {
146                this.nodeList = nodeList;
147                this.tagName = tagName;
148                findNext();
149            }
150    
151            public boolean hasNext()
152            {
153                return ( next != null );
154            }
155    
156            private void findNext()
157            {
158                while ( index < nodeList.getLength() )
159                {
160                    Node node = nodeList.item( index );
161                    index++;
162                    if ( ( node.getNodeType() == Node.ELEMENT_NODE )
163                        && ( ( tagName == null ) || node.getNodeName().equals( tagName ) ) )
164                    {
165                        // next element found
166                        next = (Element) node;
167                        return;
168                    }
169                }
170                // no element available any more
171                next = null;
172            }
173    
174            public Object next()
175            {
176                if ( next == null )
177                {
178                    throw new NoSuchElementException();
179                }
180                Object returnValue = next;
181                findNext();
182                return returnValue;
183            }
184    
185            public void remove()
186            {
187                throw new UnsupportedOperationException();
188            }
189        }
190    }