/* * Copyright 2015 * Ubiquitous Knowledge Processing (UKP) Lab * Technische Universität Darmstadt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.tudarmstadt.ukp.dkpro.core.io.brat.internal.model; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; import com.fasterxml.jackson.core.JsonGenerator; public class BratAnnotationDocument { private Map<String, BratAnnotation> annotations = new LinkedHashMap<>(); private Map<String, BratAttribute> attributes = new LinkedHashMap<>(); public static BratAnnotationDocument read(Reader aReader) { BratAnnotationDocument doc = new BratAnnotationDocument(); List<BratEventAnnotation> events = new ArrayList<>(); // Read from file LineIterator lines = IOUtils.lineIterator(aReader); while (lines.hasNext()) { String line = lines.next(); switch (line.charAt(0)) { case 'T': doc.addAnnotation(BratTextAnnotation.parse(line)); break; case 'A': case 'M': doc.addAttribute(BratAttribute.parse(line)); break; case 'R': doc.addAnnotation(BratRelationAnnotation.parse(line)); break; case 'E': { BratEventAnnotation e = BratEventAnnotation.parse(line); events.add(e); doc.addAnnotation(e); break; } default: throw new IllegalStateException("Unknown annotation format: [" + line + "]"); } } // Attach attributes to annotations for (BratAttribute attr : doc.attributes.values()) { BratAnnotation target = doc.annotations.get(attr.getTarget()); if (target == null) { throw new IllegalStateException("Attribute refers to unknown annotation [" + attr.getTarget() + "]"); } target.addAttribute(attr); } // FIXME this is currently inconsistent between reading and manual creation / writing // when we read the triggers, they no longer appear as individual annotations // when we manually create the brat annotations, we leave the triggers // Attach triggers to events and remove them as individual annotations List<String> triggersIds = new ArrayList<>(); for (BratEventAnnotation event : events) { BratTextAnnotation trigger = (BratTextAnnotation) doc.annotations.get(event .getTrigger()); if (trigger == null) { throw new IllegalStateException("Trigger refers to unknown annotation [" + event.getTrigger() + "]"); } triggersIds.add(trigger.getId()); event.setTriggerAnnotation(trigger); } // Remove trigger annotations, they are owned by the event doc.annotations.keySet().removeAll(triggersIds); return doc; } public void write(JsonGenerator aJG, String aText) throws IOException { aJG.writeStartObject(); aJG.writeStringField("text", aText); aJG.writeFieldName("entities"); aJG.writeStartArray(); for (BratAnnotation ann : annotations.values()) { if (ann instanceof BratTextAnnotation) { ann.write(aJG); } } aJG.writeEndArray(); aJG.writeFieldName("relations"); aJG.writeStartArray(); for (BratAnnotation ann : annotations.values()) { if (ann instanceof BratRelationAnnotation) { ann.write(aJG); } } aJG.writeEndArray(); aJG.writeFieldName("triggers"); aJG.writeStartArray(); for (BratAnnotation ann : annotations.values()) { if (ann instanceof BratEventAnnotation) { ((BratEventAnnotation) ann).getTriggerAnnotation().write(aJG); } } aJG.writeEndArray(); aJG.writeFieldName("events"); aJG.writeStartArray(); for (BratAnnotation ann : annotations.values()) { if (ann instanceof BratEventAnnotation) { ann.write(aJG); } } aJG.writeEndArray(); aJG.writeFieldName("attributes"); aJG.writeStartArray(); for (BratAnnotation ann : annotations.values()) { for (BratAttribute attr : ann.getAttributes()) { attr.write(aJG); } } aJG.writeEndArray(); aJG.writeEndObject(); } public void write(Writer aWriter) throws IOException { // First render only the spans because brat wants to now them first for their IDs for (BratAnnotation anno : annotations.values()) { if (anno instanceof BratTextAnnotation) { write(aWriter, anno); } if (anno instanceof BratEventAnnotation) { // Just write the trigger for now BratEventAnnotation event = (BratEventAnnotation) anno; write(aWriter, event.getTriggerAnnotation()); } } // Second render all annotations that point to span annotations for (BratAnnotation anno : annotations.values()) { // Skip the text annotations, we already rendered them in the first pass if (anno instanceof BratTextAnnotation) { continue; } write(aWriter, anno); } } private void write(Writer aWriter, BratAnnotation aAnno) throws IOException { aWriter.append(aAnno.toString()); aWriter.append('\n'); for (BratAttribute attr : aAnno.getAttributes()) { aWriter.append(attr.toString()); aWriter.append('\n'); } } public void addAttribute(BratAttribute aAttribute) { attributes.put(aAttribute.getId(), aAttribute); } public void addAnnotation(BratAnnotation aAnnotation) { annotations.put(aAnnotation.getId(), aAnnotation); } public BratAnnotation getAnnotation(String aId) { return annotations.get(aId); } public Collection<BratAnnotation> getAnnotations() { return annotations.values(); } }