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