| GateFormatXmlDocumentHandler.java |
1 /*
2 * GateFormatXmlDocumentHandler.java
3 *
4 * Copyright (c) 1998-2004, The University of Sheffield.
5 *
6 * This file is part of GATE (see http://gate.ac.uk/), and is free
7 * software, licenced under the GNU Library General Public License,
8 * Version 2, June 1991 (in the distribution as file licence.html,
9 * and also available at http://gate.ac.uk/gate/licence.html).
10 *
11 * Cristian URSU, 22 Nov 2000
12 *
13 * $Id: GateFormatXmlDocumentHandler.java,v 1.29 2004/08/06 16:08:26 valyt Exp $
14 */
15
16 package gate.xml;
17
18 import java.lang.reflect.Constructor;
19 import java.util.*;
20
21 import org.xml.sax.*;
22 import org.xml.sax.helpers.DefaultHandler;
23
24 import gate.*;
25 import gate.corpora.DocumentContentImpl;
26 import gate.event.StatusListener;
27 import gate.util.*;
28
29
30 /**
31 * Implements the behaviour of the XML reader. This is the reader for
32 * Gate Xml documents saved with DocumentImplementation.toXml() method.
33 */
34 public class GateFormatXmlDocumentHandler extends DefaultHandler{
35 /** Debug flag */
36 private static final boolean DEBUG = false;
37
38 /** This is used to capture all data within two tags before calling the actual characters method */
39 private StringBuffer contentBuffer = new StringBuffer("");
40
41 /** This is a variable that shows if characters have been read */
42 private boolean readCharacterStatus = false;
43
44 /**
45 */
46 public GateFormatXmlDocumentHandler(gate.Document aDocument){
47 // This string contains the plain text (the text without markup)
48 tmpDocContent = new StringBuffer(aDocument.getContent().size().intValue());
49
50 // Colector is used later to transform all custom objects into annotation
51 // objects
52 colector = new LinkedList();
53
54 // The Gate document
55 doc = aDocument;
56 currentAnnotationSet = doc.getAnnotations();
57 }//GateFormatXmlDocumentHandler
58
59 /**
60 * This method is called when the SAX parser encounts the beginning of the
61 * XML document.
62 */
63 public void startDocument() throws org.xml.sax.SAXException {
64 }// startDocument
65
66 /**
67 * This method is called when the SAX parser encounts the end of the
68 * XML document.
69 * Here we set the content of the gate Document to be the one generated
70 * inside this class (tmpDocContent).
71 * After that we use the colector to generate all the annotation reffering
72 * this new gate document.
73 */
74 public void endDocument() throws org.xml.sax.SAXException {
75
76 // replace the document content with the one without markups
77 doc.setContent(new DocumentContentImpl(tmpDocContent.toString()));
78 long docSize = doc.getContent().size().longValue();
79
80 // fire the status listener
81 fireStatusChangedEvent("Total elements: " + elements);
82
83 }// endDocument
84
85 /**
86 * This method is called when the SAX parser encounts the beginning of an
87 * XML element.
88 */
89 public void startElement (String uri, String qName, String elemName,
90 Attributes atts) throws SAXException {
91
92 // call characterActions
93 if(readCharacterStatus) {
94 readCharacterStatus = false;
95 charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
96 }
97
98 // Inform the progress listener to fire only if no of elements processed
99 // so far is a multiple of ELEMENTS_RATE
100 if ((++elements % ELEMENTS_RATE) == 0 )
101 fireStatusChangedEvent("Processed elements : " + elements);
102
103 // Set the curent element being processed
104 currentElementStack.add(elemName);
105
106 if("AnnotationSet".equals(elemName))
107 processAnnotationSetElement(atts);
108
109 if("Annotation".equals(elemName))
110 processAnnotationElement(atts);
111
112 if("Feature".equals(elemName))
113 processFeatureElement(atts);
114
115 if("Name".equals(elemName))
116 processNameElement(atts);
117
118 if("Value".equals(elemName))
119 processValueElement(atts);
120
121 if("Node".equals(elemName))
122 processNodeElement(atts);
123 }// startElement
124
125 /**
126 * This method is called when the SAX parser encounts the end of an
127 * XML element.
128 */
129 public void endElement (String uri, String qName, String elemName )
130 throws SAXException{
131
132 // call characterActions
133 if(readCharacterStatus) {
134 readCharacterStatus = false;
135 charactersAction(new String(contentBuffer).toCharArray(),0,contentBuffer.length());
136 }
137
138 currentElementStack.pop();
139 // Deal with Annotation
140 if ("Annotation".equals(elemName)){
141 if (currentFeatureMap == null)
142 currentFeatureMap = Factory.newFeatureMap();
143 currentAnnot.setFM(currentFeatureMap);
144 colector.add(currentAnnot);
145 // Reset current Annot and current featue map
146 currentAnnot = null;
147 currentFeatureMap = null;
148 return;
149 }// End if
150 // Deal with Value
151 if ("Value".equals(elemName) && "Feature".equals(
152 (String)currentElementStack.peek())){
153 // If the Value tag was empty, then an empty string will be created.
154 if (currentFeatureValue == null) currentFeatureValue = "";
155 }// End if
156 // Deal with Feature
157 if ("Feature".equals(elemName)){
158 if(currentFeatureName == null){
159 // Cannot add the (key,value) pair to the map
160 // One of them is null something was wrong in the XML file.
161 throw new GateSaxException("A feature name was empty." +
162 "The annotation that cause it is " +
163 currentAnnot +
164 ".Please check the document with a text editor before trying again.");
165 }else {
166 if (currentFeatureMap == null){
167 // The XMl file was somehow altered and a start Feature wasn't found.
168 throw new GateSaxException("Document not consistent. A start"+
169 " feature element is missing. " +
170 "The annotation that cause it is " +
171 currentAnnot +
172 "Please check the document with a text editor before trying again.");
173 }// End if
174 // Create the appropiate feature name and values
175 // If those object cannot be created, their string representation will
176 // be used.
177 currentFeatureMap.put(createFeatKey(),createFeatValue());
178 // currentFeatureMap.put(currentFeatureName,currentFeatureValue);
179 // Reset current key
180 currentFeatureKeyClassName = null;
181 currentFeatureKeyItemClassName = null;
182 currentFeatureName = null;
183 // Reset current value
184 currentFeatureValueClassName = null;
185 currentFeatureValueItemClassName = null;
186 currentFeatureValue = null;
187 }// End if
188 // Reset the Name & Value pair.
189 currentFeatureName = null;
190 currentFeatureValue = null;
191 return;
192 }//End if
193 // Deal GateDocumentFeatures
194 if ("GateDocumentFeatures".equals(elemName)){
195 if (currentFeatureMap == null)
196 currentFeatureMap = Factory.newFeatureMap();
197 doc.setFeatures(currentFeatureMap);
198 currentFeatureMap = null;
199 return;
200 }// End if
201
202 // Deal with AnnotationSet
203 if ("AnnotationSet".equals(elemName)){
204 // Create and add annotations to the currentAnnotationSet
205 Iterator iterator = colector.iterator();
206 while (iterator.hasNext()){
207 AnnotationObject annot = (AnnotationObject) iterator.next();
208 // Clear the annot from the colector
209 iterator.remove();
210 // Create a new annotation and add it to the annotation set
211 try{
212 currentAnnotationSet.add(annot.getStart(),
213 annot.getEnd(),
214 annot.getElemName(),
215 annot.getFM());
216 }catch (gate.util.InvalidOffsetException e){
217 throw new GateSaxException(e);
218 }// End try
219 }// End while
220 // The colector is empty and ready for the next AnnotationSet
221 return;
222 }// End if
223
224
225 }//endElement
226
227 /**
228 * This method is called when the SAX parser encounts text in the XML doc.
229 * Here we calculate the end indices for all the elements present inside the
230 * stack and update with the new values.
231 */
232 public void characters(char [] text,int start,int length) throws SAXException {
233 if(!readCharacterStatus) {
234 contentBuffer = new StringBuffer(new String(text,start,length));
235 } else {
236 contentBuffer.append(new String(text,start,length));
237 }
238 readCharacterStatus = true;
239 }
240
241 /**
242 * This method is called when all characters between specific tags have been read completely
243 */
244 public void charactersAction( char[] text,int start,int length) throws SAXException{
245 // Create a string object based on the reported text
246 String content = new String(text, start, length);
247 if ("TextWithNodes".equals((String)currentElementStack.peek())){
248 processTextOfTextWithNodesElement(content);
249 return;
250 }// End if
251 if ("Name".equals((String)currentElementStack.peek())){
252 processTextOfNameElement(content);
253 return;
254 }// End if
255 if ("Value".equals((String)currentElementStack.peek())){
256 //if (currentFeatureName != null && "string".equals(currentFeatureName) &&
257 //currentAnnot!= null && "Token".equals(currentAnnot.getElemName()) &&
258 //currentAnnot.getEnd().longValue() == 1063)
259 //System.out.println("Content=" + content + " start="+ start + " length=" + length);
260 processTextOfValueElement(content);
261 return;
262 }// End if
263 }//characters
264
265 /**
266 * This method is called when the SAX parser encounts white spaces
267 */
268 public void ignorableWhitespace(char ch[],int start,int length) throws
269 SAXException{
270 }//ignorableWhitespace
271
272 /**
273 * Error method.We deal with this exception inside SimpleErrorHandler class
274 */
275 public void error(SAXParseException ex) throws SAXException {
276 // deal with a SAXParseException
277 // see SimpleErrorhandler class
278 _seh.error(ex);
279 }//error
280
281 /**
282 * FatalError method.
283 */
284 public void fatalError(SAXParseException ex) throws SAXException {
285 // deal with a SAXParseException
286 // see SimpleErrorhandler class
287 _seh.fatalError(ex);
288 }//fatalError
289
290 /**
291 * Warning method comment.
292 */
293 public void warning(SAXParseException ex) throws SAXException {
294 // deal with a SAXParseException
295 // see SimpleErrorhandler class
296 _seh.warning(ex);
297 }//warning
298
299 // Custom methods section
300
301
302 /** This method deals with a AnnotationSet element. */
303 private void processAnnotationSetElement(Attributes atts){
304 if (atts != null){
305 for (int i = 0; i < atts.getLength(); i++) {
306 // Extract name and value
307 String attName = atts.getLocalName(i);
308 String attValue = atts.getValue(i);
309 if ("Name".equals(attName))
310 currentAnnotationSet = doc.getAnnotations(attValue);
311 }// End for
312 }// End if
313 }//processAnnotationSetElement
314
315 /** This method deals with the start of a Name element*/
316 private void processNameElement(Attributes atts){
317 if (atts == null) return;
318 currentFeatureKeyClassName = atts.getValue("className");
319 currentFeatureKeyItemClassName = atts.getValue("itemClassName");
320 }// End processNameElement();
321
322 /** This method deals with the start of a Value element*/
323 private void processValueElement(Attributes atts){
324 if (atts == null) return;
325 currentFeatureValueClassName = atts.getValue("className");
326 currentFeatureValueItemClassName = atts.getValue("itemClassName");
327 }// End processValueElement();
328
329 /** This method deals with a Annotation element. */
330 private void processAnnotationElement(Attributes atts){
331 if (atts != null){
332 currentAnnot = new AnnotationObject();
333 for (int i = 0; i < atts.getLength(); i++) {
334 // Extract name and value
335 String attName = atts.getLocalName(i);
336 String attValue = atts.getValue(i);
337
338 if ("Type".equals(attName))
339 currentAnnot.setElemName(attValue);
340
341 try{
342 if ("StartNode".equals(attName)){
343 Integer id = new Integer(attValue);
344 Long offset = (Long)id2Offset.get(id);
345 if (offset == null){
346 throw new GateRuntimeException("Couldn't found Node with id = " +
347 id +
348 ".It was specified in annot " +
349 currentAnnot+
350 " as a start node!" +
351 "Check the document with a text editor or something"+
352 " before trying again.");
353
354 }else
355 currentAnnot.setStart(offset);
356 }// Endif
357 if ("EndNode".equals(attName)){
358 Integer id = new Integer(attValue);
359 Long offset = (Long) id2Offset.get(id);
360 if (offset == null){
361 throw new GateRuntimeException("Couldn't found Node with id = " +
362 id+
363 ".It was specified in annot " +
364 currentAnnot+
365 " as a end node!" +
366 "Check the document with a text editor or something"+
367 " before trying again.");
368 }else
369 currentAnnot.setEnd(offset);
370 }// End if
371 } catch (NumberFormatException e){
372 throw new GateRuntimeException("Offsets problems.Couldn't create"+
373 " Integers from" + " id[" +
374 attValue + "]) in annot " +
375 currentAnnot+
376 "Check the document with a text editor or something,"+
377 " before trying again");
378 }// End try
379 }// End For
380 }// End if
381 }//processAnnotationElement
382
383 /** This method deals with a Features element. */
384 private void processFeatureElement(Attributes atts){
385 // The first time feature is calle it will create a features map.
386 if (currentFeatureMap == null)
387 currentFeatureMap = Factory.newFeatureMap();
388 }//processFeatureElement
389
390 /** This method deals with a Node element. */
391 private void processNodeElement(Attributes atts){
392 if (atts != null){
393 for (int i = 0; i < atts.getLength(); i++) {
394 // Extract name and value
395 String attName = atts.getLocalName(i);
396 String attValue = atts.getValue(i);
397 //System.out.println("Node : " + attName + "=" +attValue);
398 if ("id".equals(attName)){
399 try{
400 Integer id = new Integer(attValue);
401 id2Offset.put(id,new Long(tmpDocContent.length()));
402 }catch(NumberFormatException e){
403 throw new GateRuntimeException("Coudn't create a node from " +
404 attValue + " Expected an integer.");
405 }// End try
406 }// End if
407 }// End for
408 }// End if
409 }// processNodeElement();
410
411 /** This method deals with a Text belonging to TextWithNodes element. */
412 private void processTextOfTextWithNodesElement(String text){
413 text = recoverNewLineSequence(text);
414 tmpDocContent.append(text);
415 }//processTextOfTextWithNodesElement
416
417 /** Restore new line as in the original document if needed */
418 private String recoverNewLineSequence(String text) {
419 String result = text;
420
421 // check for new line
422 if(text.indexOf('\n') != -1) {
423 String newLineType =
424 (String) doc.getFeatures().get(GateConstants.DOCUMENT_NEW_LINE_TYPE);
425
426 if("LF".equalsIgnoreCase(newLineType)) {
427 newLineType = null;
428 }
429
430 // exit with the same text if the change isn't necessary
431 if(newLineType == null) return result;
432
433 String newLine = "\n";
434 if("CRLF".equalsIgnoreCase(newLineType)) {
435 newLine = "\r\n";
436 }
437 if("CR".equalsIgnoreCase(newLineType)) {
438 newLine = "\r";
439 }
440 if("LFCR".equalsIgnoreCase(newLineType)) {
441 newLine = "\n\r";
442 }
443
444 StringBuffer buff = new StringBuffer(text);
445 int index = text.lastIndexOf('\n');
446 while(index != -1) {
447 buff.replace(index, index+1, newLine);
448 index = text.lastIndexOf('\n', index-1);
449 } // while
450 result = buff.toString();
451 } // if
452
453 return result;
454 } // recoverNewLineSequence(String text)
455
456 /** This method deals with a Text belonging to Name element. */
457 private void processTextOfNameElement(String text) throws GateSaxException{
458 if (currentFeatureMap == null)
459 throw new GateSaxException("GATE xml format processing error:" +
460 " Found a Name element that is not enclosed into a Feature one while" +
461 " analyzing the annotation " +
462 currentAnnot +
463 "Please check the document with a text editor or something before" +
464 " trying again.");
465 else{
466 // In the entities case, characters() gets called separately for each
467 // entity so the text needs to be appended.
468 if (currentFeatureName == null)
469 currentFeatureName = text;
470 else
471 currentFeatureName = currentFeatureName + text;
472 }// End If
473 }//processTextOfNameElement();
474
475 /** This method deals with a Text belonging to Value element. */
476 private void processTextOfValueElement(String text) throws GateSaxException{
477 if (currentFeatureMap == null)
478 throw new GateSaxException("GATE xml format processing error:" +
479 " Found a Value element that is not enclosed into a Feature one while" +
480 " analyzing the annotation " +
481 currentAnnot+
482 "Please check the document with a text editor or something before" +
483 " trying again.");
484 else{
485 // In the entities case, characters() gets called separately for each
486 // entity so the text needs to be appended.
487 if (currentFeatureValue == null)
488 currentFeatureValue = text;
489 else
490 currentFeatureValue = currentFeatureValue + text;
491 }// End If
492 }//processTextOfValueElement();
493
494 /** Creates a feature key using this information:
495 * currentFeatureKeyClassName, currentFeatureKeyItemClassName,
496 * currentFeatureName. See createFeatObject() method for more details.
497 */
498 private Object createFeatKey(){
499 return createFeatObject(currentFeatureKeyClassName,
500 currentFeatureKeyItemClassName,
501 currentFeatureName);
502 }//createFeatKey()
503
504 /** Creates a feature value using this information:
505 * currentFeatureValueClassName, currentFeatureValueItemClassName,
506 * currentFeatureValue. See createFeatObject() method for more details.
507 */
508 private Object createFeatValue(){
509 return createFeatObject(currentFeatureValueClassName,
510 currentFeatureValueItemClassName,
511 currentFeatureValue);
512 }//createFeatValue()
513
514 /** This method tries to reconstruct an object given its class name and its
515 * string representation. If the object is a Collection then the items
516 * from its string representation must be separated by a ";". In that
517 * case, the currentFeatureValueItemClassName is used to create items
518 * belonging to this class.
519 * @param aFeatClassName represents the name of the class of
520 * the feat object being created. If it is null then the javaLang.String will
521 * be used as default.
522 * @param aFeatItemClassName is it used only if aFeatClassName is a
523 * collection.If it is null then java.lang.String will be used as default;
524 * @param aFeatStringRepresentation sais it all
525 * @return an Object created from aFeatClassName and its
526 * aFeatStringRepresentation. If not possible, then aFeatStringRepresentation
527 * is returned.
528 * @throws GateRuntimeException If it can't create an item, that
529 * does not comply with its class definition, to add to the
530 * collection.
531 */
532 private Object createFeatObject( String aFeatClassName,
533 String aFeatItemClassName,
534 String aFeatStringRepresentation){
535 // If the string rep is null then the object will be null;
536 if (aFeatStringRepresentation == null) return null;
537 if (aFeatClassName == null) aFeatClassName = "java.lang.String";
538 if (aFeatItemClassName == null) aFeatItemClassName = "java.lang.String";
539 Class currentFeatClass = null;
540 try{
541 currentFeatClass = Gate.getClassLoader().loadClass(aFeatClassName);
542 }catch (ClassNotFoundException cnfex){
543 return aFeatStringRepresentation;
544 }// End try
545 if (java.util.Collection.class.isAssignableFrom(currentFeatClass)){
546 Class itemClass = null;
547 Collection featObject = null;
548 try{
549 featObject = (Collection) currentFeatClass.newInstance();
550 try{
551 itemClass = Gate.getClassLoader().loadClass(aFeatItemClassName);
552 }catch(ClassNotFoundException cnfex){
553 Out.prln("Warning: Item class "+ aFeatItemClassName + " not found."+
554 "Adding items as Strings to the feature called \"" + currentFeatureName
555 + "\" in the annotation " + currentAnnot);
556 itemClass = java.lang.String.class;
557 }// End try
558 // Let's detect if itemClass takes a constructor with a String as param
559 Class[] paramsArray = new Class[1];
560 paramsArray[0] = java.lang.String.class;
561 Constructor itemConstructor = null;
562 boolean addItemAsString = false;
563 try{
564 itemConstructor = itemClass.getConstructor(paramsArray);
565 }catch (NoSuchMethodException nsme){
566 addItemAsString = true;
567 }catch (SecurityException se){
568 addItemAsString = true;
569 }// End try
570 StringTokenizer strTok = new StringTokenizer(
571 aFeatStringRepresentation,";");
572 Object[] params = new Object[1];
573 Object itemObj = null;
574 while (strTok.hasMoreTokens()){
575 String itemStrRep = strTok.nextToken();
576 if (addItemAsString) featObject.add(itemStrRep);
577 else{
578 params[0] = itemStrRep;
579 try{
580 itemObj = itemConstructor.newInstance(params);
581 }catch (Exception e){
582 throw new GateRuntimeException("An item("+
583 itemStrRep +
584 ") does not comply with its class" +
585 " definition("+aFeatItemClassName+").Happened while tried to"+
586 " add feature: " +
587 aFeatStringRepresentation + " to the annotation " + currentAnnot);
588 }// End try
589 featObject.add(itemObj);
590 }// End if
591 }// End while
592 }catch(InstantiationException instex ){
593 return aFeatStringRepresentation;
594 }catch (IllegalAccessException iae){
595 return aFeatStringRepresentation;
596 }// End try
597 return featObject;
598 }// End if
599 // If currentfeatClass is not a Collection,test to see if
600 // it has a constructor that takes a String as param
601 Class[] params = new Class[1];
602 params[0] = java.lang.String.class;
603 try{
604 Constructor featConstr = currentFeatClass.getConstructor(params);
605 Object[] featConstrParams = new Object[1];
606 featConstrParams[0] = aFeatStringRepresentation;
607 Object featObject = featConstr.newInstance(featConstrParams);
608 return featObject;
609 } catch(Exception e){
610 return aFeatStringRepresentation;
611 }// End try
612 }// createFeatObject()
613
614 /**
615 * This method is called when the SAX parser encounts a comment
616 * It works only if the XmlDocumentHandler implements a
617 * com.sun.parser.LexicalEventListener
618 */
619 public void comment(String text) throws SAXException {
620 }//comment
621
622 /**
623 * This method is called when the SAX parser encounts a start of a CDATA
624 * section
625 * It works only if the XmlDocumentHandler implements a
626 * com.sun.parser.LexicalEventListener
627 */
628 public void startCDATA()throws SAXException {
629 }//startCDATA
630
631 /**
632 * This method is called when the SAX parser encounts the end of a CDATA
633 * section.
634 * It works only if the XmlDocumentHandler implements a
635 * com.sun.parser.LexicalEventListener
636 */
637 public void endCDATA() throws SAXException {
638 }//endCDATA
639
640 /**
641 * This method is called when the SAX parser encounts a parsed Entity
642 * It works only if the XmlDocumentHandler implements a
643 * com.sun.parser.LexicalEventListener
644 */
645 public void startParsedEntity(String name) throws SAXException {
646 }//startParsedEntity
647
648 /**
649 * This method is called when the SAX parser encounts a parsed entity and
650 * informs the application if that entity was parsed or not
651 * It's working only if the CustomDocumentHandler implements a
652 * com.sun.parser.LexicalEventListener
653 */
654 public void endParsedEntity(String name, boolean included)throws SAXException{
655 }//endParsedEntity
656
657 //StatusReporter Implementation
658
659 /**
660 * This methos is called when a listener is registered with this class
661 */
662 public void addStatusListener(StatusListener listener){
663 myStatusListeners.add(listener);
664 }//addStatusListener
665 /**
666 * This methos is called when a listener is removed
667 */
668 public void removeStatusListener(StatusListener listener){
669 myStatusListeners.remove(listener);
670 }//removeStatusListener
671 /**
672 * This methos is called whenever we need to inform the listener about an
673 * event.
674 */
675 protected void fireStatusChangedEvent(String text){
676 Iterator listenersIter = myStatusListeners.iterator();
677 while(listenersIter.hasNext())
678 ((StatusListener)listenersIter.next()).statusChanged(text);
679 }//fireStatusChangedEvent
680
681 // XmlDocumentHandler member data
682
683 /** This constant indicates when to fire the status listener.
684 * This listener will add an overhead and we don't want a big overhead.
685 * It will be callled from ELEMENTS_RATE to ELEMENTS_RATE
686 */
687 final static int ELEMENTS_RATE = 128;
688
689 /** This object indicates what to do when the parser encounts an error */
690 private SimpleErrorHandler _seh = new SimpleErrorHandler();
691
692 /** The content of the XML document, without any tag */
693 private StringBuffer tmpDocContent = new StringBuffer("");
694
695 /** A gate document */
696 private gate.Document doc = null;
697
698 /** Listeners for status report */
699 protected List myStatusListeners = new LinkedList();
700
701 /** This reports the the number of elements that have beed processed so far*/
702 private int elements = 0;
703
704 /** We need a colection to retain all the CustomObjects that will be
705 * transformed into annotation over the gate document...
706 * At the end of every annotation set read the objects in the colector are
707 * transformed into annotations...
708 */
709 private List colector = null;
710 /** Maps nodes Ids to their offset in the document text. Those offsets will
711 * be used when creating annotations
712 */
713 private Map id2Offset = new TreeMap();
714 /** Holds the current element read.*/
715 private Stack currentElementStack = new Stack();
716 /** This inner objects maps an annotation object. When an annotation from the
717 * xml document was read this structure is filled out
718 */
719 private AnnotationObject currentAnnot = null;
720 /** A map holding current annotation's features*/
721 private FeatureMap currentFeatureMap = null;
722 /** A key of the current feature*/
723 private String currentFeatureName = null;
724 /** The value of the current feature*/
725 private String currentFeatureValue = null;
726 /** The class name of the key in the current feature*/
727 private String currentFeatureKeyClassName = null;
728 /** If the key is a collection then we need to know the class name of the
729 * items present in this collection. The next field holds just that.
730 */
731 private String currentFeatureKeyItemClassName = null;
732 /** The class name for the value in the current feature*/
733 private String currentFeatureValueClassName = null;
734 /** If the value is a collection then we need to know the class name of the
735 * items present in this collection. The next field holds just that.
736 */
737 private String currentFeatureValueItemClassName = null;
738 /** the current annotation set that is being created and filled with
739 * annotations
740 */
741 private AnnotationSet currentAnnotationSet = null;
742
743 /** An inner class modeling the information contained by an annotation.*/
744 class AnnotationObject {
745 /** Constructor */
746 public AnnotationObject(){}//AnnotationObject
747 /** Accesor for the annotation type modeled here as ElemName */
748 public String getElemName(){
749 return elemName;
750 }//getElemName
751 /** Accesor for the feature map*/
752 public FeatureMap getFM(){
753 return fm;
754 }// getFM()
755 /** Accesor for the start ofset*/
756 public Long getStart(){
757 return start;
758 }// getStart()
759 /** Accesor for the end offset*/
760 public Long getEnd(){
761 return end;
762 }// getEnd()
763 /** Mutator for the annotation type */
764 public void setElemName(String anElemName){
765 elemName = anElemName;
766 }// setElemName();
767 /** Mutator for the feature map*/
768 public void setFM(FeatureMap aFm){
769 fm = aFm;
770 }// setFM();
771 /** Mutator for the start offset*/
772 public void setStart(Long aStart){
773 start = aStart;
774 }// setStart();
775 /** Mutator for the end offset*/
776 public void setEnd(Long anEnd){
777 end = anEnd;
778 }// setEnd();
779
780 public String toString(){
781 return " [type=" + elemName +
782 " startNode=" + start+
783 " endNode=" + end+
784 " features="+ fm +"] ";
785 }
786 // Data fields
787 private String elemName = null;
788 private FeatureMap fm = null;
789 private Long start = null;
790 private Long end = null;
791 } // AnnotationObject
792 }//GateFormatXmlDocumentHandler
793
794