TextualDocumentFormat.java
001 /*
002  *  TextualDocumentFormat.java
003  *
004  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Cristian URSU, 26/May/2000
013  *
014  *  $Id: TextualDocumentFormat.java 17616 2014-03-10 16:09:07Z markagreenwood $
015  */
016 
017 package gate.corpora;
018 
019 import java.io.IOException;
020 
021 import gate.*;
022 import gate.creole.ResourceInstantiationException;
023 import gate.creole.metadata.AutoInstance;
024 import gate.creole.metadata.CreoleResource;
025 import gate.util.DocumentFormatException;
026 
027 //import org.w3c.www.mime.*;
028 
029 /** The format of Documents. Subclasses of DocumentFormat know about
030   * particular MIME types and how to unpack the information in any
031   * markup or formatting they contain into GATE annotations. Each MIME
032   * type has its own subclass of DocumentFormat, e.g. XmlDocumentFormat,
033   * RtfDocumentFormat, MpegDocumentFormat. These classes register themselves
034   * with a static index residing here when they are constructed. Static
035   * getDocumentFormat methods can then be used to get the appropriate
036   * format class for a particular document.
037   */
038 @CreoleResource(name = "GATE Textual Document Format", isPrivate = true,
039     autoinstances = {@AutoInstance(hidden = true)})
040 public class TextualDocumentFormat extends DocumentFormat
041 {
042   private static final long serialVersionUID = -5630380244338599927L;
043 
044   /** Default construction */
045   public TextualDocumentFormat() { super()}
046 
047   /** Initialise this resource, and return it. */
048   @Override
049   public Resource init() throws ResourceInstantiationException{
050     // Register plain text mime type
051     MimeType mime = new MimeType("text","plain");
052     // Register the class handler for this mime type
053     mimeString2ClassHandlerMap.put(mime.getType()"/" + mime.getSubtype(),
054                                                                           this);
055     // Register the mime type with mine string
056     mimeString2mimeTypeMap.put(mime.getType() "/" + mime.getSubtype(), mime);
057     // Register file sufixes for this mime type
058     suffixes2mimeTypeMap.put("txt",mime);
059     suffixes2mimeTypeMap.put("text",mime);
060     // Set the mimeType for this language resource
061     setMimeType(mime);
062     return this;
063   // init()
064 
065   /** Unpack the markup in the document. This converts markup from the
066     * native format (e.g. XML, RTF) into annotations in GATE format.
067     * Uses the markupElementsMap to determine which elements to convert, and
068     * what annotation type names to use.
069     */
070   @Override
071   public void unpackMarkup(Document docthrows DocumentFormatException{
072     if (doc == null || doc.getContent() == nullreturn;
073     setNewLineProperty(doc);
074     // Create paragraph annotations in the specified annotation set
075     int endOffset = doc.getContent().toString().length();
076     int startOffset = 0;
077     annotateParagraphs(doc,startOffset,endOffset,
078                                 GateConstants.ORIGINAL_MARKUPS_ANNOT_SET_NAME);
079   }//unpackMarkup
080 
081   @Override
082   public void unpackMarkup(Document doc, RepositioningInfo repInfo,
083                             RepositioningInfo ampCodingInfo)
084                                       throws DocumentFormatException {
085     unpackMarkup(doc);
086   // unpackMarkup
087   
088   /**
089    * This is a test to see if the GATE document has a valid URL or a
090    * valid content.
091    
092    @param doc
093    @throws DocumentFormatException
094    */
095   protected static boolean hasContentButNoValidUrl(Document doc)
096           throws DocumentFormatException {
097     try {
098       if(doc.getSourceUrl() == null && doc.getContent() != null) {
099         // The doc's url is null but there is a content.
100         return true;
101       }
102       else {
103         doc.getSourceUrl().openConnection();
104       }
105     }
106     catch(IOException ex1) {
107       // The URL is not null but is not valid.
108       if(doc.getContent() == null)
109       // The document content is also null. There is nothing we can do.
110         throw new DocumentFormatException("The document doesn't have a"
111                 " valid URL and also no content");
112       return true;
113     }// End try
114 
115     return false;
116   }
117 
118 
119   /**
120    * Check the new line sequence and set document property.
121    <BR>
122    * Possible values are CRLF, LFCR, CR, LF
123    */
124   protected void setNewLineProperty(Document doc) {
125     String content = doc.getContent().toString();
126     String newLineType = "";
127 
128     char ch = ' ';
129     char lastch = ' ';
130     for(int i=0; i < content.length(); ++i) {
131       ch = content.charAt(i);
132       if(lastch == '\r') {
133         if(ch == '\n') {
134           newLineType = "CRLF";
135           break;
136         }
137         else {
138           newLineType = "CR";
139           break;
140         }
141       }
142       if(lastch == '\n') {
143         if(ch == '\r') {
144           newLineType = "LFCR";
145           break;
146         }
147         else {
148           newLineType = "LF";
149           break;
150         }
151       }
152       lastch = ch;
153     // for
154 
155     doc.getFeatures().put(GateConstants.DOCUMENT_NEW_LINE_TYPE, newLineType);
156   // setNewLineProperty()
157 
158   /** Delete '\r' in combination CRLF or LFCR in document content */
159   @SuppressWarnings("unused")
160   private void removeExtraNewLine(Document doc) {
161     String content = doc.getContent().toString();
162     StringBuffer buff = new StringBuffer(content);
163 
164     char ch = ' ';
165     char lastch = ' ';
166     for(int i=content.length()-1; i > -1; --i) {
167       ch = content.charAt(i);
168       if(ch == '\n' && lastch == '\r') {
169         buff.deleteCharAt(i+1);
170       }
171       if(ch == '\r' && lastch == '\n') {
172         buff.deleteCharAt(i);
173         ch = lastch;
174       }
175       lastch = ch;
176     // for
177 
178     doc.setContent(new DocumentContentImpl(buff.toString()));
179   // removeExtraNewLine(Document doc)
180 
181   /** This method annotates paragraphs in a GATE document. The investigated text
182     * spans beetween start and end offsets and the paragraph annotations are
183     * created in the annotSetName. If annotSetName is null then they are creted
184     * in the default annotation set.
185     @param aDoc is the gate document on which the paragraph detection would
186     *  be performed.If it is null or its content it's null then the method woul
187     *  simply return doing nothing.
188     @param startOffset is the index  form the document content from which the
189     * paragraph detection will start
190     @param endOffset is the offset where the detection will end.
191     @param annotSetName is the name of the set in which paragraph annotation
192     * would be created.The annotation type created will be "paragraph"
193     */
194   public void annotateParagraphs(Document aDoc,int startOffset,int endOffset,
195                             String annotSetName)throws DocumentFormatException{
196     // Simply return if the document is null or its content
197     if (aDoc == null || aDoc.getContent() == nullreturn;
198     // Simply return if the start is > than the end
199     if (startOffset > endOffsetreturn;
200     // Decide where to put the newly detected annotations
201     AnnotationSet annotSet = null;
202     if (annotSetName == null)
203       annotSet = aDoc.getAnnotations();
204     else
205       annotSet = aDoc.getAnnotations(annotSetName);
206     // Extract the document content
207     String content = aDoc.getContent().toString();
208     // This is the offset marking the start of a para
209     int startOffsetPara = startOffset;
210     // This marks the ned of a para
211     int endOffsetPara = endOffset;
212     // The initial sate of the FSA
213     int state = 1;
214     // This field marks that a BR entity was read
215     // A BR entity can be NL or NL CR, depending on the operating system (UNIX
216     // or DOS)
217     boolean readBR = false;
218     int index = startOffset;
219     while (index < endOffset){
220       // Read the current char
221       char ch = content.charAt(index);
222       // Test if a BR entity was read
223       if (ch =='\n'){
224         readBR = true;
225         // If \n is followed by a \r then advance the index in order to read a
226         // BR entity
227         while ((index+< endOffset&& (content.charAt(index+1== '\r'))
228           index ++;
229       }// End if
230       switch(state){
231         // It is the initial and also a final state
232         // Stay in state 1 while it reads whitespaces
233         case 1:{
234           // If reads a non whitespace char then move to state 2 and record
235           // the beggining of a paragraph
236           if (!Character.isWhitespace(ch)){
237             state = 2;
238             startOffsetPara = index;
239           }// End if
240         }break;
241         // It can be also a final state.
242         case 2:{
243           // Stay in state 2 while reading chars != BR entities
244           if (readBR){
245             // If you find a BR char go to state 3. The possible end of the para
246             // can be index. This will be confirmed by state 3. So, this is why
247             // the end of a para is recorded here.
248             readBR = false;
249             endOffsetPara = index;
250             state = 3;
251           }// End if
252         }break;
253         // It can be also a final state
254         // From state 3 there are only 2 possible ways: (state 2 or state1)
255         // In state 1 it needs to read a BR
256         // For state 2 it nead to read something different then a BR
257         case 3:{
258           if (readBR){
259             // A BR was read. Go to state 1
260             readBR = false;
261             state = 1;
262             // Create an annotation type paragraph
263             try{
264               annotSet.addnew Long(startOffsetPara),
265                             new Long(endOffsetPara),
266                             "paragraph",
267                             Factory.newFeatureMap());
268             catch (gate.util.InvalidOffsetException ioe){
269               throw new DocumentFormatException("Coudn't create a paragraph"+
270               " annotation",ioe);
271             }// End try
272           }else{
273             // Go to state 2 an keep reading chars
274             state = 2;
275           }// End if
276         }break;
277       }// End switch
278       // Prepare to read the next char.
279       index ++;
280     }// End while
281     endOffsetPara = index;
282     // Investigate where the finite automata has stoped
283     if state==|| state==){
284       // Create an annotation type paragraph
285       try{
286         annotSet.addnew Long(startOffsetPara),
287                       // Create the final annotation using the endOffset
288                       new Long(endOffsetPara),
289                       "paragraph",
290                       Factory.newFeatureMap());
291       catch (gate.util.InvalidOffsetException ioe){
292               throw new DocumentFormatException("Coudn't create a paragraph"+
293               " annotation",ioe);
294       }// End try
295     }// End if
296   }// End annotateParagraphs();
297 
298   @Override
299   public DataStore getDataStore(){ return null;}
300 
301 // class TextualDocumentFormat