KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > compiler > SourceLocatorSAXOutputter


1 /* *****************************************************************************
2  * Parser.java
3 * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.compiler;
11
12 import java.io.*;
13 import java.lang.reflect.Method JavaDoc;
14 import java.lang.reflect.InvocationTargetException JavaDoc;
15 import java.util.*;
16
17 import org.xml.sax.*;
18 import org.xml.sax.Locator JavaDoc;
19 import org.xml.sax.ext.DeclHandler JavaDoc;
20 import org.xml.sax.ext.LexicalHandler JavaDoc;
21 import org.xml.sax.helpers.LocatorImpl JavaDoc;
22 import org.xml.sax.helpers.AttributesImpl JavaDoc;
23 import org.xml.sax.helpers.XMLFilterImpl JavaDoc;
24
25 import org.jdom.*;
26 import org.jdom.Element;
27
28
29 /**
30
31   Generate SAX events from a Laszlo Parser JDOM tree, with filename
32   and linenumber info updated from the ElementWithLocationInfo
33   elements.
34
35   <p>
36   This does the bare minimum needed to feed the RELAXNG
37   validator. It is not namespace aware.
38
39  */

40 public class SourceLocatorSAXOutputter extends XMLFilterImpl JavaDoc{
41     public static final String JavaDoc SOURCEINFO_ATTRIBUTE_NAME = "_lzc_meta_sourceLocation";
42     
43     private LocatorImpl JavaDoc locator = new LocatorImpl JavaDoc();
44
45     /** registered <code>ContentHandler</code> */
46     private ContentHandler contentHandler;
47    
48     /** registered <code>ErrorHandler</code> */
49     private ErrorHandler errorHandler;
50    
51     private boolean writeMetaData = false;
52
53     /**
54      * <p>
55      * This will create a <code>SAXOutputter</code> without any
56      * registered handler. The application is then responsible for
57      * registering them using the <code>setXxxHandler()</code> methods.
58      * </p>
59      */

60     public SourceLocatorSAXOutputter() {
61     }
62
63     /**
64      * <p>
65      * This will create a <code>SAXOutputter</code> with the
66      * specified <code>ContentHandler</code>.
67      * </p>
68      *
69      * @param contentHandler contains <code>ContentHandler</code>
70      * callback methods
71      */

72     public SourceLocatorSAXOutputter(ContentHandler contentHandler) {
73         setContentHandler(contentHandler);
74     }
75
76     /**
77      * <p>
78      * This will set the <code>ContentHandler</code>.
79      * </p>
80      *
81      * @param contentHandler contains <code>ContentHandler</code>
82      * callback methods.
83      */

84     public void setContentHandler(ContentHandler contentHandler) {
85         this.contentHandler = contentHandler;
86     }
87    
88     /**
89      * <p>
90      * Returns the registered <code>ContentHandler</code>.
91      * </p>
92      *
93      * @return the current <code>ContentHandler</code> or
94      * <code>null</code> if none was registered.
95      */

96     public ContentHandler getContentHandler() {
97         return this.contentHandler;
98     }
99
100     /**
101      * <p>
102      * This will set the <code>ErrorHandler</code>.
103      * </p>
104      *
105      * @param errorHandler contains <code>ErrorHandler</code> callback methods.
106      */

107     public void setErrorHandler(ErrorHandler errorHandler) {
108         this.errorHandler = errorHandler;
109     }
110
111     /**
112      * <p>
113      * Return the registered <code>ErrorHandler</code>.
114      * </p>
115      *
116      * @return the current <code>ErrorHandler</code> or
117      * <code>null</code> if none was registered.
118      */

119     public ErrorHandler getErrorHandler() {
120         return this.errorHandler;
121     }
122
123
124     /**
125      * <p>
126      * This will set the state of a SAX feature. We don't support any options right now.
127      */

128     public void setFeature(String JavaDoc name, boolean value)
129                 throws SAXNotRecognizedException, SAXNotSupportedException {
130         // No options supported
131
}
132
133     /**
134      * This will look up the value of a SAX feature.
135      */

136     public boolean getFeature(String JavaDoc name)
137                 throws SAXNotRecognizedException, SAXNotSupportedException {
138         // we don't support any options
139
return false;
140     }
141
142     /**
143      */

144     public void setProperty(String JavaDoc name, Object JavaDoc value)
145                 throws SAXNotRecognizedException, SAXNotSupportedException {
146         // nothing to see here
147
}
148
149     /**
150      * <p>
151      * This will look up the value of a SAX property.
152      * </p>
153      *
154      */

155     public Object JavaDoc getProperty(String JavaDoc name)
156                 throws SAXNotRecognizedException, SAXNotSupportedException {
157         // nothing to see here
158
return null;
159     }
160
161     public void setWriteMetaData(boolean writeMetaData) {
162         this.writeMetaData = writeMetaData;
163     }
164     
165     /**
166      * <p>
167      * This will output the <code>JDOM Document</code>, firing off the
168      * SAX events that have been registered.
169      * </p>
170      *
171      * @param document <code>JDOM Document</code> to output.
172      */

173     public void output(Document document) throws JDOMException {
174         if (document == null) {
175             return;
176         }
177
178         // contentHandler.setDocumentLocator()
179
documentLocator(document);
180
181         // contentHandler.startDocument()
182
_startDocument();
183
184         // Fire DTD events
185
//dtdEvents(document);
186

187         // Handle root element, as well as any root level
188
// processing instructions and CDATA sections
189
Iterator i = document.getContent().iterator();
190         while (i.hasNext()) {
191             Object JavaDoc obj = i.next();
192             if (obj instanceof Element) {
193                 // process root element and its content
194
element(document.getRootElement());
195             }
196             else if (obj instanceof ProcessingInstruction) {
197                 // contentHandler.processingInstruction()
198
processingInstruction((ProcessingInstruction) obj);
199             }
200             else if (obj instanceof CDATA) {
201                 // contentHandler.characters()
202
characters(((CDATA) obj).getText());
203             }
204         }
205        
206         // contentHandler.endDocument()
207
_endDocument();
208     }
209    
210     /**
211      * Copy source linenumber information from the Elements to
212      * make them available to the SAX API.
213      *
214      *
215      * @param document JDOM <code>Document</code>. */

216     private void documentLocator(Document document) {
217         String JavaDoc publicID = null;
218         String JavaDoc systemID = null;
219         DocType docType = document.getDocType();
220         if (docType != null) {
221             publicID = docType.getPublicID();
222             systemID = docType.getSystemID();
223         }
224       
225         locator.setPublicId(publicID);
226         locator.setSystemId(systemID);
227         locator.setLineNumber(1);
228         locator.setColumnNumber(1);
229       
230         contentHandler.setDocumentLocator((Locator JavaDoc) locator);
231     }
232    
233     /**
234      * <p>
235      * This method is always the second method of all callbacks in
236      * all handlers to be invoked (setDocumentLocator is always first).
237      * </p>
238      */

239     private void _startDocument() throws JDOMException {
240         try {
241             contentHandler.startDocument();
242             //contentHandler.startPrefixMapping("ps",
243
//"http://www.psol.com/2001/08/dw/tip");
244
//attributes.addAttribute("","ps","xmlns:ps","CDATA",
245
//"http://www.psol.com/2001/08/dw/tip"); }
246
} catch (SAXException se) {
247             throw new JDOMException("Exception in startDocument", se);
248         }
249     }
250    
251     /**
252      * <p>
253      * Always the last method of all callbacks in all handlers
254      * to be invoked.
255      * </p>
256      */

257     private void _endDocument() throws JDOMException {
258         try {
259             contentHandler.endDocument();
260         }
261         catch (SAXException se) {
262             throw new JDOMException("Exception in endDocument", se);
263         }
264     }
265    
266     /**
267      * <p>
268      * This will invoke the <code>ContentHandler.processingInstruction</code>
269      * callback when a processing instruction is encountered.
270      * </p>
271      *
272      * @param pi <code>ProcessingInstruction</code> containing target and data.
273      */

274     private void processingInstruction(ProcessingInstruction pi)
275                            throws JDOMException {
276         if (pi != null) {
277             String JavaDoc target = pi.getTarget();
278             String JavaDoc data = pi.getData();
279             try {
280                 contentHandler.processingInstruction(target, data);
281             }
282             catch (SAXException se) {
283                 throw new JDOMException(
284                     "Exception in processingInstruction", se);
285             }
286         }
287     }
288    
289     /**
290      * <p>
291      * This will recursively invoke all of the callbacks for a particular
292      * element.
293      * </p>
294      *
295      * @param element <code>Element</code> used in callbacks.
296      */

297     private void element(Element element)
298                            throws JDOMException {
299
300         // Update the document locator
301
Integer JavaDoc lineNumber = Parser.getSourceLocation((ElementWithLocationInfo) element, Parser.LINENO);
302         Integer JavaDoc colNumber = Parser.getSourceLocation((ElementWithLocationInfo) element, Parser.COLNO);
303
304         locator.setSystemId(Parser.getSourcePathname(element));
305         locator.setPublicId(Parser.getSourceMessagePathname(element));
306         locator.setLineNumber(lineNumber.intValue());
307         locator.setColumnNumber(colNumber.intValue());
308         contentHandler.setDocumentLocator((Locator JavaDoc) locator);
309
310         // +++ Check if we need to send a new documentLocator event if
311
// we changed these values?
312

313         // contentHandler.startElement()
314
startElement(element);
315
316         // handle content in the element
317
elementContent(element);
318
319         // contentHandler.endElement()
320
endElement(element);
321
322     }
323
324     /**
325      * <p>
326      * This will invoke the <code>startElement</code> callback
327      * in the <code>ContentHandler</code>.
328      * </p>
329      *
330      * @param element <code>Element</code> used in callbacks.
331      * @param eltNamespaces <code>List</code> of namespaces to declare with
332      * the element or <code>null</code>.
333      */

334     private void startElement(Element element)
335                       throws JDOMException {
336         String JavaDoc namespaceURI = element.getNamespaceURI();
337         String JavaDoc localName = element.getName();
338         String JavaDoc rawName = element.getQualifiedName();
339
340         AttributesImpl JavaDoc atts = new AttributesImpl JavaDoc();
341         List attributes = element.getAttributes();
342         Iterator i = attributes.iterator();
343         while (i.hasNext()) {
344             Attribute a = (Attribute) i.next();
345             atts.addAttribute(a.getNamespaceURI(),
346                               a.getName(),
347                               a.getQualifiedName(),
348                               getAttributeTypeName(a.getAttributeType()),
349                               a.getValue());
350         }
351         if (this.writeMetaData) {
352             // TODO [2003-4-30 ows]: Use a namespace for LZX
353
// metasource information, instead of an obfuscated name.
354
atts.addAttribute("",
355                               SOURCEINFO_ATTRIBUTE_NAME,
356                               SOURCEINFO_ATTRIBUTE_NAME,
357                               "CDATA",
358                               ((ElementWithLocationInfo) element).getSourceLocator().toString()
359                               );
360         }
361         
362         try {
363             contentHandler.startElement(namespaceURI, localName, rawName, atts);
364         }
365         catch (SAXException se) {
366             throw new JDOMException("Exception in startElement", se);
367         }
368     }
369    
370     /**
371      * <p>
372      * This will invoke the <code>endElement</code> callback
373      * in the <code>ContentHandler</code>.
374      * </p>
375      *
376      * @param element <code>Element</code> used in callbacks.
377      */

378     private void endElement(Element element) throws JDOMException {
379         String JavaDoc namespaceURI = element.getNamespaceURI();
380         String JavaDoc localName = element.getName();
381         String JavaDoc rawName = element.getQualifiedName();
382         
383         try {
384             contentHandler.endElement(namespaceURI, localName, rawName);
385         }
386         catch (SAXException se) {
387             throw new JDOMException("Exception in endElement", se);
388         }
389     }
390    
391     /**
392      * <p>
393      * This will invoke the callbacks for the content of an element.
394      * </p>
395      *
396      * @param element <code>Element</code> used in callbacks.
397      */

398     private void elementContent(Element element)
399                       throws JDOMException {
400         List eltContent = element.getContent();
401       
402         boolean empty = eltContent.size() == 0;
403         boolean stringOnly =
404             !empty &&
405             eltContent.size() == 1 &&
406             eltContent.get(0) instanceof Text;
407           
408         if (stringOnly) {
409             // contentHandler.characters()
410
characters(element.getText());
411         }
412         else {
413             Object JavaDoc content = null;
414             for (int i = 0, size = eltContent.size(); i < size; i++) {
415                 content = eltContent.get(i);
416                 if (content instanceof Element) {
417                     element((Element) content);
418                 }
419                 else if (content instanceof Text) {
420                     // contentHandler.characters()
421
characters(((Text) content).getText());
422                 }
423                 else if (content instanceof CDATA) {
424                     // contentHandler.characters()
425
characters(((CDATA) content).getText());
426                 }
427                 else if (content instanceof ProcessingInstruction) {
428                     // contentHandler.processingInstruction()
429
processingInstruction((ProcessingInstruction) content);
430                 }
431             }
432         }
433     }
434     
435     /**
436      * <p>
437      * This will be called for each chunk of character data encountered.
438      * </p>
439      *
440      * @param elementText all text in an element, including whitespace.
441      */

442     private void characters(String JavaDoc elementText) throws JDOMException {
443         char[] c = elementText.toCharArray();
444         try {
445             contentHandler.characters(c, 0, c.length);
446         }
447         catch (SAXException se) {
448             throw new JDOMException("Exception in characters", se);
449         }
450     }
451
452
453     /**
454      * Array to map JDOM attribute type (as entry index) to SAX
455      * attribute type names.
456      */

457     private static final String JavaDoc[] attrTypeToNameMap = new String JavaDoc[] {
458         "CDATA", // Attribute.UNDEFINED_ATTRIBUTE, as per SAX 2.0 spec.
459
"CDATA", // Attribute.CDATA_ATTRIBUTE
460
"ID", // Attribute.ID_ATTRIBUTE
461
"IDREF", // Attribute.IDREF_ATTRIBUTE
462
"IDREFS", // Attribute.IDREFS_ATTRIBUTE
463
"ENTITY", // Attribute.ENTITY_ATTRIBUTE
464
"ENTITIES", // Attribute.ENTITIES_ATTRIBUTE
465
"NMTOKEN", // Attribute.NMTOKEN_ATTRIBUTE
466
"NMTOKENS", // Attribute.NMTOKENS_ATTRIBUTE
467
"NOTATION", // Attribute.NOTATION_ATTRIBUTE
468
"NMTOKEN", // Attribute.ENUMERATED_ATTRIBUTE, as per SAX 2.0 spec.
469
};
470
471     /**
472      * <p>
473      * Returns the SAX 2.0 attribute type string from the type of
474      * a JDOM Attribute.
475      * </p>
476      *
477      * @param type <code>int</code> the type of the JDOM attribute.
478      *
479      * @return <code>String</code> the SAX 2.0 attribute type string.
480      *
481      * @see org.jdom.Attribute#getAttributeType
482      * @see org.xml.sax.Attributes#getType
483      */

484     private String JavaDoc getAttributeTypeName(int type) {
485         if ((type < 0) || (type >= attrTypeToNameMap.length)) {
486             type = Attribute.UNDECLARED_ATTRIBUTE;
487         }
488         return attrTypeToNameMap[type];
489     }
490
491 }
492
Popular Tags