001/** 
002 * Copyright (c) 2007-2008, Regents of the University of Colorado 
003 * All rights reserved.
004 * 
005 * Redistribution and use in source and binary forms, with or without
006 * modification, are permitted provided that the following conditions are met:
007 * 
008 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
009 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
010 * Neither the name of the University of Colorado at Boulder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
011 * 
012 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
013 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
014 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
015 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
016 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
017 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
018 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
019 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
020 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
021 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
022 * POSSIBILITY OF SUCH DAMAGE. 
023 */
024package org.cleartk.corpus.timeml;
025
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030
031import org.apache.uima.cas.Feature;
032import org.apache.uima.cas.text.AnnotationFS;
033import org.apache.uima.jcas.JCas;
034import org.apache.uima.jcas.tcas.Annotation;
035import org.cleartk.timeml.type.Anchor;
036import org.cleartk.timeml.type.DocumentCreationTime;
037import org.cleartk.timeml.type.Event;
038import org.cleartk.timeml.type.TemporalLink;
039import org.cleartk.timeml.type.Time;
040import org.jdom2.Element;
041import org.xml.sax.Attributes;
042import org.xml.sax.helpers.AttributesImpl;
043
044/**
045 * <br>
046 * Copyright (c) 2007-2008, Regents of the University of Colorado <br>
047 * All rights reserved.
048 * 
049 * 
050 * @author Steven Bethard
051 * 
052 */
053public class TimeMlUtil {
054
055  private static final Map<String, String> elementNames;
056
057  private static final List<NamePair> eventAttributes;
058
059  private static final List<NamePair> timeAttributes;
060
061  private static final List<NamePair> tlinkAttributes;
062
063  private static final Map<String, List<NamePair>> timemlAttributeLists;
064
065  private static final Map<Class<?>, List<NamePair>> uimaAttributeLists;
066
067  static {
068    elementNames = new HashMap<String, String>();
069    eventAttributes = new ArrayList<NamePair>();
070    timeAttributes = new ArrayList<NamePair>();
071    tlinkAttributes = new ArrayList<NamePair>();
072    timemlAttributeLists = new HashMap<String, List<NamePair>>();
073    uimaAttributeLists = new HashMap<Class<?>, List<NamePair>>();
074
075    elementNames.put("Document", "TimeML");
076    elementNames.put(Event.class.getName(), "EVENT");
077    elementNames.put(Time.class.getName(), "TIMEX3");
078    elementNames.put(DocumentCreationTime.class.getName(), "TIMEX3");
079    elementNames.put(TemporalLink.class.getName(), "TLINK");
080
081    eventAttributes.add(new NamePair("eid", "id"));
082    eventAttributes.add(new NamePair("eiid", "eventInstanceID"));
083    eventAttributes.add(new NamePair("class", "eventClass"));
084    for (String name : new String[] {
085        "stem",
086        "pos",
087        "tense",
088        "aspect",
089        "cardinality",
090        "polarity",
091        "modality",
092        "signalID" }) {
093      eventAttributes.add(new NamePair(name, name));
094    }
095
096    timeAttributes.add(new NamePair("tid", "id"));
097    timeAttributes.add(new NamePair("type", "timeType"));
098    for (String name : new String[] {
099        "beginPoint",
100        "endPoint",
101        "quant",
102        "freq",
103        "functionInDocument",
104        "temporalFunction",
105        "value",
106        "valueFromFunction",
107        "mod" }) {
108      timeAttributes.add(new NamePair(name, name));
109    }
110
111    tlinkAttributes.add(new NamePair("lid", "id"));
112    tlinkAttributes.add(new NamePair("relType", "relationType"));
113    tlinkAttributes.add(new NamePair("signalID", "signalID"));
114
115    timemlAttributeLists.put("EVENT", eventAttributes);
116    timemlAttributeLists.put("MAKEINSTANCE", eventAttributes);
117    timemlAttributeLists.put("TIMEX3", timeAttributes);
118    timemlAttributeLists.put("TLINK", tlinkAttributes);
119
120    uimaAttributeLists.put(Event.class, eventAttributes);
121    uimaAttributeLists.put(Time.class, timeAttributes);
122    uimaAttributeLists.put(TemporalLink.class, tlinkAttributes);
123  }
124
125  public static void copyAttributes(Element element, Annotation annotation, JCas jCas) {
126    for (NamePair names : timemlAttributeLists.get(element.getName().toUpperCase())) {
127      String featureValue = element.getAttributeValue(names.timemlName);
128      if (featureValue != null) {
129        String className = annotation.getClass().getName();
130        String uimaName = String.format("%s:%s", className, names.uimaName);
131        Feature feature = jCas.getTypeSystem().getFeatureByFullName(uimaName);
132        annotation.setFeatureValueFromString(feature, featureValue);
133      }
134    }
135  }
136
137  public static void removeInconsistentAttributes(Element element, Annotation annotation, JCas jCas) {
138    for (NamePair names : timemlAttributeLists.get(element.getName().toUpperCase())) {
139      String newValue = element.getAttributeValue(names.timemlName);
140      String className = annotation.getClass().getName();
141      String uimaName = String.format("%s:%s", className, names.uimaName);
142      Feature feature = jCas.getTypeSystem().getFeatureByFullName(uimaName);
143      String oldValue = annotation.getFeatureValueAsString(feature);
144      if (oldValue != null && !oldValue.equals(newValue)) {
145        annotation.setFeatureValueFromString(feature, null);
146      }
147    }
148  }
149
150  public static String toTimeMLElementName(AnnotationFS annotation) {
151    if (annotation instanceof Event) {
152      return "EVENT";
153    } else if (annotation instanceof Time) {
154      return "TIMEX3";
155    } else if (annotation instanceof TemporalLink) {
156      return "TLINK";
157    } else {
158      return null;
159    }
160  }
161
162  public static Attributes toTimeMLAttributes(AnnotationFS annotation, String elementName) {
163    // add attributes that have a simple one-to-one mapping
164    AttributesImpl attributes = new AttributesImpl();
165    for (NamePair names : timemlAttributeLists.get(elementName)) {
166      Feature feature = annotation.getType().getFeatureByBaseName(names.uimaName);
167      addAttribute(attributes, names.timemlName, annotation.getFeatureValueAsString(feature));
168    }
169    // add un-mappable attributes
170    if (annotation instanceof TemporalLink) {
171      TemporalLink tlink = (TemporalLink) annotation;
172      Anchor source = tlink.getSource();
173      Anchor target = tlink.getTarget();
174      if (source instanceof Event) {
175        Event event = (Event) source;
176        addAttribute(attributes, "eventID", event.getId());
177        addAttribute(attributes, "eventInstanceID", event.getEventInstanceID());
178      } else if (source instanceof Time) {
179        addAttribute(attributes, "timeID", source.getId());
180      }
181      if (target instanceof Event) {
182        Event event = (Event) target;
183        addAttribute(attributes, "relatedToEvent", event.getId());
184        addAttribute(attributes, "relatedToEventInstance", event.getEventInstanceID());
185      } else if (target instanceof Time) {
186        addAttribute(attributes, "relatedToTime", target.getId());
187      }
188    }
189    return attributes;
190  }
191
192  public static Attributes toTempEval2007Attributes(AnnotationFS annotation, String elementName) {
193    // add attributes that have a simple one-to-one mapping
194    AttributesImpl attributes = new AttributesImpl();
195    for (NamePair names : timemlAttributeLists.get(elementName)) {
196      if (!names.timemlName.equals("eiid")) {
197        Feature feature = annotation.getType().getFeatureByBaseName(names.uimaName);
198        addAttribute(attributes, names.timemlName, annotation.getFeatureValueAsString(feature));
199      }
200    }
201    // add un-mappable attributes
202    if (annotation instanceof TemporalLink) {
203      TemporalLink tlink = (TemporalLink) annotation;
204      Anchor source = tlink.getSource();
205      Anchor target = tlink.getTarget();
206      if (source instanceof Event) {
207        Event event = (Event) source;
208        addAttribute(attributes, "eventID", event.getId());
209      } else if (source instanceof Time) {
210        addAttribute(attributes, "timeID", source.getId());
211      }
212      if (target instanceof Event) {
213        Event event = (Event) target;
214        addAttribute(attributes, "relatedToEvent", event.getId());
215      } else if (target instanceof Time) {
216        addAttribute(attributes, "relatedToTime", target.getId());
217      }
218    }
219    return attributes;
220  }
221
222  private static void addAttribute(AttributesImpl attributes, String name, String value) {
223    if (value != null) {
224      attributes.addAttribute("", name, name, "CDATA", value);
225    }
226  }
227
228  private static class NamePair {
229    public String timemlName;
230
231    public String uimaName;
232
233    public NamePair(String timemlName, String uimaName) {
234      this.timemlName = timemlName;
235      this.uimaName = uimaName;
236    }
237  }
238}