001: /*--
002:
003: $Id: DOMBuilder.java,v 1.1 2005/04/27 09:32:41 wittek Exp $
004:
005: Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
006: All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions
010: are met:
011:
012: 1. Redistributions of source code must retain the above copyright
013: notice, this list of conditions, and the following disclaimer.
014:
015: 2. Redistributions in binary form must reproduce the above copyright
016: notice, this list of conditions, and the disclaimer that follows
017: these conditions in the documentation and/or other materials
018: provided with the distribution.
019:
020: 3. The name "JDOM" must not be used to endorse or promote products
021: derived from this software without prior written permission. For
022: written permission, please contact <request_AT_jdom_DOT_org>.
023:
024: 4. Products derived from this software may not be called "JDOM", nor
025: may "JDOM" appear in their name, without prior written permission
026: from the JDOM Project Management <request_AT_jdom_DOT_org>.
027:
028: In addition, we request (but do not require) that you include in the
029: end-user documentation provided with the redistribution and/or in the
030: software itself an acknowledgement equivalent to the following:
031: "This product includes software developed by the
032: JDOM Project (http://www.jdom.org/)."
033: Alternatively, the acknowledgment may be graphical using the logos
034: available at http://www.jdom.org/images/logos.
035:
036: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
040: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: SUCH DAMAGE.
048:
049: This software consists of voluntary contributions made by many
050: individuals on behalf of the JDOM Project and was originally
051: created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
052: Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
053: on the JDOM Project, please see <http://www.jdom.org/>.
054:
055: */
056:
057: package org.jdom.input;
058:
059: import org.jdom.*;
060: import org.jdom.Document;
061: import org.jdom.Element;
062: import org.w3c.dom.*;
063:
064: /**
065: * Builds a JDOM {@link org.jdom.Document org.jdom.Document} from a pre-existing
066: * DOM {@link org.w3c.dom.Document org.w3c.dom.Document}. Also handy for testing
067: * builds from files to sanity check {@link SAXBuilder}.
068: *
069: * @version $Revision: 1.1 $, $Date: 2005/04/27 09:32:41 $
070: * @author Brett McLaughlin
071: * @author Jason Hunter
072: * @author Philip Nelson
073: * @author Kevin Regan
074: * @author Yusuf Goolamabbas
075: * @author Dan Schaffer
076: * @author Bradley S. Huffman
077: */
078: public class DOMBuilder {
079:
080: private static final String CVS_ID = "@(#) $RCSfile: DOMBuilder.java,v $ $Revision: 1.1 $ $Date: 2005/04/27 09:32:41 $ $Name: $";
081:
082: /** Adapter class to use */
083: private String adapterClass;
084:
085: /** The factory for creating new JDOM objects */
086: private JDOMFactory factory = new DefaultJDOMFactory();
087:
088: /**
089: * This creates a new DOMBuilder which will attempt to first locate
090: * a parser via JAXP, then will try to use a set of default parsers.
091: * The underlying parser will not validate.
092: */
093: public DOMBuilder() {
094: }
095:
096: /**
097: * This creates a new DOMBuilder using the specified DOMAdapter
098: * implementation as a way to choose the underlying parser.
099: * The underlying parser will not validate.
100: *
101: * @param adapterClass <code>String</code> name of class
102: * to use for DOM building.
103: */
104: public DOMBuilder(String adapterClass) {
105: this .adapterClass = adapterClass;
106: }
107:
108: /*
109: * This sets a custom JDOMFactory for the builder. Use this to build
110: * the tree with your own subclasses of the JDOM classes.
111: *
112: * @param factory <code>JDOMFactory</code> to use
113: */
114: public void setFactory(JDOMFactory factory) {
115: this .factory = factory;
116: }
117:
118: /**
119: * Returns the current {@link org.jdom.JDOMFactory} in use.
120: * @return the factory in use
121: */
122: public JDOMFactory getFactory() {
123: return factory;
124: }
125:
126: /**
127: * This will build a JDOM tree from an existing DOM tree.
128: *
129: * @param domDocument <code>org.w3c.dom.Document</code> object
130: * @return <code>Document</code> - JDOM document object.
131: */
132: public Document build(org.w3c.dom.Document domDocument) {
133: Document doc = factory.document(null);
134: buildTree(domDocument, doc, null, true);
135: return doc;
136: }
137:
138: /**
139: * This will build a JDOM Element from an existing DOM Element
140: *
141: * @param domElement <code> org.w3c.dom.Element</code> object
142: * @return <code>Element</code> - JDOM Element object
143: */
144: public org.jdom.Element build(org.w3c.dom.Element domElement) {
145: Document doc = factory.document(null);
146: buildTree(domElement, doc, null, true);
147: return doc.getRootElement();
148: }
149:
150: /**
151: * This takes a DOM <code>Node</code> and builds up
152: * a JDOM tree, recursing until the DOM tree is exhausted
153: * and the JDOM tree results.
154: *
155: * @param node <code>Code</node> to examine.
156: * @param doc JDOM <code>Document</code> being built.
157: * @param current <code>Element</code> that is current parent.
158: * @param atRoot <code>boolean</code> indicating whether at root level.
159: */
160: private void buildTree(Node node, Document doc, Element current,
161: boolean atRoot) {
162: // Recurse through the tree
163: switch (node.getNodeType()) {
164: case Node.DOCUMENT_NODE:
165: NodeList nodes = node.getChildNodes();
166: for (int i = 0, size = nodes.getLength(); i < size; i++) {
167: buildTree(nodes.item(i), doc, current, true);
168: }
169: break;
170:
171: case Node.ELEMENT_NODE:
172: String nodeName = node.getNodeName();
173: String prefix = "";
174: String localName = nodeName;
175: int colon = nodeName.indexOf(':');
176: if (colon >= 0) {
177: prefix = nodeName.substring(0, colon);
178: localName = nodeName.substring(colon + 1);
179: }
180:
181: // Get element's namespace
182: Namespace ns = null;
183: String uri = node.getNamespaceURI();
184: if (uri == null) {
185: ns = (current == null) ? Namespace.NO_NAMESPACE
186: : current.getNamespace(prefix);
187: } else {
188: ns = Namespace.getNamespace(prefix, uri);
189: }
190:
191: Element element = factory.element(localName, ns);
192:
193: if (atRoot) {
194: // If at root, set as document root
195: doc.setRootElement(element); // XXX should we use a factory call?
196: } else {
197: // else add to parent element
198: factory.addContent(current, element);
199: }
200:
201: // Add namespaces
202: NamedNodeMap attributeList = node.getAttributes();
203: int attsize = attributeList.getLength();
204:
205: for (int i = 0; i < attsize; i++) {
206: Attr att = (Attr) attributeList.item(i);
207:
208: String attname = att.getName();
209: if (attname.startsWith("xmlns")) {
210: String attPrefix = "";
211: colon = attname.indexOf(':');
212: if (colon >= 0) {
213: attPrefix = attname.substring(colon + 1);
214: }
215:
216: String attvalue = att.getValue();
217:
218: Namespace declaredNS = Namespace.getNamespace(
219: attPrefix, attvalue);
220:
221: // Add as additional namespaces if it's different
222: // than this element's namespace (perhaps we should
223: // also have logic not to mark them as additional if
224: // it's been done already, but it probably doesn't
225: // matter)
226: if (prefix.equals(attPrefix)) {
227: element.setNamespace(declaredNS);
228: } else {
229: factory.addNamespaceDeclaration(element,
230: declaredNS);
231: }
232: }
233: }
234:
235: // Add attributes
236: for (int i = 0; i < attsize; i++) {
237: Attr att = (Attr) attributeList.item(i);
238:
239: String attname = att.getName();
240:
241: if (!attname.startsWith("xmlns")) {
242: String attPrefix = "";
243: String attLocalName = attname;
244: colon = attname.indexOf(':');
245: if (colon >= 0) {
246: attPrefix = attname.substring(0, colon);
247: attLocalName = attname.substring(colon + 1);
248: }
249:
250: String attvalue = att.getValue();
251:
252: // Get attribute's namespace
253: Namespace attns = null;
254: if ("".equals(attPrefix)) {
255: attns = Namespace.NO_NAMESPACE;
256: } else {
257: attns = element.getNamespace(attPrefix);
258: }
259:
260: Attribute attribute = factory.attribute(
261: attLocalName, attvalue, attns);
262: factory.setAttribute(element, attribute);
263: }
264: }
265:
266: // Recurse on child nodes
267: // The list should never be null nor should it ever contain
268: // null nodes, but some DOM impls are broken
269: NodeList children = node.getChildNodes();
270: if (children != null) {
271: int size = children.getLength();
272: for (int i = 0; i < size; i++) {
273: Node item = children.item(i);
274: if (item != null) {
275: buildTree(item, doc, element, false);
276: }
277: }
278: }
279: break;
280:
281: case Node.TEXT_NODE:
282: String data = node.getNodeValue();
283: factory.addContent(current, factory.text(data));
284: break;
285:
286: case Node.CDATA_SECTION_NODE:
287: String cdata = node.getNodeValue();
288: factory.addContent(current, factory.cdata(cdata));
289: break;
290:
291: case Node.PROCESSING_INSTRUCTION_NODE:
292: if (atRoot) {
293: factory.addContent(doc, factory.processingInstruction(
294: node.getNodeName(), node.getNodeValue()));
295: } else {
296: factory.addContent(current, factory
297: .processingInstruction(node.getNodeName(), node
298: .getNodeValue()));
299: }
300: break;
301:
302: case Node.COMMENT_NODE:
303: if (atRoot) {
304: factory.addContent(doc, factory.comment(node
305: .getNodeValue()));
306: } else {
307: factory.addContent(current, factory.comment(node
308: .getNodeValue()));
309: }
310: break;
311:
312: case Node.ENTITY_REFERENCE_NODE:
313: EntityRef entity = factory.entityRef(node.getNodeName());
314: factory.addContent(current, entity);
315: break;
316:
317: case Node.ENTITY_NODE:
318: // ??
319: break;
320:
321: case Node.DOCUMENT_TYPE_NODE:
322: DocumentType domDocType = (DocumentType) node;
323: String publicID = domDocType.getPublicId();
324: String systemID = domDocType.getSystemId();
325: String internalDTD = domDocType.getInternalSubset();
326:
327: DocType docType = factory.docType(domDocType.getName());
328: docType.setPublicID(publicID);
329: docType.setSystemID(systemID);
330: docType.setInternalSubset(internalDTD);
331:
332: factory.addContent(doc, docType);
333: break;
334: }
335: }
336: }
|