gt:       char currentchar = buffer.charAt(i);
context: /*
   *  DocumentXmlUtils.java
   *
   *  Copyright (c) 1995-2012, The University of Sheffield. See the file
   *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
   *
   *  This file is part of GATE (see http://gate.ac.uk/), and is free
   *  software, licenced under the GNU Library General Public License,
   *  Version 2, June 1991 (in the distribution as file licence.html,
   *  and also available at http://gate.ac.uk/gate/licence.html).
   *
   *  Ian Roberts, 20/Jul/2006
   *
   *  $Id: DocumentXmlUtils.java 15161 2012-01-21 12:50:09Z markagreenwood $
   */
  package gate.corpora;
  
  import gate.Annotation;
  import gate.AnnotationSet;
  import gate.FeatureMap;
  import gate.TextualDocument;
  import gate.event.StatusListener;
  import gate.util.Err;
  import gate.util.Strings;
  
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  import java.util.SortedMap;
  import java.util.SortedSet;
  import java.util.TreeMap;
  import java.util.TreeSet;
  
  /**
   * This class is contains useful static methods for working with the GATE XML
   * format.  Many of the methods in this class were originally in {@link
   * DocumentImpl} but as they are not specific to any one implementation of the
   * <code>Document</code> interface they have been moved here.
   */
  public class DocumentXmlUtils {
  
    /**
     * This field is used when creating StringBuffers for toXml() methods. The
     * size of the StringBuffer will be docDonctent.size() multiplied by this
     * value. It is aimed to improve the performance of StringBuffer
     */
    public static final int DOC_SIZE_MULTIPLICATION_FACTOR = 40;
  
    /**
     * Returns a GateXml document that is a custom XML format for wich there is a
     * reader inside GATE called gate.xml.GateFormatXmlHandler. What it does is to
     * serialize a GATE document in an XML format.
     * 
     * @param doc the document to serialize.
     * @return a string representing a Gate Xml document.
     */
    public static String toXml(TextualDocument doc) {
      // Initialize the xmlContent several time the size of the current document.
      // This is because of the tags size. This measure is made to increase the
      // performance of StringBuffer.
      StringBuffer xmlContent = new StringBuffer(
              DOC_SIZE_MULTIPLICATION_FACTOR
              * (doc.getContent().size().intValue()));
      // Add xml header
      xmlContent.append("<?xml version=\"1.0\" encoding=\"");
      xmlContent.append(doc.getEncoding());
      xmlContent.append("\" ?>");
      xmlContent.append(Strings.getNl());
      // Add the root element
      xmlContent.append("<GateDocument>\n");
      xmlContent.append("<!-- The document's features-->\n\n");
      xmlContent.append("<GateDocumentFeatures>\n");
      xmlContent.append(featuresToXml(doc.getFeatures(),null));
      xmlContent.append("</GateDocumentFeatures>\n");
      xmlContent.append("<!-- The document content area with serialized"
              + " nodes -->\n\n");
      // Add plain text element
      xmlContent.append("<TextWithNodes>");
      xmlContent.append(textWithNodes(doc, doc.getContent().toString()));
      xmlContent.append("</TextWithNodes>\n");
      // Serialize as XML all document's annotation sets
      // Serialize the default AnnotationSet
      StatusListener sListener = (StatusListener)gate.Gate
              .getListeners().get("gate.event.StatusListener");
      if(sListener != null)
        sListener.statusChanged("Saving the default annotation set ");
      xmlContent.append("<!-- The default annotation set -->\n\n");
      annotationSetToXml(doc.getAnnotations(), xmlContent);
      // Serialize all others AnnotationSets
      // namedAnnotSets is a Map containing all other named Annotation Sets.
      Map<String,AnnotationSet> namedAnnotSets = doc.getNamedAnnotationSets();
      if(namedAnnotSets != null) {
        Iterator<AnnotationSet> iter = namedAnnotSets.values().iterator();
        while(iter.hasNext()) {
          AnnotationSet annotSet = iter.next();
          xmlContent.append("<!-- Named annotation set -->\n\n");
          // Serialize it as XML
          if(sListener != null)
            sListener.statusChanged("Saving " + annotSet.getName()
                    + " annotation set ");
          annotationSetToXml(annotSet, xmlContent);
        }// End while
      }// End if
      // Add the end of GateDocument
      xmlContent.append("</GateDocument>");
      if(sListener != null) sListener.statusChanged("Done !");
      // return the XmlGateDocument
      return xmlContent.toString();
    }
  
  
    /**
     * This method saves a FeatureMap as XML elements.
     * 
     * @param aFeatureMap
     *          the feature map that has to be saved as XML.
     * @return a String like this: <Feature><Name>...</Name> <Value>...</Value></Feature><Feature>...</Feature>
     */
    public static StringBuffer featuresToXml(FeatureMap aFeatureMap, Map<String,StringBuffer> normalizedFeatureNames) {
      if(aFeatureMap == null) return new StringBuffer();
      StringBuffer buffer = new StringBuffer(1024);
      Set keySet = aFeatureMap.keySet();
      Iterator keyIterator = keySet.iterator();
      while(keyIterator.hasNext()) {
        Object key = keyIterator.next();
        Object value = aFeatureMap.get(key);
        if((key != null) && (value != null)) {
          String keyClassName = null;
          String keyItemClassName = null;
          String valueClassName = null;
          String valueItemClassName = null;
          String key2String = key.toString();
          String value2String = value.toString();
          Object item = null;
          // Test key if it is String, Number or Collection
          if(key instanceof java.lang.String || key instanceof java.lang.Number
                  || key instanceof java.util.Collection)
            keyClassName = key.getClass().getName();
          // Test value if it is String, Number or Collection
          if(value instanceof java.lang.String
                  || value instanceof java.lang.Number
                  || value instanceof java.util.Collection)
            valueClassName = value.getClass().getName();
          // Features and values that are not Strings, Numbers or collections
          // will be discarded.
          if(keyClassName == null || valueClassName == null) continue;
          // If key is collection serialize the collection in a specific format
          if(key instanceof java.util.Collection) {
            StringBuffer keyStrBuff = new StringBuffer();
            Iterator iter = ((Collection)key).iterator();
            if(iter.hasNext()) {
              item = iter.next();
              if(item instanceof java.lang.Number)
                keyItemClassName = item.getClass().getName();
              else keyItemClassName = String.class.getName();
              keyStrBuff.append(item.toString());
            }// End if
            while(iter.hasNext()) {
              item = iter.next();
              keyStrBuff.append(";").append(item.toString());
            }// End while
            key2String = keyStrBuff.toString();
          }// End if
          // If key is collection serialize the colection in a specific format
          if(value instanceof java.util.Collection) {
            StringBuffer valueStrBuff = new StringBuffer();
            Iterator iter = ((Collection)value).iterator();
            if(iter.hasNext()) {
              item = iter.next();
              if(item instanceof java.lang.Number)
                valueItemClassName = item.getClass().getName();
              else valueItemClassName = String.class.getName();
              valueStrBuff.append(item.toString());
            }// End if
            while(iter.hasNext()) {
              item = iter.next();
              valueStrBuff.append(";").append(item.toString());
            }// End while
            value2String = valueStrBuff.toString();
          }// End if
          buffer.append("<Feature>\n  <Name");
          if(keyClassName != null)
            buffer.append(" className=\"").append(keyClassName).append("\"");
          if(keyItemClassName != null)
            buffer.append(" itemClassName=\"").append(keyItemClassName).append(
                    "\"");
          buffer.append(">");
          
          // use a map of keys already checked for XML validity
          StringBuffer normalizedKey = new StringBuffer(key2String);
          if (normalizedFeatureNames!=null){
            // has this key been already converted ?
            normalizedKey = (StringBuffer)normalizedFeatureNames.get(key2String);
            if (normalizedKey==null){
              // never seen so far!
              normalizedKey= combinedNormalisation(key2String);
              normalizedFeatureNames.put(key2String,normalizedKey);
            }
          }
          else normalizedKey = combinedNormalisation(key2String);
          
          buffer.append(normalizedKey);
          buffer.append("</Name>\n  <Value");
          if(valueClassName != null)
            buffer.append(" className=\"").append(valueClassName).append("\"");
          if(valueItemClassName != null)
            buffer.append(" itemClassName=\"").append(valueItemClassName).append(
                    "\"");
          buffer.append(">");
          buffer.append(combinedNormalisation(value2String));
          buffer.append("</Value>\n</Feature>\n");
        }// End if
      }// end While
      return buffer;
    }// featuresToXml
  
  
    /**
     * Combines replaceCharsWithEntities and filterNonXmlChars in a single method
     **/
    public static StringBuffer combinedNormalisation(String inputString){
      if(inputString == null) return new StringBuffer("");
      StringBuffer buffer = new StringBuffer(inputString);
      for (int i=buffer.length()-1; i>=0; i--){
  