1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xerces" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 2001, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.impl.xs.opti;
  58. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  59. import com.sun.org.apache.xerces.internal.xni.QName;
  60. import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  61. import com.sun.org.apache.xerces.internal.xni.XMLString;
  62. import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  63. import org.w3c.dom.Attr;
  64. import org.w3c.dom.Element;
  65. import org.w3c.dom.NamedNodeMap;
  66. import org.w3c.dom.Node;
  67. import java.util.Vector;
  68. import java.util.Enumeration;
  69. /**
  70. * @author Rahul Srivastava, Sun Microsystems Inc.
  71. * @author Sandy Gao, IBM
  72. *
  73. * @version $Id: SchemaDOM.java,v 1.4 2003/07/03 15:15:58 neilg Exp $
  74. */
  75. public class SchemaDOM extends DefaultDocument {
  76. static final int relationsRowResizeFactor = 15;
  77. static final int relationsColResizeFactor = 10;
  78. NodeImpl[][] relations;
  79. // parent must be an element in this scheme
  80. ElementImpl parent;
  81. int currLoc;
  82. int nextFreeLoc;
  83. boolean hidden;
  84. // for annotation support:
  85. StringBuffer fAnnotationBuffer = null;
  86. public SchemaDOM() {
  87. reset();
  88. }
  89. public void startElement(QName element, XMLAttributes attributes,
  90. int line, int column) {
  91. ElementImpl node = new ElementImpl(line, column);
  92. processElement(element, attributes, node);
  93. // now the current node added, becomes the parent
  94. parent = node;
  95. }
  96. public void emptyElement(QName element, XMLAttributes attributes,
  97. int line, int column) {
  98. ElementImpl node = new ElementImpl(line, column);
  99. processElement(element, attributes, node);
  100. }
  101. private void processElement(QName element, XMLAttributes attributes, ElementImpl node) {
  102. // populate node
  103. node.prefix = element.prefix;
  104. node.localpart = element.localpart;
  105. node.rawname = element.rawname;
  106. node.uri = element.uri;
  107. node.schemaDOM = this;
  108. // set the attributes
  109. Attr[] attrs = new Attr[attributes.getLength()];
  110. for (int i=0; i<attributes.getLength(); i++) {
  111. attrs[i] = new AttrImpl(null,
  112. attributes.getPrefix(i),
  113. attributes.getLocalName(i),
  114. attributes.getQName(i),
  115. attributes.getURI(i),
  116. attributes.getValue(i));
  117. }
  118. node.attrs = attrs;
  119. // check if array needs to be resized
  120. if (nextFreeLoc == relations.length) {
  121. resizeRelations();
  122. }
  123. // store the current parent
  124. //if (relations[currLoc][0] == null || relations[currLoc][0] != parent) {
  125. if (relations[currLoc][0] != parent) {
  126. relations[nextFreeLoc][0] = parent;
  127. currLoc = nextFreeLoc++;
  128. }
  129. // add the current node as child of parent
  130. boolean foundPlace = false;
  131. int i = 1;
  132. for (i = 1; i<relations[currLoc].length; i++) {
  133. if (relations[currLoc][i] == null) {
  134. foundPlace = true;
  135. break;
  136. }
  137. }
  138. if (!foundPlace) {
  139. resizeRelations(currLoc);
  140. }
  141. relations[currLoc][i] = node;
  142. parent.parentRow = currLoc;
  143. node.row = currLoc;
  144. node.col = i;
  145. }
  146. public void endElement() {
  147. // the parent of current parent node becomes the parent
  148. // for the next node.
  149. currLoc = parent.row;
  150. parent = (ElementImpl)relations[currLoc][0];
  151. }
  152. // note that this will only be called within appinfo/documentation
  153. void comment(XMLString text) {
  154. fAnnotationBuffer.append("<!--").append(text.toString()).append("-->");
  155. }
  156. // note that this will only be called within appinfo/documentation
  157. void processingInstruction(String target, String data) {
  158. fAnnotationBuffer.append("<?").append(target).append(" ").append(data).append("?>");
  159. }
  160. // note that this will only be called within appinfo/documentation
  161. void characters(XMLString text ) {
  162. // need to handle &s and <s
  163. for(int i=text.offset; i<text.offset+text.length; i++ ) {
  164. if(text.ch[i] == '&') {
  165. fAnnotationBuffer.append("&");
  166. } else if (text.ch[i] == '<') {
  167. fAnnotationBuffer.append("<");
  168. } else {
  169. fAnnotationBuffer.append(text.ch[i]);
  170. }
  171. }
  172. }
  173. void endAnnotationElement(QName elemName, boolean complete) {
  174. if(complete) {
  175. fAnnotationBuffer.append("\n</").append(elemName.rawname).append(">");
  176. // note that this is always called after endElement on <annotation>'s
  177. // child and before endElement on annotation.
  178. // hence, we must make this the child of the current
  179. // parent's only child.
  180. ElementImpl child = (ElementImpl)relations[currLoc][1];
  181. // check if array needs to be resized
  182. if (nextFreeLoc == relations.length) {
  183. resizeRelations();
  184. }
  185. int newRow = child.parentRow = nextFreeLoc++;
  186. // now find the place to insert this node
  187. boolean foundPlace = false;
  188. int i = 1;
  189. for (; i<relations[newRow].length; i++) {
  190. if (relations[newRow][i] == null) {
  191. foundPlace = true;
  192. break;
  193. }
  194. }
  195. if (!foundPlace) {
  196. resizeRelations(newRow);
  197. }
  198. relations[newRow][i] = new TextImpl(fAnnotationBuffer, this, newRow, i);
  199. // apparently, there is no sensible way of resetting
  200. // these things
  201. fAnnotationBuffer = null;
  202. } else //capturing character calls
  203. fAnnotationBuffer.append("</").append(elemName.rawname).append(">");
  204. }
  205. void startAnnotationCDATA() {
  206. fAnnotationBuffer.append("<![CDATA[");
  207. }
  208. void endAnnotationCDATA() {
  209. fAnnotationBuffer.append("]]>");
  210. }
  211. private void resizeRelations() {
  212. NodeImpl[][] temp = new NodeImpl[relations.length+relationsRowResizeFactor][];
  213. System.arraycopy(relations, 0, temp, 0, relations.length);
  214. for (int i = relations.length ; i < temp.length ; i++) {
  215. temp[i] = new NodeImpl[relationsColResizeFactor];
  216. }
  217. relations = temp;
  218. }
  219. private void resizeRelations(int i) {
  220. NodeImpl[] temp = new NodeImpl[relations[i].length+relationsColResizeFactor];
  221. System.arraycopy(relations[i], 0, temp, 0, relations[i].length);
  222. relations[i] = temp;
  223. }
  224. public void reset() {
  225. // help out the garbage collector
  226. if(relations != null)
  227. for(int i=0; i<relations.length; i++)
  228. for(int j=0; j<relations[i].length; j++)
  229. relations[i][j] = null;
  230. relations = new NodeImpl[relationsRowResizeFactor][];
  231. parent = new ElementImpl(0, 0);
  232. parent.rawname = "DOCUMENT_NODE";
  233. currLoc = 0;
  234. nextFreeLoc = 1;
  235. for (int i=0; i<relationsRowResizeFactor; i++) {
  236. relations[i] = new NodeImpl[relationsColResizeFactor];
  237. }
  238. relations[currLoc][0] = parent;
  239. }
  240. public void printDOM() {
  241. /*
  242. for (int i=0; i<relations.length; i++) {
  243. if (relations[i][0] != null) {
  244. for (int j=0; j<relations[i].length; j++) {
  245. if (relations[i][j] != null) {
  246. System.out.print(relations[i][j].nodeType+"-"+relations[i][j].parentRow+" ");
  247. }
  248. }
  249. System.out.println("");
  250. }
  251. }
  252. */
  253. //traverse(getDocumentElement(), 0);
  254. }
  255. // debug methods
  256. public static void traverse(Node node, int depth) {
  257. indent(depth);
  258. System.out.print("<"+node.getNodeName());
  259. if (node.hasAttributes()) {
  260. NamedNodeMap attrs = node.getAttributes();
  261. for (int i=0; i<attrs.getLength(); i++) {
  262. System.out.print(" "+((Attr)attrs.item(i)).getName()+"=\""+((Attr)attrs.item(i)).getValue()+"\"");
  263. }
  264. }
  265. if (node.hasChildNodes()) {
  266. System.out.println(">");
  267. depth+=4;
  268. for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
  269. traverse(child, depth);
  270. }
  271. depth-=4;
  272. indent(depth);
  273. System.out.println("</"+node.getNodeName()+">");
  274. }
  275. else {
  276. System.out.println("/>");
  277. }
  278. }
  279. public static void indent(int amount) {
  280. for (int i = 0; i < amount; i++) {
  281. System.out.print(' ');
  282. }
  283. }
  284. // org.w3c.dom methods
  285. public Element getDocumentElement() {
  286. // this returns a parent node, known to be an ElementImpl
  287. return (ElementImpl)relations[0][1];
  288. }
  289. // commence the serialization of an annotation
  290. void startAnnotation(QName elemName, XMLAttributes attributes,
  291. NamespaceContext namespaceContext) {
  292. if(fAnnotationBuffer == null) fAnnotationBuffer = new StringBuffer(256);
  293. fAnnotationBuffer.append("<").append(elemName.rawname).append(" ");
  294. // attributes are a bit of a pain. To get this right, we have to keep track
  295. // of the namespaces we've seen declared, then examine the namespace context
  296. // for other namespaces so that we can also include them.
  297. // optimized for simplicity and the case that not many
  298. // namespaces are declared on this annotation...
  299. Vector namespaces = new Vector();
  300. for(int i=0; i<attributes.getLength(); i++) {
  301. String aValue = attributes.getValue(i);
  302. String aPrefix = attributes.getPrefix(i);
  303. // if it's xmlns, must be a namespace decl
  304. namespaces.addElement(aValue);
  305. fAnnotationBuffer.append(attributes.getQName(i)).append("=\"").append(aValue).append("\" ");
  306. }
  307. // now we have to look through currently in-scope namespaces to see what
  308. // wasn't declared here
  309. Enumeration currPrefixes = namespaceContext.getAllPrefixes();
  310. while(currPrefixes.hasMoreElements()) {
  311. String prefix = (String)currPrefixes.nextElement();
  312. String uri = namespaceContext.getURI(prefix);
  313. if(!namespaces.contains(uri)) {
  314. // have to declare this one
  315. if(prefix == XMLSymbols.EMPTY_STRING)
  316. fAnnotationBuffer.append("xmlns").append("=\"").append(uri).append("\" ");
  317. else
  318. fAnnotationBuffer.append("xmlns:").append(prefix).append("=\"").append(uri).append("\" ");
  319. }
  320. }
  321. fAnnotationBuffer.append(">\n");
  322. }
  323. void startAnnotationElement(QName elemName, XMLAttributes attributes) {
  324. fAnnotationBuffer.append("<").append(elemName.rawname).append(" ");
  325. for(int i=0; i<attributes.getLength(); i++) {
  326. String aValue = attributes.getValue(i);
  327. fAnnotationBuffer.append(" ").append(attributes.getQName(i)).append("=\"").append(processAttValue(aValue)).append("\" ");
  328. }
  329. fAnnotationBuffer.append(">");
  330. }
  331. private static String processAttValue(String original) {
  332. // normally, nothing will happen
  333. StringBuffer newVal = new StringBuffer(original.length());
  334. for(int i=0; i<original.length(); i++) {
  335. char currChar = original.charAt(i);
  336. if(currChar == '"') {
  337. newVal.append(""");
  338. } else if (currChar == '>') {
  339. newVal.append(">");
  340. } else if (currChar == '&') {
  341. newVal.append("&");
  342. } else {
  343. newVal.append(currChar);
  344. }
  345. }
  346. return newVal.toString();
  347. }
  348. }