KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > xs > opti > SchemaDOM


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 package org.apache.xerces.impl.xs.opti;
18
19 import org.apache.xerces.xni.NamespaceContext;
20 import org.apache.xerces.xni.QName;
21 import org.apache.xerces.xni.XMLAttributes;
22 import org.apache.xerces.xni.XMLString;
23 import org.apache.xerces.util.XMLSymbols;
24 import org.w3c.dom.Attr JavaDoc;
25 import org.w3c.dom.Element JavaDoc;
26 import org.w3c.dom.NamedNodeMap JavaDoc;
27 import org.w3c.dom.Node JavaDoc;
28
29 import java.util.Vector JavaDoc;
30 import java.util.Enumeration JavaDoc;
31
32 /**
33  * @xerces.internal
34  *
35  * @author Rahul Srivastava, Sun Microsystems Inc.
36  * @author Sandy Gao, IBM
37  *
38  * @version $Id: SchemaDOM.java,v 1.11 2005/07/22 21:42:26 mrglavas Exp $
39  */

40 public class SchemaDOM extends DefaultDocument {
41     
42     static final int relationsRowResizeFactor = 15;
43     static final int relationsColResizeFactor = 10;
44     
45     NodeImpl[][] relations;
46     // parent must be an element in this scheme
47
ElementImpl parent;
48     int currLoc;
49     int nextFreeLoc;
50     boolean hidden;
51     boolean inCDATA;
52     
53     // for annotation support:
54
StringBuffer JavaDoc fAnnotationBuffer = null;
55     
56     public SchemaDOM() {
57         reset();
58     }
59     
60     
61     public void startElement(QName element, XMLAttributes attributes,
62             int line, int column, int offset) {
63         ElementImpl node = new ElementImpl(line, column, offset);
64         processElement(element, attributes, node);
65         // now the current node added, becomes the parent
66
parent = node;
67     }
68     
69     
70     public void emptyElement(QName element, XMLAttributes attributes,
71             int line, int column, int offset) {
72         ElementImpl node = new ElementImpl(line, column, offset);
73         processElement(element, attributes, node);
74     }
75     
76     public void startElement(QName element, XMLAttributes attributes,
77             int line, int column) {
78         startElement(element, attributes, line, column, -1);
79     }
80     
81     
82     public void emptyElement(QName element, XMLAttributes attributes,
83             int line, int column) {
84         emptyElement(element, attributes, line, column, -1);
85     }
86     
87     
88     private void processElement(QName element, XMLAttributes attributes, ElementImpl node) {
89         
90         // populate node
91
node.prefix = element.prefix;
92         node.localpart = element.localpart;
93         node.rawname = element.rawname;
94         node.uri = element.uri;
95         node.schemaDOM = this;
96         
97         // set the attributes
98
Attr JavaDoc[] attrs = new Attr JavaDoc[attributes.getLength()];
99         for (int i=0; i<attributes.getLength(); i++) {
100             attrs[i] = new AttrImpl(null,
101                     attributes.getPrefix(i),
102                     attributes.getLocalName(i),
103                     attributes.getQName(i),
104                     attributes.getURI(i),
105                     attributes.getValue(i));
106         }
107         node.attrs = attrs;
108         
109         // check if array needs to be resized
110
if (nextFreeLoc == relations.length) {
111             resizeRelations();
112         }
113         
114         // store the current parent
115
//if (relations[currLoc][0] == null || relations[currLoc][0] != parent) {
116
if (relations[currLoc][0] != parent) {
117             relations[nextFreeLoc][0] = parent;
118             currLoc = nextFreeLoc++;
119         }
120         
121         // add the current node as child of parent
122
boolean foundPlace = false;
123         int i = 1;
124         for (i = 1; i<relations[currLoc].length; i++) {
125             if (relations[currLoc][i] == null) {
126                 foundPlace = true;
127                 break;
128             }
129         }
130         
131         if (!foundPlace) {
132             resizeRelations(currLoc);
133         }
134         relations[currLoc][i] = node;
135         
136         parent.parentRow = currLoc;
137         node.row = currLoc;
138         node.col = i;
139     }
140     
141     
142     public void endElement() {
143         // the parent of current parent node becomes the parent
144
// for the next node.
145
currLoc = parent.row;
146         parent = (ElementImpl)relations[currLoc][0];
147     }
148     
149     // note that this will only be called within appinfo/documentation
150
void comment(XMLString text) {
151         fAnnotationBuffer.append("<!--").append(text.toString()).append("-->");
152     }
153     
154     // note that this will only be called within appinfo/documentation
155
void processingInstruction(String JavaDoc target, String JavaDoc data) {
156         fAnnotationBuffer.append("<?").append(target).append(" ").append(data).append("?>");
157     }
158     
159     // note that this will only be called within appinfo/documentation
160
void characters(XMLString text ) {
161         
162         // escape characters if necessary
163
if (!inCDATA) {
164             for (int i = text.offset; i < text.offset+text.length; ++i ) {
165                 char ch = text.ch[i];
166                 if (ch == '&') {
167                     fAnnotationBuffer.append("&amp;");
168                 }
169                 else if (ch == '<') {
170                     fAnnotationBuffer.append("&lt;");
171                 }
172                 // character sequence "]]>" cannot appear in content,
173
// therefore we should escape '>'.
174
else if (ch == '>') {
175                     fAnnotationBuffer.append("&gt;");
176                 }
177                 // If CR is part of the document's content, it
178
// must not be printed as a literal otherwise
179
// it would be normalized to LF when the document
180
// is reparsed.
181
else if (ch == '\r') {
182                     fAnnotationBuffer.append("&#xD;");
183                 }
184                 else {
185                     fAnnotationBuffer.append(ch);
186                 }
187             }
188         }
189         else {
190             fAnnotationBuffer.append(text.ch, text.offset, text.length);
191         }
192     }
193     
194     void endAnnotationElement(QName elemName, boolean complete) {
195         if(complete) {
196             fAnnotationBuffer.append("\n</").append(elemName.rawname).append(">");
197             // note that this is always called after endElement on <annotation>'s
198
// child and before endElement on annotation.
199
// hence, we must make this the child of the current
200
// parent's only child.
201
ElementImpl child = (ElementImpl)relations[currLoc][1];
202             
203             // check if array needs to be resized
204
if (nextFreeLoc == relations.length) {
205                 resizeRelations();
206             }
207             int newRow = child.parentRow = nextFreeLoc++;
208             
209             // now find the place to insert this node
210
boolean foundPlace = false;
211             int i = 1;
212             for (; i<relations[newRow].length; i++) {
213                 if (relations[newRow][i] == null) {
214                     foundPlace = true;
215                     break;
216                 }
217             }
218             
219             if (!foundPlace) {
220                 resizeRelations(newRow);
221             }
222             relations[newRow][i] = new TextImpl(fAnnotationBuffer, this, newRow, i);
223             // apparently, there is no sensible way of resetting
224
// these things
225
fAnnotationBuffer = null;
226         } else //capturing character calls
227
fAnnotationBuffer.append("</").append(elemName.rawname).append(">");
228     }
229     
230     void endSyntheticAnnotationElement(QName elemName, boolean complete) {
231         if(complete) {
232             fAnnotationBuffer.append("\n</").append(elemName.rawname).append(">");
233             // note that this is always called after endElement on <annotation>'s
234
// child and before endElement on annotation.
235
// hence, we must make this the child of the current
236
// parent's only child.
237
parent.fSyntheticAnnotation = fAnnotationBuffer.toString();
238             
239             // apparently, there is no sensible way of resetting
240
// these things
241
fAnnotationBuffer = null;
242         } else //capturing character calls
243
fAnnotationBuffer.append("</").append(elemName.rawname).append(">");
244     }
245     
246     void startAnnotationCDATA() {
247         inCDATA = true;
248         fAnnotationBuffer.append("<![CDATA[");
249     }
250     
251     void endAnnotationCDATA() {
252         fAnnotationBuffer.append("]]>");
253         inCDATA = false;
254     }
255     
256     private void resizeRelations() {
257         NodeImpl[][] temp = new NodeImpl[relations.length+relationsRowResizeFactor][];
258         System.arraycopy(relations, 0, temp, 0, relations.length);
259         for (int i = relations.length ; i < temp.length ; i++) {
260             temp[i] = new NodeImpl[relationsColResizeFactor];
261         }
262         relations = temp;
263     }
264     
265     private void resizeRelations(int i) {
266         NodeImpl[] temp = new NodeImpl[relations[i].length+relationsColResizeFactor];
267         System.arraycopy(relations[i], 0, temp, 0, relations[i].length);
268         relations[i] = temp;
269     }
270     
271     
272     public void reset() {
273         
274         // help out the garbage collector
275
if(relations != null)
276             for(int i=0; i<relations.length; i++)
277                 for(int j=0; j<relations[i].length; j++)
278                     relations[i][j] = null;
279         relations = new NodeImpl[relationsRowResizeFactor][];
280         parent = new ElementImpl(0, 0, 0);
281         parent.rawname = "DOCUMENT_NODE";
282         currLoc = 0;
283         nextFreeLoc = 1;
284         inCDATA = false;
285         for (int i=0; i<relationsRowResizeFactor; i++) {
286             relations[i] = new NodeImpl[relationsColResizeFactor];
287         }
288         relations[currLoc][0] = parent;
289     }
290     
291     
292     public void printDOM() {
293         /*
294          for (int i=0; i<relations.length; i++) {
295          if (relations[i][0] != null) {
296          for (int j=0; j<relations[i].length; j++) {
297          if (relations[i][j] != null) {
298          System.out.print(relations[i][j].nodeType+"-"+relations[i][j].parentRow+" ");
299          }
300          }
301          System.out.println("");
302          }
303          }
304          */

305         //traverse(getDocumentElement(), 0);
306
}
307     
308     
309     // debug methods
310

311     public static void traverse(Node JavaDoc node, int depth) {
312         indent(depth);
313         System.out.print("<"+node.getNodeName());
314         
315         if (node.hasAttributes()) {
316             NamedNodeMap JavaDoc attrs = node.getAttributes();
317             for (int i=0; i<attrs.getLength(); i++) {
318                 System.out.print(" "+((Attr JavaDoc)attrs.item(i)).getName()+"=\""+((Attr JavaDoc)attrs.item(i)).getValue()+"\"");
319             }
320         }
321         
322         if (node.hasChildNodes()) {
323             System.out.println(">");
324             depth+=4;
325             for (Node JavaDoc child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
326                 traverse(child, depth);
327             }
328             depth-=4;
329             indent(depth);
330             System.out.println("</"+node.getNodeName()+">");
331         }
332         else {
333             System.out.println("/>");
334         }
335     }
336     
337     public static void indent(int amount) {
338         for (int i = 0; i < amount; i++) {
339             System.out.print(' ');
340         }
341     }
342     
343     // org.w3c.dom methods
344
public Element JavaDoc getDocumentElement() {
345         // this returns a parent node, known to be an ElementImpl
346
return (ElementImpl)relations[0][1];
347     }
348     
349     // commence the serialization of an annotation
350
void startAnnotation(QName elemName, XMLAttributes attributes,
351             NamespaceContext namespaceContext) {
352         if(fAnnotationBuffer == null) fAnnotationBuffer = new StringBuffer JavaDoc(256);
353         fAnnotationBuffer.append("<").append(elemName.rawname).append(" ");
354         
355         // attributes are a bit of a pain. To get this right, we have to keep track
356
// of the namespaces we've seen declared, then examine the namespace context
357
// for other namespaces so that we can also include them.
358
// optimized for simplicity and the case that not many
359
// namespaces are declared on this annotation...
360
Vector JavaDoc namespaces = new Vector JavaDoc();
361         for (int i = 0; i < attributes.getLength(); ++i) {
362             String JavaDoc aValue = attributes.getValue(i);
363             String JavaDoc aPrefix = attributes.getPrefix(i);
364             String JavaDoc aQName = attributes.getQName(i);
365             // if it's xmlns:* or xmlns, must be a namespace decl
366
if (aPrefix == XMLSymbols.PREFIX_XMLNS || aQName == XMLSymbols.PREFIX_XMLNS) {
367                 namespaces.addElement(aPrefix == XMLSymbols.PREFIX_XMLNS ?
368                         attributes.getLocalName(i) : XMLSymbols.EMPTY_STRING);
369             }
370             fAnnotationBuffer.append(aQName).append("=\"").append(processAttValue(aValue)).append("\" ");
371         }
372         // now we have to look through currently in-scope namespaces to see what
373
// wasn't declared here
374
Enumeration JavaDoc currPrefixes = namespaceContext.getAllPrefixes();
375         while(currPrefixes.hasMoreElements()) {
376             String JavaDoc prefix = (String JavaDoc)currPrefixes.nextElement();
377             String JavaDoc uri = namespaceContext.getURI(prefix);
378             if (uri == null) {
379                 uri = XMLSymbols.EMPTY_STRING;
380             }
381             if (!namespaces.contains(prefix)) {
382                 // have to declare this one
383
if(prefix == XMLSymbols.EMPTY_STRING) {
384                     fAnnotationBuffer.append("xmlns").append("=\"").append(processAttValue(uri)).append("\" ");
385                 }
386                 else {
387                     fAnnotationBuffer.append("xmlns:").append(prefix).append("=\"").append(processAttValue(uri)).append("\" ");
388                 }
389             }
390         }
391         fAnnotationBuffer.append(">\n");
392     }
393     void startAnnotationElement(QName elemName, XMLAttributes attributes) {
394         fAnnotationBuffer.append("<").append(elemName.rawname);
395         for(int i=0; i<attributes.getLength(); i++) {
396             String JavaDoc aValue = attributes.getValue(i);
397             fAnnotationBuffer.append(" ").append(attributes.getQName(i)).append("=\"").append(processAttValue(aValue)).append("\"");
398         }
399         fAnnotationBuffer.append(">");
400     }
401     
402     private static String JavaDoc processAttValue(String JavaDoc original) {
403         final int length = original.length();
404         // normally, nothing will happen
405
for (int i = 0; i < length; ++i) {
406             char currChar = original.charAt(i);
407             if (currChar == '"' || currChar == '<' || currChar == '&' ||
408                     currChar == 0x09 || currChar == 0x0A || currChar == 0x0D) {
409                 return escapeAttValue(original, i);
410             }
411         }
412         return original;
413     }
414     
415     private static String JavaDoc escapeAttValue(String JavaDoc original, int from) {
416         int i;
417         final int length = original.length();
418         StringBuffer JavaDoc newVal = new StringBuffer JavaDoc(length);
419         newVal.append(original.substring(0, from));
420         for (i = from; i < length; ++i) {
421             char currChar = original.charAt(i);
422             if (currChar == '"') {
423                 newVal.append("&quot;");
424             }
425             else if (currChar == '<') {
426                 newVal.append("&lt;");
427             }
428             else if (currChar == '&') {
429                 newVal.append("&amp;");
430             }
431             // Must escape 0x09, 0x0A and 0x0D if they appear in attribute
432
// value so that they may be round-tripped. They would otherwise
433
// be transformed to a 0x20 during attribute value normalization.
434
else if (currChar == 0x09) {
435                 newVal.append("&#x9;");
436             }
437             else if (currChar == 0x0A) {
438                 newVal.append("&#xA;");
439             }
440             else if (currChar == 0x0D) {
441                 newVal.append("&#xD;");
442             }
443             else {
444                 newVal.append(currChar);
445             }
446         }
447         return newVal.toString();
448     }
449 }
450
Popular Tags