001package 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
017import java.util.Iterator;
018import java.util.NoSuchElementException;
019import org.w3c.dom.Element;
020import org.w3c.dom.Node;
021import org.w3c.dom.NodeList;
022
023/**
024 * Miscellaneous utilities for DOM.
025 */
026public 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<Element> 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<Element> 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<Element>
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, String tagName )
140        {
141            this.nodeList = nodeList;
142            this.tagName = tagName;
143            findNext();
144        }
145
146        public boolean hasNext()
147        {
148            return ( next != null );
149        }
150
151        private void findNext()
152        {
153            while ( index < nodeList.getLength() )
154            {
155                Node node = nodeList.item( index );
156                index++;
157                if ( ( node.getNodeType() == Node.ELEMENT_NODE )
158                    && ( ( tagName == null ) || node.getNodeName().equals( tagName ) ) )
159                {
160                    // next element found
161                    next = (Element) node;
162                    return;
163                }
164            }
165            // no element available any more
166            next = null;
167        }
168
169        public Element next()
170        {
171            if ( next == null )
172            {
173                throw new NoSuchElementException();
174            }
175            Element returnValue = next;
176            findNext();
177            return returnValue;
178        }
179
180        public void remove()
181        {
182            throw new UnsupportedOperationException();
183        }
184    }
185}