KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > StaxBridge


1
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.style.StandardNames;
4 import net.sf.saxon.tinytree.CharSlice;
5 import net.sf.saxon.event.*;
6 import net.sf.saxon.expr.ExpressionLocation;
7 import net.sf.saxon.om.*;
8 import net.sf.saxon.pull.PullProvider;
9 import net.sf.saxon.pull.PullPushCopier;
10 import net.sf.saxon.trans.DynamicError;
11 import net.sf.saxon.trans.SaxonErrorCode;
12 import net.sf.saxon.trans.XPathException;
13 import net.sf.saxon.value.AtomicValue;
14
15 import javax.xml.stream.*;
16 import javax.xml.transform.SourceLocator JavaDoc;
17 import javax.xml.transform.TransformerException JavaDoc;
18 import java.io.File JavaDoc;
19 import java.io.FileInputStream JavaDoc;
20 import java.io.FileOutputStream JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.util.Properties JavaDoc;
23
24 /**
25  * This class implements the Saxon PullProvider API on top of a standard StAX parser
26  * (or any other StAX implementation)
27  */

28
29 public class StaxBridge implements PullProvider, SaxonLocator {
30
31     private XMLStreamReader reader;
32     private StaxAttributes attributes = new StaxAttributes();
33     private StaxNamespaces namespaces = new StaxNamespaces();
34     private PipelineConfiguration pipe;
35     int currentEvent = START_OF_INPUT;
36     int depth = 0;
37
38     public StaxBridge() {
39
40     }
41
42     public void setInputStream(String JavaDoc systemId, InputStream JavaDoc inputStream) throws XPathException {
43         try {
44             XMLInputFactory factory = XMLInputFactory.newInstance();
45             factory.setXMLReporter(new StaxErrorReporter());
46             XMLStreamReader reader = factory.createXMLStreamReader(systemId, inputStream);
47             this.reader = reader;
48         } catch (XMLStreamException e) {
49             throw new DynamicError(e);
50         }
51     }
52
53     /**
54      * Set configuration information. This must only be called before any events
55      * have been read.
56      */

57
58     public void setPipelineConfiguration(PipelineConfiguration pipe) {
59         this.pipe = new PipelineConfiguration(pipe);
60         this.pipe.setLocationProvider(this);
61     }
62
63     /**
64      * Get configuration information.
65      */

66
67     public PipelineConfiguration getPipelineConfiguration() {
68         return pipe;
69     }
70
71     /**
72      * Get the name pool
73      */

74
75     public NamePool getNamePool() {
76         return pipe.getConfiguration().getNamePool();
77     }
78
79     /**
80      * Get the next event
81      *
82      * @return an integer code indicating the type of event. The code
83      * {@link END_OF_INPUT} is returned at the end of the sequence.
84      */

85
86     public int next() throws XPathException {
87         if (currentEvent == START_OF_INPUT) {
88             // StAX isn't reporting START_DOCUMENT so we supply it ourselves
89
currentEvent = START_DOCUMENT;
90             return currentEvent;
91         }
92         if (currentEvent == END_OF_INPUT || currentEvent == END_DOCUMENT) {
93             try {
94                 reader.close();
95             } catch (XMLStreamException e) {
96                 //
97
}
98             return END_OF_INPUT;
99         }
100         try {
101             if (reader.hasNext()) {
102                 int event = reader.next();
103                 //System.err.println("Read event " + event);
104
currentEvent = translate(event);
105             } else {
106                 currentEvent = END_OF_INPUT;
107             }
108         } catch (XMLStreamException e) {
109             String JavaDoc message = e.getMessage();
110             // Following code recognizes the messages produced by the Sun Zephyr parser
111
if (message.startsWith("ParseError at")) {
112                 int c = message.indexOf("\nMessage: ");
113                 if (c > 0) {
114                     message = message.substring(c+10);
115                 }
116             }
117             DynamicError err = new DynamicError("Error reported by XML parser: " + message);
118             err.setErrorCode(SaxonErrorCode.SXXP0003);
119             err.setLocator(translateLocation(e.getLocation()));
120             throw err;
121         }
122         return currentEvent;
123     }
124
125
126     private int translate(int event) throws XPathException {
127             //System.err.println("EVENT " + event);
128
switch (event) {
129                 case XMLStreamConstants.ATTRIBUTE:
130                     return ATTRIBUTE;
131                 case XMLStreamConstants.CDATA:
132                     return TEXT;
133                 case XMLStreamConstants.CHARACTERS:
134                     if (depth == 0) {
135                         return next();
136                     } else {
137 // System.err.println("TEXT[" + new String(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()) + "]");
138
// System.err.println(" ARRAY length " + reader.getTextCharacters().length + "[" + new String(reader.getTextCharacters(), 0, reader.getTextStart() + reader.getTextLength()) + "]");
139
// System.err.println(" START: " + reader.getTextStart() + " LENGTH " + reader.getTextLength());
140
return TEXT;
141                     }
142                 case XMLStreamConstants.COMMENT:
143                     return COMMENT;
144                 case XMLStreamConstants.DTD:
145                     return next();
146                 case XMLStreamConstants.END_DOCUMENT:
147                     return END_DOCUMENT;
148                 case XMLStreamConstants.END_ELEMENT:
149                     depth--;
150                     return END_ELEMENT;
151                 case XMLStreamConstants.ENTITY_DECLARATION:
152                     return next();
153                 case XMLStreamConstants.ENTITY_REFERENCE:
154                     return next();
155                 case XMLStreamConstants.NAMESPACE:
156                     return NAMESPACE;
157                 case XMLStreamConstants.NOTATION_DECLARATION:
158                     return next();
159                 case XMLStreamConstants.PROCESSING_INSTRUCTION:
160                     return PROCESSING_INSTRUCTION;
161                 case XMLStreamConstants.SPACE:
162                     if (depth == 0) {
163                         return next();
164                     } else {
165                         return TEXT;
166                     }
167                 case XMLStreamConstants.START_DOCUMENT:
168                     return next(); // we supplied the START_DOCUMENT ourselves
169
//return START_DOCUMENT;
170
case XMLStreamConstants.START_ELEMENT:
171                     depth++;
172                     return START_ELEMENT;
173                 default:
174                     throw new IllegalStateException JavaDoc("Unknown StAX event " + event);
175
176
177             }
178     }
179
180     /**
181      * Get the event most recently returned by next(), or by other calls that change
182      * the position, for example getStringValue() and skipToMatchingEnd(). This
183      * method does not change the position of the PullProvider.
184      *
185      * @return the current event
186      */

187
188     public int current() {
189         return currentEvent;
190     }
191
192     /**
193      * Get the attributes associated with the current element. This method must
194      * be called only after a START_ELEMENT event has been notified. The contents
195      * of the returned AttributeCollection are guaranteed to remain unchanged
196      * until the next START_ELEMENT event, but may be modified thereafter. The object
197      * should not be modified by the client.
198      * <p/>
199      * <p>Attributes may be read before or after reading the namespaces of an element,
200      * but must not be read after the first child node has been read, or after calling
201      * one of the methods skipToEnd(), getStringValue(), or getTypedValue().</p>
202      *
203      * @return an AttributeCollection representing the attributes of the element
204      * that has just been notified.
205      */

206
207     public AttributeCollection getAttributes() throws XPathException {
208         return attributes;
209     }
210
211     /**
212      * Get the namespace declarations associated with the current element. This method must
213      * be called only after a START_ELEMENT event has been notified. In the case of a top-level
214      * START_ELEMENT event (that is, an element that either has no parent node, or whose parent
215      * is not included in the sequence being read), the NamespaceDeclarations object returned
216      * will contain a namespace declaration for each namespace that is in-scope for this element
217      * node. In the case of a non-top-level element, the NamespaceDeclarations will contain
218      * a set of namespace declarations and undeclarations, representing the differences between
219      * this element and its parent.
220      * <p/>
221      * <p>It is permissible for this method to return namespace declarations that are redundant.</p>
222      * <p/>
223      * <p>The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT
224      * event, but may then be overwritten. The object should not be modified by the client.</p>
225      * <p/>
226      * <p>Namespaces may be read before or after reading the attributes of an element,
227      * but must not be read after the first child node has been read, or after calling
228      * one of the methods skipToEnd(), getStringValue(), or getTypedValue().</p>*
229      */

230
231     public NamespaceDeclarations getNamespaceDeclarations() throws XPathException {
232         return namespaces;
233     }
234
235     /**
236      * Skip the current subtree. This method may be called only immediately after
237      * a START_DOCUMENT or START_ELEMENT event. This call returns the matching
238      * END_DOCUMENT or END_ELEMENT event; the next call on next() will return
239      * the event following the END_DOCUMENT or END_ELEMENT.
240      */

241
242     public int skipToMatchingEnd() throws XPathException {
243         switch (currentEvent) {
244             case START_DOCUMENT:
245                 currentEvent = END_DOCUMENT;
246                 return currentEvent;
247             case START_ELEMENT:
248                 try {
249                     int skipDepth = 0;
250                     while (reader.hasNext()) {
251                         int event = reader.next();
252                         if (event == XMLStreamConstants.START_ELEMENT) {
253                             skipDepth++;
254                         } else if (event == XMLStreamConstants.END_ELEMENT) {
255                             if (skipDepth-- == 0) {
256                                 currentEvent = END_ELEMENT;
257                                 return currentEvent;
258                             }
259                         }
260                     }
261                 } catch (XMLStreamException e) {
262                     throw new DynamicError(e);
263                 }
264                 throw new IllegalStateException JavaDoc(
265                         "Element start has no matching element end");
266             default:
267                 throw new IllegalStateException JavaDoc(
268                         "Cannot call skipToMatchingEnd() except when at start of element or document");
269
270         }
271     }
272
273     /**
274      * Close the event reader. This indicates that no further events are required.
275      * It is not necessary to close an event reader after {@link END_OF_INPUT} has
276      * been reported, but it is recommended to close it if reading terminates
277      * prematurely. Once an event reader has been closed, the effect of further
278      * calls on next() is undefined.
279      */

280
281     public void close() {
282         try {
283             reader.close();
284         } catch (XMLStreamException e) {
285             //
286
}
287     }
288
289     /**
290      * Get the nameCode identifying the name of the current node. This method
291      * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION},
292      * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations,
293      * including this one, it can also be used after {@link #END_ELEMENT}.
294      * If called at other times, the result is undefined and may result in an IllegalStateException.
295      * If called when the current node is an unnamed namespace node (a node representing the default namespace)
296      * the returned value is -1.
297      *
298      * @return the nameCode. The nameCode can be used to obtain the prefix, local name,
299      * and namespace URI from the name pool.
300      */

301
302     public int getNameCode() {
303         if (currentEvent == START_ELEMENT || currentEvent == END_ELEMENT) {
304             String JavaDoc local = reader.getLocalName();
305             String JavaDoc uri = reader.getNamespaceURI();
306             String JavaDoc prefix = reader.getPrefix();
307             if (prefix==null) {
308                 prefix = "";
309             }
310             if (uri == null) {
311                 uri = "";
312             }
313             return getNamePool().allocate(prefix, uri, local);
314         } else if (currentEvent == PROCESSING_INSTRUCTION) {
315             String JavaDoc local = reader.getPITarget();
316             return getNamePool().allocate("", "", local);
317         } else {
318             throw new IllegalStateException JavaDoc();
319         }
320     }
321
322     /**
323      * Get the fingerprint of the name of the element. This is similar to the nameCode, except that
324      * it does not contain any information about the prefix: so two elements with the same fingerprint
325      * have the same name, excluding prefix. This method
326      * can be used after the {@link START_ELEMENT}, {@link PROCESSING_INSTRUCTION},
327      * {@link ATTRIBUTE}, or {@link NAMESPACE} events.
328      * If called at other times, the result is undefined and may result in an IllegalStateException.
329      * If called when the current node is an unnamed namespace node (a node representing the default namespace)
330      * the returned value is -1.
331      *
332      * @return the fingerprint. The fingerprint can be used to obtain the local name
333      * and namespace URI from the name pool.
334      */

335
336     public int getFingerprint() {
337         int nc = getNameCode();
338         if (nc == -1) {
339             return -1;
340         } else {
341             return nc & NamePool.FP_MASK;
342         }
343     }
344
345     /**
346      * Get the string value of the current element, text node, processing-instruction,
347      * or top-level attribute or namespace node, or atomic value.
348      * <p/>
349      * <p>In other situations the result is undefined and may result in an IllegalStateException.</p>
350      * <p/>
351      * <p>If the most recent event was a {@link START_ELEMENT}, this method causes the content
352      * of the element to be read. The current event on completion of this method will be the
353      * corresponding {@link END_ELEMENT}. The next call of next() will return the event following
354      * the END_ELEMENT event.</p>
355      *
356      * @return the String Value of the node in question, defined according to the rules in the
357      * XPath data model.
358      */

359
360     public CharSequence JavaDoc getStringValue() throws XPathException {
361         switch (currentEvent) {
362             case TEXT:
363             case COMMENT:
364                 //return reader.getText();
365
return new CharSlice(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
366                 // -- the latter is more efficient but doesn't work for entity references
367
case PROCESSING_INSTRUCTION:
368                 String JavaDoc s = reader.getPIData();
369                 // The BEA parser includes the separator space in the value,
370
// which isn't part of the XPath data model
371
if (s.length() > 0 && s.charAt(0) == ' ') {
372                     return s.substring(1);
373                 } else {
374                     return s;
375                 }
376             case START_ELEMENT:
377                 FastStringBuffer combinedText = null;
378                 try {
379                     int depth = 0;
380                     while (reader.hasNext()) {
381                         int event = reader.next();
382                         if (event == XMLStreamConstants.CHARACTERS) {
383                             if (combinedText == null) {
384                                 combinedText = new FastStringBuffer(1024);
385                             }
386                             combinedText.append(
387                                         reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
388                         } else if (event == XMLStreamConstants.START_ELEMENT) {
389                             depth++;
390                         } else if (event == XMLStreamConstants.END_ELEMENT) {
391                             if (depth-- == 0) {
392                                 currentEvent = END_ELEMENT;
393                                 if (combinedText != null) {
394                                     return combinedText.condense();
395                                 } else {
396                                     return "";
397                                 }
398                             }
399                         }
400                     }
401                 } catch (XMLStreamException e) {
402                     throw new DynamicError(e);
403                 }
404             default:
405                 throw new IllegalStateException JavaDoc("getStringValue() called when current event is " + currentEvent);
406
407         }
408     }
409
410     /**
411      * Get an atomic value. This call may be used only when the last event reported was
412      * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains
413      * a free-standing atomic value; it is never used when reading the content of a node.
414      */

415
416     public AtomicValue getAtomicValue() {
417         throw new IllegalStateException JavaDoc();
418     }
419
420     /**
421      * Get the location of the current event. The location is returned as an integer.
422      * This is a value that can be passed to the {@link net.sf.saxon.event.LocationProvider}
423      * held by the {@link net.sf.saxon.event.PipelineConfiguration} to get real location information (line number,
424      * system Id, etc). For an event stream representing a real document, the location information
425      * should identify the location in the lexical XML source. For a constructed document, it should
426      * identify the location in the query or stylesheet that caused the node to be created.
427      * A value of zero can be returned if no location information is available.
428      */

429
430     public int getLocationId() {
431         return 0; //To change body of implemented methods use File | Settings | File Templates.
432
}
433
434     /**
435      * Get the type annotation of the current attribute or element node, or atomic value.
436      * The result of this method is undefined unless the most recent event was START_ELEMENT,
437      * ATTRIBUTE, or ATOMIC_VALUE.
438      *
439      * @return the type annotation. This code is the fingerprint of a type name, which may be
440      * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration.
441      */

442
443     public int getTypeAnnotation() {
444         return -1;
445     }
446
447     /**
448      * Get the location of the current event.
449      * For an event stream representing a real document, the location information
450      * should identify the location in the lexical XML source. For a constructed document, it should
451      * identify the location in the query or stylesheet that caused the node to be created.
452      * A value of null can be returned if no location information is available.
453      */

454
455     public SourceLocator JavaDoc getSourceLocator() {
456         return translateLocation(reader.getLocation());
457     }
458
459     /**
460      * Translate a StAX Location object to a Saxon Locator
461      */

462
463     private ExpressionLocation translateLocation(Location location) {
464         ExpressionLocation loc = new ExpressionLocation();
465         loc.setLineNumber(location.getLineNumber());
466         loc.setColumnNumber(location.getColumnNumber());
467         loc.setSystemId(location.getSystemId());
468         loc.setPublicId(location.getPublicId());
469         return loc;
470     }
471
472     /**
473      * Implement the Saxon AttributeCollection interface over the StAX interface.
474      */

475
476     private class StaxAttributes implements AttributeCollection {
477
478         /**
479          * Set the location provider. This must be set if the methods getSystemId() and getLineNumber()
480          * are to be used to get location information for an attribute.
481          */

482
483         public void setLocationProvider(LocationProvider provider) {
484
485         }
486
487         /**
488          * Return the number of attributes in the list.
489          *
490          * @return The number of attributes in the list.
491          */

492
493         public int getLength() {
494             return reader.getAttributeCount();
495         }
496
497         /**
498          * Get the namecode of an attribute (by position).
499          *
500          * @param index The position of the attribute in the list.
501          * @return The namecode of the attribute
502          */

503
504         public int getNameCode(int index) {
505             String JavaDoc local = reader.getAttributeLocalName(index);
506             String JavaDoc uri = reader.getAttributeNamespace(index);
507             String JavaDoc prefix = reader.getAttributePrefix(index);
508             if (prefix == null) {
509                 prefix = "";
510             }
511             if (uri == null) {
512                 uri = "";
513             }
514             return getNamePool().allocate(prefix, uri, local);
515             // TODO: the JavaDoc for XMLStreamReader doesn't say what happens if index is out of range.
516
// The interface definition for PullProvider states that null/-1 is returned.
517
}
518
519         /**
520          * Get the type annotation of an attribute (by position).
521          *
522          * @param index The position of the attribute in the list.
523          * @return The type annotation, as the fingerprint of the type name.
524          * The bit {@link net.sf.saxon.om.NodeInfo.IS_DTD_TYPE} represents a DTD-derived type.
525          */

526
527         public int getTypeAnnotation(int index) {
528             if (isId(index)) {
529                 return StandardNames.XS_ID | NodeInfo.IS_DTD_TYPE;
530             }
531             return StandardNames.XDT_UNTYPED_ATOMIC;
532         }
533                                           
534         /**
535          * Get the locationID of an attribute (by position)
536          *
537          * @param index The position of the attribute in the list.
538          * @return The location identifier of the attribute. This can be supplied
539          * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the
540          * actual system identifier and line number of the relevant location
541          */

542
543         public int getLocationId(int index) {
544             return 0;
545         }
546
547         /**
548          * Get the systemId part of the location of an attribute, at a given index.
549          * <p/>
550          * <p>Attribute location information is not available from a SAX parser, so this method
551          * is not useful for getting the location of an attribute in a source document. However,
552          * in a Saxon result document, the location information represents the location in the
553          * stylesheet of the instruction used to generate this attribute, which is useful for
554          * debugging.</p>
555          *
556          * @param index the required attribute
557          * @return the systemId of the location of the attribute
558          */

559
560         public String JavaDoc getSystemId(int index) {
561             return reader.getLocation().getSystemId();
562         }
563
564         /**
565          * Get the line number part of the location of an attribute, at a given index.
566          * <p/>
567          * <p>Attribute location information is not available from a SAX parser, so this method
568          * is not useful for getting the location of an attribute in a source document. However,
569          * in a Saxon result document, the location information represents the location in the
570          * stylesheet of the instruction used to generate this attribute, which is useful for
571          * debugging.</p>
572          *
573          * @param index the required attribute
574          * @return the line number of the location of the attribute
575          */

576
577         public int getLineNumber(int index) {
578             return reader.getLocation().getLineNumber();
579         }
580
581         /**
582          * Get the properties of an attribute (by position)
583          *
584          * @param index The position of the attribute in the list.
585          * @return The properties of the attribute. This is a set
586          * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The
587          * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE},
588          * which indicates an attribute that was added to an element as a result of schema validation.
589          */

590
591         public int getProperties(int index) {
592             int properties = 0;
593             if (!reader.isAttributeSpecified(index)) {
594                 properties |= ReceiverOptions.DEFAULTED_ATTRIBUTE;
595             }
596             return properties;
597         }
598
599         /**
600          * Get the prefix of the name of an attribute (by position).
601          *
602          * @param index The position of the attribute in the list.
603          * @return The prefix of the attribute name as a string, or null if there
604          * is no attribute at that position. Returns "" for an attribute that
605          * has no prefix.
606          */

607
608         public String JavaDoc getPrefix(int index) {
609             return getNamePool().getPrefix(getNameCode(index));
610         }
611
612         /**
613          * Get the lexical QName of an attribute (by position).
614          *
615          * @param index The position of the attribute in the list.
616          * @return The lexical QName of the attribute as a string, or null if there
617          * is no attribute at that position.
618          */

619
620         public String JavaDoc getQName(int index) {
621             return getNamePool().getDisplayName(getNameCode(index));
622         }
623
624         /**
625          * Get the local name of an attribute (by position).
626          *
627          * @param index The position of the attribute in the list.
628          * @return The local name of the attribute as a string, or null if there
629          * is no attribute at that position.
630          */

631
632         public String JavaDoc getLocalName(int index) {
633             return reader.getAttributeLocalName(index);
634         }
635
636         /**
637          * Get the namespace URI of an attribute (by position).
638          *
639          * @param index The position of the attribute in the list.
640          * @return The local name of the attribute as a string, or null if there
641          * is no attribute at that position.
642          */

643
644         public String JavaDoc getURI(int index) {
645             return reader.getAttributeNamespace(index);
646         }
647
648         /**
649          * Get the index of an attribute (by name).
650          *
651          * @param uri The namespace uri of the attribute.
652          * @param localname The local name of the attribute.
653          * @return The index position of the attribute
654          */

655
656         public int getIndex(String JavaDoc uri, String JavaDoc localname) {
657             for (int i=0; i<getLength(); i++) {
658                 if (getLocalName(i) == localname && getURI(i) == uri) {
659                     return i;
660                 }
661             }
662             return -1;
663         }
664
665         /**
666          * Get the index, given the fingerprint
667          */

668
669         public int getIndexByFingerprint(int fingerprint) {
670             return getIndex(getNamePool().getURI(fingerprint), getNamePool().getLocalName(fingerprint));
671         }
672
673         /**
674          * Get the attribute value using its fingerprint
675          */

676
677         public String JavaDoc getValueByFingerprint(int fingerprint) {
678             return getValue(getIndexByFingerprint(fingerprint));
679         }
680
681         /**
682          * Get the value of an attribute (by name).
683          *
684          * @param uri The namespace uri of the attribute.
685          * @param localname The local name of the attribute.
686          * @return The index position of the attribute
687          */

688
689         public String JavaDoc getValue(String JavaDoc uri, String JavaDoc localname) {
690             return reader.getAttributeValue(uri, localname);
691         }
692
693         /**
694          * Get the value of an attribute (by position).
695          *
696          * @param index The position of the attribute in the list.
697          * @return The attribute value as a string, or null if
698          * there is no attribute at that position.
699          */

700
701         public String JavaDoc getValue(int index) {
702             return reader.getAttributeValue(index);
703         }
704
705         /**
706          * Determine whether a given attribute has the is-ID property set
707          */

708
709         public boolean isId(int index) {
710             return reader.getAttributeType(index).equals("ID");
711         }
712     }
713
714     public class StaxNamespaces implements NamespaceDeclarations {
715         /**
716          * Get the number of declarations (and undeclarations) in this list.
717          */

718
719         public int getLength() {
720             return reader.getNamespaceCount();
721         }
722
723         /**
724          * Get the prefix of the n'th declaration (or undeclaration) in the list,
725          * counting from zero.
726          *
727          * @param index the index identifying which declaration is required.
728          * @return the namespace prefix. For a declaration or undeclaration of the
729          * default namespace, this is the zero-length string.
730          * @throws IndexOutOfBoundsException if the index is out of range.
731          */

732
733         public String JavaDoc getPrefix(int index) {
734             String JavaDoc p = reader.getNamespacePrefix(index);
735             return (p==null ? "" : p);
736         }
737
738         /**
739          * Get the namespace URI of the n'th declaration (or undeclaration) in the list,
740          * counting from zero.
741          *
742          * @param index the index identifying which declaration is required.
743          * @return the namespace URI. For a namespace undeclaration, this is the
744          * zero-length string.
745          * @throws IndexOutOfBoundsException if the index is out of range.
746          */

747
748         public String JavaDoc getURI(int index) {
749             String JavaDoc uri = reader.getNamespaceURI(index);
750             return (uri==null ? "" : uri);
751         }
752
753         /**
754          * Get the n'th declaration in the list in the form of a namespace code. Namespace
755          * codes can be translated into a prefix and URI by means of methods in the
756          * NamePool
757          *
758          * @param index the index identifying which declaration is required.
759          * @return the namespace code. This is an integer whose upper half indicates
760          * the prefix (0 represents the default namespace), and whose lower half indicates
761          * the URI (0 represents an undeclaration).
762          * @throws IndexOutOfBoundsException if the index is out of range.
763          * @see net.sf.saxon.om.NamePool#getPrefixFromNamespaceCode(int)
764          * @see net.sf.saxon.om.NamePool#getURIFromNamespaceCode(int)
765          */

766
767         public int getNamespaceCode(int index) {
768             return getNamePool().allocateNamespaceCode(getPrefix(index), getURI(index));
769         }
770
771         /**
772          * Get all the namespace codes, as an array.
773          *
774          * @param buffer a sacrificial array that the method is free to use to contain the result.
775          * May be null.
776          * @return an integer array containing namespace codes. The array may be filled completely
777          * with namespace codes, or it may be incompletely filled, in which case a -1 integer acts
778          * as a terminator.
779          */

780
781         public int[] getNamespaceCodes(int[] buffer) {
782             if (buffer.length < getLength()) {
783                 buffer = new int[getLength()];
784             }
785             for (int i=0; i<getLength(); i++) {
786                 buffer[i] = getNamespaceCode(i);
787             }
788             return buffer;
789         }
790
791     }
792
793     /**
794      * Return the public identifier for the current document event.
795      * <p/>
796      * <p>The return value is the public identifier of the document
797      * entity or of the external parsed entity in which the markup
798      * triggering the event appears.</p>
799      *
800      * @return A string containing the public identifier, or
801      * null if none is available.
802      * @see #getSystemId
803      */

804     public String JavaDoc getPublicId() {
805         return reader.getLocation().getPublicId();
806     }
807
808     /**
809      * Return the system identifier for the current document event.
810      * <p/>
811      * <p>The return value is the system identifier of the document
812      * entity or of the external parsed entity in which the markup
813      * triggering the event appears.</p>
814      * <p/>
815      * <p>If the system identifier is a URL, the parser must resolve it
816      * fully before passing it to the application. For example, a file
817      * name must always be provided as a <em>file:...</em> URL, and other
818      * kinds of relative URI are also resolved against their bases.</p>
819      *
820      * @return A string containing the system identifier, or null
821      * if none is available.
822      * @see #getPublicId
823      */

824     public String JavaDoc getSystemId() {
825         return reader.getLocation().getSystemId();
826     }
827
828     /**
829      * Return the line number where the current document event ends.
830      * Lines are delimited by line ends, which are defined in
831      * the XML specification.
832      * <p/>
833      * <p><strong>Warning:</strong> The return value from the method
834      * is intended only as an approximation for the sake of diagnostics;
835      * it is not intended to provide sufficient information
836      * to edit the character content of the original XML document.
837      * In some cases, these "line" numbers match what would be displayed
838      * as columns, and in others they may not match the source text
839      * due to internal entity expansion. </p>
840      * <p/>
841      * <p>The return value is an approximation of the line number
842      * in the document entity or external parsed entity where the
843      * markup triggering the event appears.</p>
844      * <p/>
845      * <p>If possible, the SAX driver should provide the line position
846      * of the first character after the text associated with the document
847      * event. The first line is line 1.</p>
848      *
849      * @return The line number, or -1 if none is available.
850      * @see #getColumnNumber
851      */

852     public int getLineNumber() {
853         return reader.getLocation().getLineNumber();
854     }
855
856     /**
857      * Return the column number where the current document event ends.
858      * This is one-based number of Java <code>char</code> values since
859      * the last line end.
860      * <p/>
861      * <p><strong>Warning:</strong> The return value from the method
862      * is intended only as an approximation for the sake of diagnostics;
863      * it is not intended to provide sufficient information
864      * to edit the character content of the original XML document.
865      * For example, when lines contain combining character sequences, wide
866      * characters, surrogate pairs, or bi-directional text, the value may
867      * not correspond to the column in a text editor's display. </p>
868      * <p/>
869      * <p>The return value is an approximation of the column number
870      * in the document entity or external parsed entity where the
871      * markup triggering the event appears.</p>
872      * <p/>
873      * <p>If possible, the SAX driver should provide the line position
874      * of the first character after the text associated with the document
875      * event. The first column in each line is column 1.</p>
876      *
877      * @return The column number, or -1 if none is available.
878      * @see #getLineNumber
879      */

880     public int getColumnNumber() {
881         return reader.getLocation().getColumnNumber();
882     }
883
884     public String JavaDoc getSystemId(int locationId) {
885         return getSystemId();
886     }
887
888     public int getLineNumber(int locationId) {
889         return getLineNumber();
890     }
891
892     /**
893      * Error reporting class for StAX parser errors
894      */

895
896     private class StaxErrorReporter implements XMLReporter {
897
898         public void report(String JavaDoc message, String JavaDoc errorType,
899                            Object JavaDoc relatedInformation, Location location)
900                 throws XMLStreamException {
901             ExpressionLocation loc = translateLocation(location);
902             DynamicError err = new DynamicError("Error reported by XML parser: " + message + " (" + errorType + ')');
903             err.setLocator(loc);
904             try {
905                 pipe.getErrorListener().error(err);
906             } catch (TransformerException JavaDoc e) {
907                 throw new XMLStreamException(e);
908             }
909         }
910
911     }
912
913     /**
914      * Simple test program
915      * Usage: java StaxBridge in.xml [out.xml]
916      */

917
918     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
919         for (int i=0; i<1; i++) {
920             long startTime = System.currentTimeMillis();
921             PipelineConfiguration pipe = new Configuration().makePipelineConfiguration();
922             StaxBridge puller = new StaxBridge();
923             File JavaDoc f = new File JavaDoc(args[0]);
924             puller.setInputStream(f.toURI().toString(), new FileInputStream JavaDoc(f));
925             XMLEmitter emitter = new XMLEmitter();
926             emitter.setPipelineConfiguration(pipe);
927             emitter.setOutputProperties(new Properties JavaDoc());
928             if (args.length > 1) {
929                 emitter.setOutputStream(new FileOutputStream JavaDoc(args[1]));
930             } else {
931                 emitter.setOutputStream(System.out);
932             }
933             NamespaceReducer r = new NamespaceReducer();
934             r.setUnderlyingReceiver(emitter);
935             puller.setPipelineConfiguration(pipe);
936             r.setPipelineConfiguration(pipe);
937             new PullPushCopier(puller, r).copy();
938             System.err.println("Elapsed time: " + (System.currentTimeMillis() - startTime) + "ms");
939         }
940     }
941 }
942
943
944 //
945
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
946
// you may not use this file except in compliance with the License. You may obtain a copy of the
947
// License at http://www.mozilla.org/MPL/
948
//
949
// Software distributed under the License is distributed on an "AS IS" basis,
950
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
951
// See the License for the specific language governing rights and limitations under the License.
952
//
953
// The Original Code is: all this file.
954
//
955
// The Initial Developer of the Original Code is Michael H. Kay.
956
//
957
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
958
//
959
// Contributor(s): none.
960
//
961
Popular Tags