1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: DOM2TO.java,v 1.9 2004/02/20 19:30:40 bhakti Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.trax;
  20. import java.io.IOException;
  21. import org.w3c.dom.NamedNodeMap;
  22. import org.w3c.dom.Node;
  23. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  24. import org.xml.sax.ContentHandler;
  25. import org.xml.sax.DTDHandler;
  26. import org.xml.sax.EntityResolver;
  27. import org.xml.sax.ErrorHandler;
  28. import org.xml.sax.InputSource;
  29. import org.xml.sax.Locator;
  30. import org.xml.sax.SAXException;
  31. import org.xml.sax.SAXNotRecognizedException;
  32. import org.xml.sax.SAXNotSupportedException;
  33. import org.xml.sax.XMLReader;
  34. import com.sun.org.apache.xml.internal.serializer.NamespaceMappings;
  35. /**
  36. * @author Santiago Pericas-Geertsen
  37. */
  38. public class DOM2TO implements XMLReader, Locator {
  39. private final static String EMPTYSTRING = "";
  40. private static final String XMLNS_PREFIX = "xmlns";
  41. /**
  42. * A reference to the DOM to be traversed.
  43. */
  44. private Node _dom;
  45. /**
  46. * A reference to the output handler receiving the events.
  47. */
  48. private SerializationHandler _handler;
  49. public DOM2TO(Node root, SerializationHandler handler) {
  50. _dom = root;
  51. _handler = handler;
  52. }
  53. public ContentHandler getContentHandler() {
  54. return null;
  55. }
  56. public void setContentHandler(ContentHandler handler) {
  57. // Empty
  58. }
  59. public void parse(InputSource unused) throws IOException, SAXException {
  60. parse(_dom);
  61. }
  62. public void parse() throws IOException, SAXException {
  63. if (_dom != null) {
  64. boolean isIncomplete =
  65. (_dom.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE);
  66. if (isIncomplete) {
  67. _handler.startDocument();
  68. parse(_dom);
  69. _handler.endDocument();
  70. }
  71. else {
  72. parse(_dom);
  73. }
  74. }
  75. }
  76. /**
  77. * Traverse the DOM and generate TO events for a handler. Notice that
  78. * we need to handle implicit namespace declarations too.
  79. */
  80. private void parse(Node node)
  81. throws IOException, SAXException
  82. {
  83. if (node == null) return;
  84. switch (node.getNodeType()) {
  85. case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE
  86. case Node.DOCUMENT_TYPE_NODE :
  87. case Node.ENTITY_NODE :
  88. case Node.ENTITY_REFERENCE_NODE:
  89. case Node.NOTATION_NODE :
  90. // These node types are ignored!!!
  91. break;
  92. case Node.CDATA_SECTION_NODE:
  93. _handler.startCDATA();
  94. _handler.characters(node.getNodeValue());
  95. _handler.endCDATA();
  96. break;
  97. case Node.COMMENT_NODE: // should be handled!!!
  98. _handler.comment(node.getNodeValue());
  99. break;
  100. case Node.DOCUMENT_NODE:
  101. _handler.startDocument();
  102. Node next = node.getFirstChild();
  103. while (next != null) {
  104. parse(next);
  105. next = next.getNextSibling();
  106. }
  107. _handler.endDocument();
  108. break;
  109. case Node.DOCUMENT_FRAGMENT_NODE:
  110. next = node.getFirstChild();
  111. while (next != null) {
  112. parse(next);
  113. next = next.getNextSibling();
  114. }
  115. break;
  116. case Node.ELEMENT_NODE:
  117. // Generate SAX event to start element
  118. final String qname = node.getNodeName();
  119. _handler.startElement(null, null, qname);
  120. String prefix;
  121. final NamedNodeMap map = node.getAttributes();
  122. final int length = map.getLength();
  123. // Process all other attributes
  124. NamespaceMappings nm = new NamespaceMappings();
  125. for (int i = 0; i < length; i++) {
  126. int colon;
  127. final Node attr = map.item(i);
  128. final String qnameAttr = attr.getNodeName();
  129. if (qnameAttr.startsWith(XMLNS_PREFIX)) {
  130. final String uriAttr = attr.getNodeValue();
  131. colon = qnameAttr.lastIndexOf(':');
  132. prefix = (colon > 0) ? qnameAttr.substring(colon + 1)
  133. : EMPTYSTRING;
  134. _handler.namespaceAfterStartElement(prefix, uriAttr);
  135. }
  136. else {
  137. final String uriAttr = attr.getNamespaceURI();
  138. // Uri may be implicitly declared
  139. if (uriAttr != null && !uriAttr.equals(EMPTYSTRING) ) {
  140. colon = qnameAttr.lastIndexOf(':');
  141. // Fix for bug 26319
  142. // For attributes not given an prefix explictly
  143. // but having a namespace uri we need
  144. // to explicitly generate the prefix
  145. String newPrefix = nm.lookupPrefix(uriAttr);
  146. if (newPrefix == null)
  147. newPrefix = nm.generateNextPrefix();
  148. prefix = (colon > 0) ? qnameAttr.substring(0, colon)
  149. : newPrefix;
  150. _handler.namespaceAfterStartElement(prefix, uriAttr);
  151. _handler.addAttribute((prefix + ":" + qnameAttr)
  152. , attr.getNodeValue());
  153. } else {
  154. _handler.addAttribute(qnameAttr, attr.getNodeValue());
  155. }
  156. }
  157. }
  158. // Now element namespace and children
  159. final String uri = node.getNamespaceURI();
  160. final String localName = node.getLocalName();
  161. // Uri may be implicitly declared
  162. if (uri != null) {
  163. final int colon = qname.lastIndexOf(':');
  164. prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING;
  165. _handler.namespaceAfterStartElement(prefix, uri);
  166. }else {
  167. // Fix for bug 26319
  168. // If an element foo is created using
  169. // createElementNS(null,locName)
  170. // then the element should be serialized
  171. // <foo xmlns=" "/>
  172. if (uri == null && localName != null) {
  173. prefix = EMPTYSTRING;
  174. _handler.namespaceAfterStartElement(prefix, EMPTYSTRING);
  175. }
  176. }
  177. // Traverse all child nodes of the element (if any)
  178. next = node.getFirstChild();
  179. while (next != null) {
  180. parse(next);
  181. next = next.getNextSibling();
  182. }
  183. // Generate SAX event to close element
  184. _handler.endElement(qname);
  185. break;
  186. case Node.PROCESSING_INSTRUCTION_NODE:
  187. _handler.processingInstruction(node.getNodeName(),
  188. node.getNodeValue());
  189. break;
  190. case Node.TEXT_NODE:
  191. _handler.characters(node.getNodeValue());
  192. break;
  193. }
  194. }
  195. /**
  196. * This class is only used internally so this method should never
  197. * be called.
  198. */
  199. public DTDHandler getDTDHandler() {
  200. return null;
  201. }
  202. /**
  203. * This class is only used internally so this method should never
  204. * be called.
  205. */
  206. public ErrorHandler getErrorHandler() {
  207. return null;
  208. }
  209. /**
  210. * This class is only used internally so this method should never
  211. * be called.
  212. */
  213. public boolean getFeature(String name) throws SAXNotRecognizedException,
  214. SAXNotSupportedException
  215. {
  216. return false;
  217. }
  218. /**
  219. * This class is only used internally so this method should never
  220. * be called.
  221. */
  222. public void setFeature(String name, boolean value) throws
  223. SAXNotRecognizedException, SAXNotSupportedException
  224. {
  225. }
  226. /**
  227. * This class is only used internally so this method should never
  228. * be called.
  229. */
  230. public void parse(String sysId) throws IOException, SAXException {
  231. throw new IOException("This method is not yet implemented.");
  232. }
  233. /**
  234. * This class is only used internally so this method should never
  235. * be called.
  236. */
  237. public void setDTDHandler(DTDHandler handler) throws NullPointerException {
  238. }
  239. /**
  240. * This class is only used internally so this method should never
  241. * be called.
  242. */
  243. public void setEntityResolver(EntityResolver resolver) throws
  244. NullPointerException
  245. {
  246. }
  247. /**
  248. * This class is only used internally so this method should never
  249. * be called.
  250. */
  251. public EntityResolver getEntityResolver() {
  252. return null;
  253. }
  254. /**
  255. * This class is only used internally so this method should never
  256. * be called.
  257. */
  258. public void setErrorHandler(ErrorHandler handler) throws
  259. NullPointerException
  260. {
  261. }
  262. /**
  263. * This class is only used internally so this method should never
  264. * be called.
  265. */
  266. public void setProperty(String name, Object value) throws
  267. SAXNotRecognizedException, SAXNotSupportedException {
  268. }
  269. /**
  270. * This class is only used internally so this method should never
  271. * be called.
  272. */
  273. public Object getProperty(String name) throws SAXNotRecognizedException,
  274. SAXNotSupportedException
  275. {
  276. return null;
  277. }
  278. /**
  279. * This class is only used internally so this method should never
  280. * be called.
  281. */
  282. public int getColumnNumber() {
  283. return 0;
  284. }
  285. /**
  286. * This class is only used internally so this method should never
  287. * be called.
  288. */
  289. public int getLineNumber() {
  290. return 0;
  291. }
  292. /**
  293. * This class is only used internally so this method should never
  294. * be called.
  295. */
  296. public String getPublicId() {
  297. return null;
  298. }
  299. /**
  300. * This class is only used internally so this method should never
  301. * be called.
  302. */
  303. public String getSystemId() {
  304. return null;
  305. }
  306. // Debugging
  307. private String getNodeTypeFromCode(short code) {
  308. String retval = null;
  309. switch (code) {
  310. case Node.ATTRIBUTE_NODE :
  311. retval = "ATTRIBUTE_NODE"; break;
  312. case Node.CDATA_SECTION_NODE :
  313. retval = "CDATA_SECTION_NODE"; break;
  314. case Node.COMMENT_NODE :
  315. retval = "COMMENT_NODE"; break;
  316. case Node.DOCUMENT_FRAGMENT_NODE :
  317. retval = "DOCUMENT_FRAGMENT_NODE"; break;
  318. case Node.DOCUMENT_NODE :
  319. retval = "DOCUMENT_NODE"; break;
  320. case Node.DOCUMENT_TYPE_NODE :
  321. retval = "DOCUMENT_TYPE_NODE"; break;
  322. case Node.ELEMENT_NODE :
  323. retval = "ELEMENT_NODE"; break;
  324. case Node.ENTITY_NODE :
  325. retval = "ENTITY_NODE"; break;
  326. case Node.ENTITY_REFERENCE_NODE :
  327. retval = "ENTITY_REFERENCE_NODE"; break;
  328. case Node.NOTATION_NODE :
  329. retval = "NOTATION_NODE"; break;
  330. case Node.PROCESSING_INSTRUCTION_NODE :
  331. retval = "PROCESSING_INSTRUCTION_NODE"; break;
  332. case Node.TEXT_NODE:
  333. retval = "TEXT_NODE"; break;
  334. }
  335. return retval;
  336. }
  337. }