001/*
002// $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/W3CDOMWrapper.java#5 $
003// Package org.eigenbase.xom is an XML Object Mapper.
004// Copyright (C) 2005-2005 The Eigenbase Project
005// Copyright (C) 2005-2005 Disruptive Tech
006// Copyright (C) 2005-2005 LucidEra, Inc.
007// Portions Copyright (C) 2001-2005 Kana Software, Inc. and others.
008//
009// This library is free software; you can redistribute it and/or modify it
010// under the terms of the GNU Lesser General Public License as published by the
011// Free Software Foundation; either version 2 of the License, or (at your
012// option) any later version approved by The Eigenbase Project.
013//
014// This library is distributed in the hope that it will be useful,
015// but WITHOUT ANY WARRANTY; without even the implied warranty of
016// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017// GNU Lesser General Public License for more details.
018//
019// You should have received a copy of the GNU Lesser General Public License
020// along with this library; if not, write to the Free Software
021// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022//
023// dsommerfield, 16 July, 2001
024*/
025
026package org.eigenbase.xom.wrappers;
027
028import org.eigenbase.xom.*;
029import org.w3c.dom.CharacterData;
030import org.w3c.dom.*;
031
032/**
033 * This implementation of DOMWrapper wraps any w3c DOM-compliant java
034 * XML Parser.
035 */
036public class W3CDOMWrapper implements DOMWrapper {
037
038    final Node node;
039    private final Locator locator;
040
041    /**
042     * W3CDOMWrapper parses XML based on a Node.  The Node may be either an
043     * Element or some form of text node.
044     *
045     * @param node DOM Node
046     * @param locator Callback to find location of node. May be null.
047     */
048    public W3CDOMWrapper(Node node, Locator locator)
049    {
050        this.node = node;
051        this.locator = locator;
052    }
053
054    /**
055     * Map the Node's type to DOMWrapper's simplified concept of type.
056     */
057    public int getType()
058    {
059        int nodeType = node.getNodeType();
060        switch (nodeType) {
061        case Node.ELEMENT_NODE:
062            return ELEMENT;
063        case Node.COMMENT_NODE:
064            return COMMENT;
065        case Node.CDATA_SECTION_NODE:
066            return CDATA;
067        case Node.TEXT_NODE:
068            return FREETEXT;
069        default:
070            return UNKNOWN;
071        }
072    }
073
074    /**
075     * Retrieve the tag name directly.  Return null immediately if not an
076     * element.
077     **/
078    public String getTagName()
079    {
080        if (getType() != ELEMENT) {
081            return null;
082        }
083        return ((Element)node).getTagName();
084    }
085
086    /**
087     * Return the attribute.  Return null if the attribute isn't defined,
088     * or if not an element.  This behavior differs from the underlying DOM,
089     * which returns an empty string for undefined attributes.
090     */
091    public String getAttribute(String attrName)
092    {
093        if (getType() != ELEMENT) {
094            return null;
095        }
096        String attrVal = ((Element)node).getAttribute(attrName);
097        if (attrVal == null || attrVal.length() == 0) {
098            return null;
099        } else {
100            return attrVal;
101        }
102    }
103
104    // implement DOMWrapper
105    public String[] getAttributeNames()
106    {
107        NamedNodeMap map = node.getAttributes();
108        int count = map.getLength();
109        String[] attributeNames = new String[count];
110        for (int i = 0; i < count; i++) {
111            attributeNames[i] = map.item(i).getLocalName();
112        }
113        return attributeNames;
114    }
115
116    /**
117     * Recursively unwrap and create the contained text.  If the node is a
118     * comment, return the comment text; but ignore comments inside elements.
119     **/
120    public String getText()
121    {
122        if (node instanceof Comment) {
123            return ((Comment)node).getData();
124        } else {
125            StringBuffer sbuf = new StringBuffer();
126            appendNodeText(node, sbuf);
127            return sbuf.toString();
128        }
129    }
130
131    // implement DOMWrapper
132    public String toXML()
133    {
134        boolean onlyElements = false;
135        return XOMUtil.wrapperToXml(this, onlyElements);
136    }
137
138    /**
139     * Helper to collect all Text nodes into a buffer.
140     */
141    private static void appendNodeText(Node node, StringBuffer sbuf)
142    {
143        if (node instanceof Comment) {
144            // ignore it
145        } else if (node instanceof CharacterData) {
146            // Text
147            sbuf.append(((CharacterData)node).getData());
148        } else if (node instanceof Element) {
149            NodeList nodeList = node.getChildNodes();
150            for (int i = 0; i < nodeList.getLength(); i++) {
151                appendNodeText(nodeList.item(i), sbuf);
152            }
153        }
154    }
155
156    /**
157     * Retrieve all children, and build an array of W3CDOMWrappers around
158     * each child that is of TEXT or ELEMENT type to return.
159     */
160    public DOMWrapper[] getChildren()
161    {
162        if (getType() != ELEMENT) {
163            return new DOMWrapper[0];
164        }
165        NodeList nodeList = node.getChildNodes();
166
167        // Count the elements that are TEXT or ELEMENTs.
168        int count = 0;
169        for (int i = 0; i < nodeList.getLength(); i++) {
170            Node nextNode = nodeList.item(i);
171            if (nextNode instanceof Element || nextNode instanceof Text) {
172                count++;
173            }
174        }
175
176        // Create and populate the array
177        DOMWrapper[] ret = new DOMWrapper[count];
178        count = 0;
179        for (int i = 0; i < nodeList.getLength(); i++) {
180            Node nextNode = nodeList.item(i);
181            if (nextNode instanceof Element || nextNode instanceof Text) {
182                ret[count++] = new W3CDOMWrapper(nextNode, locator);
183            }
184        }
185
186        // Done.
187        return ret;
188    }
189
190    /**
191     * Retrieve all children, and build an array of W3CDOMWrappers around
192     * each ELEMENT child.
193     */
194    public DOMWrapper[] getElementChildren()
195    {
196        if (getType() != ELEMENT) {
197            return new DOMWrapper[0];
198        }
199        NodeList nodeList = node.getChildNodes();
200
201        // Count the elements that are TEXT or ELEMENTs.
202        int count = 0;
203        for (int i = 0; i < nodeList.getLength(); i++) {
204            Node nextNode = nodeList.item(i);
205            if (nextNode instanceof Element) {
206                count++;
207            }
208        }
209
210        // Create and populate the array
211        DOMWrapper[] ret = new DOMWrapper[count];
212        count = 0;
213        for (int i = 0; i < nodeList.getLength(); i++) {
214            Node nextNode = nodeList.item(i);
215            if (nextNode instanceof Element) {
216                ret[count++] = new W3CDOMWrapper(nextNode, locator);
217            }
218        }
219
220        // Done.
221        return ret;
222    }
223
224    public Location getLocation()
225    {
226        return locator.getLocation(this);
227    }
228}
229
230// End W3CDOMWrapper.java