/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: DOM2TO.java,v 1.10 2004/12/10 18:39:15 santiagopg Exp $ */ package com.sun.org.apache.xalan.internal.xsltc.trax; import java.io.IOException; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLReader; import com.sun.org.apache.xml.internal.serializer.NamespaceMappings; /** * @author Santiago Pericas-Geertsen */ public class DOM2TO implements XMLReader, Locator { private final static String EMPTYSTRING = ""; private static final String XMLNS_PREFIX = "xmlns"; /** * A reference to the DOM to be traversed. */ private Node _dom; /** * A reference to the output handler receiving the events. */ private SerializationHandler _handler; public DOM2TO(Node root, SerializationHandler handler) { _dom = root; _handler = handler; } public ContentHandler getContentHandler() { return null; } public void setContentHandler(ContentHandler handler) { // Empty } public void parse(InputSource unused) throws IOException, SAXException { parse(_dom); } public void parse() throws IOException, SAXException { if (_dom != null) { boolean isIncomplete = (_dom.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE); if (isIncomplete) { _handler.startDocument(); parse(_dom); _handler.endDocument(); } else { parse(_dom); } } } /** * Traverse the DOM and generate TO events for a handler. Notice that * we need to handle implicit namespace declarations too. */ private void parse(Node node) throws IOException, SAXException { if (node == null) return; switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE case Node.DOCUMENT_TYPE_NODE : case Node.ENTITY_NODE : case Node.ENTITY_REFERENCE_NODE: case Node.NOTATION_NODE : // These node types are ignored!!! break; case Node.CDATA_SECTION_NODE: _handler.startCDATA(); _handler.characters(node.getNodeValue()); _handler.endCDATA(); break; case Node.COMMENT_NODE: // should be handled!!! _handler.comment(node.getNodeValue()); break; case Node.DOCUMENT_NODE: _handler.startDocument(); Node next = node.getFirstChild(); while (next != null) { parse(next); next = next.getNextSibling(); } _handler.endDocument(); break; case Node.DOCUMENT_FRAGMENT_NODE: next = node.getFirstChild(); while (next != null) { parse(next); next = next.getNextSibling(); } break; case Node.ELEMENT_NODE: // Generate SAX event to start element final String qname = node.getNodeName(); _handler.startElement(null, null, qname); int colon; String prefix; final NamedNodeMap map = node.getAttributes(); final int length = map.getLength(); // Process all namespace attributes first for (int i = 0; i < length; i++) { final Node attr = map.item(i); final String qnameAttr = attr.getNodeName(); // Is this a namespace declaration? if (qnameAttr.startsWith(XMLNS_PREFIX)) { final String uriAttr = attr.getNodeValue(); colon = qnameAttr.lastIndexOf(':'); prefix = (colon > 0) ? qnameAttr.substring(colon + 1) : EMPTYSTRING; _handler.namespaceAfterStartElement(prefix, uriAttr); } } // Process all non-namespace attributes next NamespaceMappings nm = new NamespaceMappings(); for (int i = 0; i < length; i++) { final Node attr = map.item(i); final String qnameAttr = attr.getNodeName(); // Is this a regular attribute? if (!qnameAttr.startsWith(XMLNS_PREFIX)) { final String uriAttr = attr.getNamespaceURI(); // Uri may be implicitly declared if (uriAttr != null && !uriAttr.equals(EMPTYSTRING) ) { colon = qnameAttr.lastIndexOf(':'); // Fix for bug 26319 // For attributes not given an prefix explictly // but having a namespace uri we need // to explicitly generate the prefix String newPrefix = nm.lookupPrefix(uriAttr); if (newPrefix == null) newPrefix = nm.generateNextPrefix(); prefix = (colon > 0) ? qnameAttr.substring(0, colon) : newPrefix; _handler.namespaceAfterStartElement(prefix, uriAttr); _handler.addAttribute((prefix + ":" + qnameAttr), attr.getNodeValue()); } else { _handler.addAttribute(qnameAttr, attr.getNodeValue()); } } } // Now element namespace and children final String uri = node.getNamespaceURI(); final String localName = node.getLocalName(); // Uri may be implicitly declared if (uri != null) { colon = qname.lastIndexOf(':'); prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING; _handler.namespaceAfterStartElement(prefix, uri); }else { // Fix for bug 26319 // If an element foo is created using // createElementNS(null,locName) // then the element should be serialized // if (uri == null && localName != null) { prefix = EMPTYSTRING; _handler.namespaceAfterStartElement(prefix, EMPTYSTRING); } } // Traverse all child nodes of the element (if any) next = node.getFirstChild(); while (next != null) { parse(next); next = next.getNextSibling(); } // Generate SAX event to close element _handler.endElement(qname); break; case Node.PROCESSING_INSTRUCTION_NODE: _handler.processingInstruction(node.getNodeName(), node.getNodeValue()); break; case Node.TEXT_NODE: _handler.characters(node.getNodeValue()); break; } } /** * This class is only used internally so this method should never * be called. */ public DTDHandler getDTDHandler() { return null; } /** * This class is only used internally so this method should never * be called. */ public ErrorHandler getErrorHandler() { return null; } /** * This class is only used internally so this method should never * be called. */ public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { return false; } /** * This class is only used internally so this method should never * be called. */ public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { } /** * This class is only used internally so this method should never * be called. */ public void parse(String sysId) throws IOException, SAXException { throw new IOException("This method is not yet implemented."); } /** * This class is only used internally so this method should never * be called. */ public void setDTDHandler(DTDHandler handler) throws NullPointerException { } /** * This class is only used internally so this method should never * be called. */ public void setEntityResolver(EntityResolver resolver) throws NullPointerException { } /** * This class is only used internally so this method should never * be called. */ public EntityResolver getEntityResolver() { return null; } /** * This class is only used internally so this method should never * be called. */ public void setErrorHandler(ErrorHandler handler) throws NullPointerException { } /** * This class is only used internally so this method should never * be called. */ public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { } /** * This class is only used internally so this method should never * be called. */ public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { return null; } /** * This class is only used internally so this method should never * be called. */ public int getColumnNumber() { return 0; } /** * This class is only used internally so this method should never * be called. */ public int getLineNumber() { return 0; } /** * This class is only used internally so this method should never * be called. */ public String getPublicId() { return null; } /** * This class is only used internally so this method should never * be called. */ public String getSystemId() { return null; } // Debugging private String getNodeTypeFromCode(short code) { String retval = null; switch (code) { case Node.ATTRIBUTE_NODE : retval = "ATTRIBUTE_NODE"; break; case Node.CDATA_SECTION_NODE : retval = "CDATA_SECTION_NODE"; break; case Node.COMMENT_NODE : retval = "COMMENT_NODE"; break; case Node.DOCUMENT_FRAGMENT_NODE : retval = "DOCUMENT_FRAGMENT_NODE"; break; case Node.DOCUMENT_NODE : retval = "DOCUMENT_NODE"; break; case Node.DOCUMENT_TYPE_NODE : retval = "DOCUMENT_TYPE_NODE"; break; case Node.ELEMENT_NODE : retval = "ELEMENT_NODE"; break; case Node.ENTITY_NODE : retval = "ENTITY_NODE"; break; case Node.ENTITY_REFERENCE_NODE : retval = "ENTITY_REFERENCE_NODE"; break; case Node.NOTATION_NODE : retval = "NOTATION_NODE"; break; case Node.PROCESSING_INSTRUCTION_NODE : retval = "PROCESSING_INSTRUCTION_NODE"; break; case Node.TEXT_NODE: retval = "TEXT_NODE"; break; } return retval; } }