KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2001-2005 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 java.io.IOException JavaDoc;
20
21 import org.apache.xerces.impl.Constants;
22 import org.apache.xerces.impl.XMLErrorReporter;
23 import org.apache.xerces.impl.xs.SchemaSymbols;
24 import org.apache.xerces.impl.xs.XSMessageFormatter;
25 import org.apache.xerces.util.XMLAttributesImpl;
26 import org.apache.xerces.util.XMLChar;
27 import org.apache.xerces.xni.Augmentations;
28 import org.apache.xerces.xni.NamespaceContext;
29 import org.apache.xerces.xni.QName;
30 import org.apache.xerces.xni.XMLAttributes;
31 import org.apache.xerces.xni.XMLLocator;
32 import org.apache.xerces.xni.XMLString;
33 import org.apache.xerces.xni.XNIException;
34 import org.apache.xerces.xni.parser.XMLEntityResolver;
35 import org.apache.xerces.xni.parser.XMLInputSource;
36 import org.apache.xerces.xni.parser.XMLParserConfiguration;
37 import org.w3c.dom.Document JavaDoc;
38
39 /**
40  * @xerces.internal
41  *
42  * @author Rahul Srivastava, Sun Microsystems Inc.
43  * @author Sandy Gao, IBM
44  *
45  * @version $Id: SchemaDOMParser.java,v 1.19 2005/05/30 04:17:11 mrglavas Exp $
46  */

47 public class SchemaDOMParser extends DefaultXMLDocumentHandler {
48     
49     //
50
// Data
51
//
52

53     /** Property identifier: error reporter. */
54     public static final String JavaDoc ERROR_REPORTER =
55         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
56     
57     /** Feature identifier: generate synthetic annotations. */
58     public static final String JavaDoc GENERATE_SYNTHETIC_ANNOTATION =
59         Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
60     
61     // the locator containing line/column information
62
protected XMLLocator fLocator;
63     
64     // namespace context, needed for producing
65
// representations of annotations
66
protected NamespaceContext fNamespaceContext = null;
67     
68     SchemaDOM schemaDOM;
69     
70     XMLParserConfiguration config;
71     
72     //
73
// Constructors
74
//
75

76     /** Default constructor. */
77     public SchemaDOMParser(XMLParserConfiguration config) {
78         this.config = config;
79     }
80     
81     // where an annotation element itself begins
82
// -1 means not in an annotation's scope
83
private int fAnnotationDepth = -1;
84     // Where xs:appinfo or xs:documentation starts;
85
// -1 means not in the scope of either of the two elements.
86
private int fInnerAnnotationDepth = -1;
87     // The current element depth
88
private int fDepth = -1;
89     // Use to report the error when characters are not allowed.
90
XMLErrorReporter fErrorReporter;
91     
92     // fields for generate-synthetic annotations feature
93
private boolean fGenerateSyntheticAnnotation = false;
94     private BooleanStack fHasNonSchemaAttributes = new BooleanStack();
95     private BooleanStack fSawAnnotation = new BooleanStack();
96     private XMLAttributes fEmptyAttr = new XMLAttributesImpl();
97     
98     //
99
// XMLDocumentHandler methods
100
//
101

102     public void startDocument(XMLLocator locator, String JavaDoc encoding,
103             NamespaceContext namespaceContext, Augmentations augs)
104     throws XNIException {
105         fErrorReporter = (XMLErrorReporter)config.getProperty(ERROR_REPORTER);
106         fGenerateSyntheticAnnotation = config.getFeature(GENERATE_SYNTHETIC_ANNOTATION);
107         fHasNonSchemaAttributes.clear();
108         fSawAnnotation.clear();
109         schemaDOM = new SchemaDOM();
110         fAnnotationDepth = -1;
111         fInnerAnnotationDepth = -1;
112         fDepth = -1;
113         fLocator = locator;
114         fNamespaceContext = namespaceContext;
115         schemaDOM.setDocumentURI(locator.getExpandedSystemId());
116     } // startDocument(XMLLocator,String,NamespaceContext, Augmentations)
117

118     /**
119      * The end of the document.
120      * @param augs Additional information that may include infoset augmentations
121      *
122      * @throws XNIException Thrown by handler to signal an error.
123      */

124     public void endDocument(Augmentations augs) throws XNIException {
125         // To debug the DOM created uncomment the line below
126
// schemaDOM.printDOM();
127
} // endDocument()
128

129     
130     /**
131      * A comment.
132      *
133      * @param text The text in the comment.
134      * @param augs Additional information that may include infoset augmentations
135      *
136      * @exception XNIException
137      * Thrown by application to signal an error.
138      */

139     public void comment(XMLString text, Augmentations augs) throws XNIException {
140         if(fAnnotationDepth > -1) {
141             schemaDOM.comment(text);
142         }
143     }
144     
145     /**
146      * A processing instruction. Processing instructions consist of a
147      * target name and, optionally, text data. The data is only meaningful
148      * to the application.
149      * <p>
150      * Typically, a processing instruction's data will contain a series
151      * of pseudo-attributes. These pseudo-attributes follow the form of
152      * element attributes but are <strong>not</strong> parsed or presented
153      * to the application as anything other than text. The application is
154      * responsible for parsing the data.
155      *
156      * @param target The target.
157      * @param data The data or null if none specified.
158      * @param augs Additional information that may include infoset augmentations
159      *
160      * @exception XNIException
161      * Thrown by handler to signal an error.
162      */

163     public void processingInstruction(String JavaDoc target, XMLString data, Augmentations augs)
164     throws XNIException {
165         if(fAnnotationDepth > -1) {
166             schemaDOM.processingInstruction(target, data.toString());
167         }
168     }
169     
170     /**
171      * Character content.
172      *
173      * @param text The content.
174      * @param augs Additional information that may include infoset augmentations
175      *
176      * @exception XNIException
177      * Thrown by handler to signal an error.
178      */

179     public void characters(XMLString text, Augmentations augs) throws XNIException {
180         // when it's not within xs:appinfo or xs:documentation
181
if (fInnerAnnotationDepth == -1 ) {
182             for (int i=text.offset; i<text.offset+text.length; i++) {
183                 // and there is a non-whitespace character
184
if (!XMLChar.isSpace(text.ch[i])) {
185                     // the string we saw: starting from the first non-whitespace character.
186
String JavaDoc txt = new String JavaDoc(text.ch, i, text.length+text.offset-i);
187                     // report an error
188
fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
189                             "s4s-elt-character",
190                             new Object JavaDoc[]{txt},
191                             XMLErrorReporter.SEVERITY_ERROR);
192                     break;
193                 }
194             }
195             // don't call super.characters() when it's not within one of the 2
196
// annotation elements: the traversers ignore them anyway. We can
197
// save time/memory creating the text nodes.
198
}
199         // when it's within either of the 2 elements, characters are allowed
200
// and we need to store them.
201
else {
202             schemaDOM.characters(text);
203         }
204         
205     }
206     
207     
208     /**
209      * The start of an element.
210      *
211      * @param element The name of the element.
212      * @param attributes The element attributes.
213      * @param augs Additional information that may include infoset augmentations
214      *
215      * @exception XNIException
216      * Thrown by handler to signal an error.
217      */

218     public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
219     throws XNIException {
220         
221         fDepth++;
222         // while it is true that non-whitespace character data
223
// may only occur in appInfo or documentation
224
// elements, it's certainly legal for comments and PI's to
225
// occur as children of annotation; we need
226
// to account for these here.
227
if (fAnnotationDepth == -1) {
228             if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
229                     element.localpart == SchemaSymbols.ELT_ANNOTATION) {
230                 if (fGenerateSyntheticAnnotation) {
231                     if (fSawAnnotation.size() > 0) {
232                         fSawAnnotation.pop();
233                     }
234                     fSawAnnotation.push(true);
235                 }
236                 fAnnotationDepth = fDepth;
237                 schemaDOM.startAnnotation(element, attributes, fNamespaceContext);
238             }
239             else if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && fGenerateSyntheticAnnotation) {
240                 fSawAnnotation.push(false);
241                 fHasNonSchemaAttributes.push(hasNonSchemaAttributes(element, attributes));
242             }
243         } else if(fDepth == fAnnotationDepth+1) {
244             fInnerAnnotationDepth = fDepth;
245             schemaDOM.startAnnotationElement(element, attributes);
246         } else {
247             schemaDOM.startAnnotationElement(element, attributes);
248             // avoid falling through; don't call startElement in this case
249
return;
250         }
251         schemaDOM.startElement(element, attributes,
252                 fLocator.getLineNumber(),
253                 fLocator.getColumnNumber(),
254                 fLocator.getCharacterOffset());
255         
256     }
257     
258     
259     /**
260      * An empty element.
261      *
262      * @param element The name of the element.
263      * @param attributes The element attributes.
264      * @param augs Additional information that may include infoset augmentations
265      *
266      * @exception XNIException
267      * Thrown by handler to signal an error.
268      */

269     public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
270     throws XNIException {
271         
272         if (fGenerateSyntheticAnnotation && fAnnotationDepth == -1 &&
273                 element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && element.localpart != SchemaSymbols.ELT_ANNOTATION && hasNonSchemaAttributes(element, attributes)) {
274             
275             schemaDOM.startElement(element, attributes,
276                     fLocator.getLineNumber(),
277                     fLocator.getColumnNumber(),
278                     fLocator.getCharacterOffset());
279             
280             attributes.removeAllAttributes();
281             String JavaDoc schemaPrefix = fNamespaceContext.getPrefix(SchemaSymbols.URI_SCHEMAFORSCHEMA);
282             QName annQName = new QName(schemaPrefix, SchemaSymbols.ELT_ANNOTATION, schemaPrefix + (schemaPrefix.length() == 0?"":":") + SchemaSymbols.ELT_ANNOTATION, SchemaSymbols.URI_SCHEMAFORSCHEMA);
283             schemaDOM.startAnnotation(annQName, attributes, fNamespaceContext);
284             QName elemQName = new QName(schemaPrefix, SchemaSymbols.ELT_DOCUMENTATION, schemaPrefix + (schemaPrefix.length() == 0?"":":") + SchemaSymbols.ELT_DOCUMENTATION, SchemaSymbols.URI_SCHEMAFORSCHEMA);
285             schemaDOM.startAnnotationElement(elemQName, attributes);
286             schemaDOM.characters(new XMLString("SYNTHETIC_ANNOTATION".toCharArray(), 0, 20 ));
287             schemaDOM.endSyntheticAnnotationElement(elemQName, false);
288             schemaDOM.endSyntheticAnnotationElement(annQName, true);
289             
290             schemaDOM.endElement();
291             
292             return;
293         }
294         // the order of events that occurs here is:
295
// schemaDOM.startAnnotation/startAnnotationElement (if applicable)
296
// schemaDOM.emptyElement (basically the same as startElement then endElement)
297
// schemaDOM.endAnnotationElement (if applicable)
298
// the order of events that would occur if this was <element></element>:
299
// schemaDOM.startAnnotation/startAnnotationElement (if applicable)
300
// schemaDOM.startElement
301
// schemaDOM.endAnnotationElement (if applicable)
302
// schemaDOM.endElementElement
303
// Thus, we can see that the order of events isn't the same. However, it doesn't
304
// seem to matter. -- PJM
305
if (fAnnotationDepth == -1) {
306             // this is messed up, but a case to consider:
307
if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
308                     element.localpart == SchemaSymbols.ELT_ANNOTATION) {
309                 schemaDOM.startAnnotation(element, attributes, fNamespaceContext);
310             }
311         } else {
312             schemaDOM.startAnnotationElement(element, attributes);
313         }
314         
315         schemaDOM.emptyElement(element, attributes,
316                 fLocator.getLineNumber(),
317                 fLocator.getColumnNumber(),
318                 fLocator.getCharacterOffset());
319         
320         if (fAnnotationDepth == -1) {
321             // this is messed up, but a case to consider:
322
if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
323                     element.localpart == SchemaSymbols.ELT_ANNOTATION) {
324                 schemaDOM.endAnnotationElement(element, true);
325             }
326         } else {
327             schemaDOM.endAnnotationElement(element, false);
328         }
329     }
330     
331     
332     /**
333      * The end of an element.
334      *
335      * @param element The name of the element.
336      * @param augs Additional information that may include infoset augmentations
337      *
338      * @exception XNIException
339      * Thrown by handler to signal an error.
340      */

341     public void endElement(QName element, Augmentations augs) throws XNIException {
342         
343         // when we reach the endElement of xs:appinfo or xs:documentation,
344
// change fInnerAnnotationDepth to -1
345
if(fAnnotationDepth > -1) {
346             if (fInnerAnnotationDepth == fDepth) {
347                 fInnerAnnotationDepth = -1;
348                 schemaDOM.endAnnotationElement(element, false);
349                 schemaDOM.endElement();
350             } else if (fAnnotationDepth == fDepth) {
351                 fAnnotationDepth = -1;
352                 schemaDOM.endAnnotationElement(element, true);
353                 schemaDOM.endElement();
354             } else { // inside a child of annotation
355
schemaDOM.endAnnotationElement(element, false);
356             }
357         } else { // not in an annotation at all
358
if(element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && fGenerateSyntheticAnnotation) {
359                 boolean value = fHasNonSchemaAttributes.pop();
360                 boolean sawann = fSawAnnotation.pop();
361                 if (value && !sawann) {
362                     String JavaDoc schemaPrefix = fNamespaceContext.getPrefix(SchemaSymbols.URI_SCHEMAFORSCHEMA);
363                     QName annQName = new QName(schemaPrefix, SchemaSymbols.ELT_ANNOTATION, schemaPrefix + (schemaPrefix.length() == 0?"":":") + SchemaSymbols.ELT_ANNOTATION, SchemaSymbols.URI_SCHEMAFORSCHEMA);
364                     schemaDOM.startAnnotation(annQName, fEmptyAttr, fNamespaceContext);
365                     QName elemQName = new QName(schemaPrefix, SchemaSymbols.ELT_DOCUMENTATION, schemaPrefix + (schemaPrefix.length() == 0?"":":") + SchemaSymbols.ELT_DOCUMENTATION, SchemaSymbols.URI_SCHEMAFORSCHEMA);
366                     schemaDOM.startAnnotationElement(elemQName, fEmptyAttr);
367                     schemaDOM.characters(new XMLString("SYNTHETIC_ANNOTATION".toCharArray(), 0, 20 ));
368                     schemaDOM.endSyntheticAnnotationElement(elemQName, false);
369                     schemaDOM.endSyntheticAnnotationElement(annQName, true);
370                 }
371             }
372             schemaDOM.endElement();
373         }
374         fDepth--;
375         
376     }
377     
378     /**
379      * @param attributes
380      * @return
381      */

382     private boolean hasNonSchemaAttributes(QName element, XMLAttributes attributes) {
383         final int length = attributes.getLength();
384         for (int i = 0; i < length; ++i) {
385             String JavaDoc uri = attributes.getURI(i);
386             if (uri != null && uri != SchemaSymbols.URI_SCHEMAFORSCHEMA &&
387                     uri != NamespaceContext.XMLNS_URI &&
388                     !(uri == NamespaceContext.XML_URI &&
389                             attributes.getQName(i) == SchemaSymbols.ATT_XML_LANG && element.localpart == SchemaSymbols.ELT_SCHEMA)) {
390                 return true;
391             }
392         }
393         return false;
394     }
395     
396     /**
397      * Ignorable whitespace. For this method to be called, the document
398      * source must have some way of determining that the text containing
399      * only whitespace characters should be considered ignorable. For
400      * example, the validator can determine if a length of whitespace
401      * characters in the document are ignorable based on the element
402      * content model.
403      *
404      * @param text The ignorable whitespace.
405      * @param augs Additional information that may include infoset augmentations
406      *
407      * @exception XNIException
408      * Thrown by handler to signal an error.
409      */

410     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
411         // unlikely to be called, but you never know...
412
if (fAnnotationDepth != -1 ) {
413             schemaDOM.characters(text);
414         }
415     }
416     
417     /**
418      * The start of a CDATA section.
419      *
420      * @param augs Additional information that may include infoset augmentations
421      *
422      * @exception XNIException
423      * Thrown by handler to signal an error.
424      */

425     public void startCDATA(Augmentations augs) throws XNIException {
426         // only deal with CDATA boundaries within an annotation.
427
if (fAnnotationDepth != -1) {
428             schemaDOM.startAnnotationCDATA();
429         }
430     }
431     
432     /**
433      * The end of a CDATA section.
434      *
435      * @param augs Additional information that may include infoset augmentations
436      *
437      * @exception XNIException
438      * Thrown by handler to signal an error.
439      */

440     public void endCDATA(Augmentations augs) throws XNIException {
441         // only deal with CDATA boundaries within an annotation.
442
if (fAnnotationDepth != -1) {
443             schemaDOM.endAnnotationCDATA();
444         }
445     }
446     
447     
448     //
449
// other methods
450
//
451

452     /**
453      * Returns the DOM document object.
454      */

455     public Document JavaDoc getDocument() {
456         return schemaDOM;
457     }
458     
459     /**
460      * Delegates to SchemaParsingConfig.setFeature
461      * @param featureId
462      * @param state
463      */

464     public void setFeature(String JavaDoc featureId, boolean state){
465         config.setFeature(featureId, state);
466     }
467     
468     /**
469      * Delegates to SchemaParsingConfig.getFeature
470      * @param featureId
471      * @return boolean
472      */

473     public boolean getFeature(String JavaDoc featureId){
474         return config.getFeature(featureId);
475     }
476     
477     /**
478      * Delegates to SchemaParsingConfig.setProperty.
479      * @param propertyId
480      * @param value
481      */

482     public void setProperty(String JavaDoc propertyId, Object JavaDoc value){
483         config.setProperty(propertyId, value);
484     }
485     
486     /**
487      * Delegates to SchemaParsingConfig.getProperty.
488      * @param propertyId
489      * @return Object
490      */

491     public Object JavaDoc getProperty(String JavaDoc propertyId){
492         return config.getProperty(propertyId);
493     }
494     
495     /**
496      * Delegates to SchemaParsingConfig.setEntityResolver.
497      * @param er XMLEntityResolver
498      */

499     public void setEntityResolver(XMLEntityResolver er) {
500         config.setEntityResolver(er);
501     }
502     
503     /**
504      * Delegates parsing to SchemaParsingConfig
505      *
506      * @param inputSource
507      * @throws IOException
508      */

509     public void parse(XMLInputSource inputSource) throws IOException JavaDoc {
510         config.parse(inputSource);
511     }
512     
513     /**
514      * Gets the document from SchemaParsingConfig
515      * @return Document
516      */

517     public Document JavaDoc getDocument2() {
518         return ((SchemaParsingConfig)config).getDocument();
519     }
520     
521     /**
522      * Reset SchemaParsingConfig
523      */

524     public void reset() {
525         ((SchemaParsingConfig)config).reset();
526     }
527     
528     /**
529      * ResetNodePool on SchemaParsingConfig
530      */

531     public void resetNodePool() {
532         ((SchemaParsingConfig)config).resetNodePool();
533     }
534     
535     /**
536      * A simple boolean based stack.
537      *
538      * @xerces.internal
539      */

540     private static final class BooleanStack {
541
542         //
543
// Data
544
//
545

546         /** Stack depth. */
547         private int fDepth;
548
549         /** Stack data. */
550         private boolean[] fData;
551         
552         //
553
// Constructor
554
//
555

556         public BooleanStack () {}
557
558         //
559
// Public methods
560
//
561

562         /** Returns the size of the stack. */
563         public int size() {
564             return fDepth;
565         }
566
567         /** Pushes a value onto the stack. */
568         public void push(boolean value) {
569             ensureCapacity(fDepth + 1);
570             fData[fDepth++] = value;
571         }
572
573         /** Pops a value off of the stack. */
574         public boolean pop() {
575             return fData[--fDepth];
576         }
577
578         /** Clears the stack. */
579         public void clear() {
580             fDepth = 0;
581         }
582
583         //
584
// Private methods
585
//
586

587         /** Ensures capacity. */
588         private void ensureCapacity(int size) {
589             if (fData == null) {
590                 fData = new boolean[32];
591             }
592             else if (fData.length <= size) {
593                 boolean[] newdata = new boolean[fData.length * 2];
594                 System.arraycopy(fData, 0, newdata, 0, fData.length);
595                 fData = newdata;
596             }
597         }
598     }
599 }
600
Popular Tags