LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
BratJSONDumper.cpp
Go to the documentation of this file.
1// Copyright (C) 2004-2012 by CEA LIST *
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6#include "BratJSONDumper.h"
8
21
22#include <boost/algorithm/string.hpp>
23#include <fstream>
24#include <queue>
25#include <tuple>
26
27using namespace std;
28using namespace Lima::Common::Misc;
29using namespace Lima::Common::AnnotationGraphs;
34using namespace boost;
35
36namespace Lima {
37namespace LinguisticProcessing {
38namespace AnalysisDumpers {
39
41
44m_useNormalizedForms(false),
45// m_firstEntity(true),
46m_firstRelation(true),
47m_firstEvent(true),
48m_attributes(),
49m_norms(),
50m_entities(),
51m_eventTriggers()
52{
54 LDEBUG << "BratJSONDumper::BratJSONDumper()";
55}
56
57
60
63 Manager* manager)
64
65{
67 LDEBUG << "BratJSONDumper::init";
68 AbstractIEDumper::init(unitConfiguration,manager);
69 // here, specific parameters for this dumper if different from AbstractIEDumper ones
70 try
71 {
72 string str=unitConfiguration.getParamsValueAtKey("useNorms");
73 if (str=="yes" || str=="1" || str=="true") {
74 m_useNormalizedForms=true;
75 }
76 }
77 catch (Common::XMLConfigurationFiles::NoSuchParam& ) { } // optional keep default
78
79}
80
81// utility function to escape endlines in JSON
82std::string jsonEscape(const std::string& str) {
83 std::string s=str;
84 boost::replace_all(s,"\n", "\\n");
85 boost::replace_all(s,"\r", "\\r");
86 boost::replace_all(s,"\t", "\\t");
87 return s;
88}
89
90// headers and footers
91void BratJSONDumper::outputGlobalHeader(std::ostream& os, const std::string& /*sourceFile*/,
92 const LimaStringText& originalText) const
93{
94 os << "{" << endl << "\"text\": \"" << jsonEscape(limastring2utf8stdstring(originalText)) << "\"," << endl;
95}
96void BratJSONDumper::outputGlobalFooter(std::ostream& os) const
97{
98 std::string sep(""); // use this trick for proper comma-separated values
99 if (m_entities.size()) {
100 os << "," << endl;
101 os << "\"entities\": [";
102 for (const auto& e: m_entities) {
103 os << sep << endl << e.second;
104 sep=",";
105 }
106 os << endl << "]";
107 }
108 if (m_eventTriggers.size()) {
109 sep="";
110 os << "," << endl;
111 os << "\"triggers\": [";
112 for (const auto& e: m_eventTriggers) {
113 os << sep << endl << e;
114 sep=",";
115 }
116 os << endl << "]";
117 }
118 if (m_attributes.size()) {
119 sep="";
120 os << "," << endl;
121 os << "\"attributes\": [";
122 for (const auto& a: m_attributes) {
123 os << sep << endl << a;
124 sep=",";
125 }
126 os << "]";
127 }
128 if (m_norms.size()) {
129 sep="";
130 os << "," << endl;
131 os << "\"normalizations\": [";
132 for (const auto& n: m_norms) {
133 os << sep << endl << n;
134 sep=",";
135 }
136 os << "]";
137 }
138 os << endl << "}" << endl;
139 // clear all stored values
140 m_attributes.clear();
141 m_norms.clear();
142 m_entities.clear();
143 m_eventTriggers.clear();
144 m_firstRelation=true;
145 m_firstEvent=true;
146}
147
148void BratJSONDumper::outputEntitiesHeader(std::ostream& /*os*/) const
149{
150 //os << "\"entities\": [";
151}
152void BratJSONDumper::outputEntitiesFooter(std::ostream& /*os*/) const
153{
154 //os << "]," << endl;
155}
156void BratJSONDumper::outputRelationsHeader(std::ostream& os) const
157{
158 os << "\"relations\": [";
159}
160void BratJSONDumper::outputRelationsFooter(std::ostream& os) const
161{
162 os << "]" << endl;
163}
164void BratJSONDumper::outputEventsHeader(std::ostream& os) const
165{
166 os << "\"events\": [";
167}
168void BratJSONDumper::outputEventsFooter(std::ostream& os) const
169{
170 os << "]," << endl;
171}
172
173
175outputEntityString(ostream& out,
176 unsigned int entityId,
177 const std::string& entityType,
178 const std::string& entityString,
179 const vector<pair<uint64_t,uint64_t> >& positions,
180 const Automaton::EntityFeatures& entityFeatures, bool noNorm) const
181{
182 //if (m_firstEntity) { m_firstEntity=false; out << endl; } else { out << "," << endl; }
183 ostringstream oss;
184
185 oss << "[ \"T" << entityId << "\", \"" << entityType << "\", ";
186 if (positions.size()==0) {
187 // use simple positions
189 LERROR << "BratJSONDumper: no positions given for entity" << entityString;
190 oss << "[[0,0]]";
191 }
192 else {
193 vector<pair<uint64_t,uint64_t> >::const_iterator posIt=positions.begin();
194 oss << "[ [" << (*posIt).first << "," << (*posIt).second << "]";
195 for (posIt++; posIt!=positions.end(); posIt++) {
196 oss << ", [" << (*posIt).first << "," << (*posIt).second << "]";
197 }
198 oss << " ]";
199 }
200 oss << " ]";
201 m_entities[entityId]=oss.str();
202 if (m_useNormalizedForms && !noNorm) {
203 bool done(false);
204 for (Automaton::EntityFeatures::const_iterator
205 featureItr=entityFeatures.begin(),features_end=entityFeatures.end();
206 featureItr!=features_end; featureItr++)
207 {
208 if (featureItr->getName()=="value") {
209 string valuestr=featureItr->getValueString();
210 // if only whitespaces, do not print it (error in brat format)
211 if (valuestr.find_first_not_of(' ') != std::string::npos) {
212 outputEntityNorm(out,entityId,valuestr);
213 done=true;
214 break;
215 }
216 }
217 }
218 if (! done) { // backoff to surface form if norm is not found
219 outputEntityNorm(out,entityId,entityString);
220 }
221 }
222}
223
225outputAttributesString(std::ostream& /*out*/,
226 unsigned int entityId,
227 std::map <std::tuple <std::size_t, std::string , std::string >, std::size_t >& mapAttributes) const
228{
229 for(auto iterAttribute = mapAttributes.begin();
230 iterAttribute!=mapAttributes.end();
231 iterAttribute++)
232 {
233 auto feature = iterAttribute->first;
234 std::size_t eId = std::get<0>(feature);
235 if( eId == entityId )
236 {
237 std::size_t attributeId = iterAttribute->second;
238 std::string featName = std::get<1>(feature);
239 std::string featValue = std::get<2>(feature);
240 ostringstream oss;
241 oss << "[ \"" << attributeId << "\", \"" << featName << "\", \"" << entityId << "\"";
242 if(featValue!=""){
243 oss << ", \"" << featValue << "\"";
244 }
245 oss << "]";
246 m_attributes.push_back(oss.str());
247 }
248 }
249}
250
252outputEntityNorm(ostream& /*out*/,
253 unsigned int entityId,
254 const std::string& entityNorm) const
255{
256 ostringstream oss;
257 // format is id normType target refdb refid reftext;
258 oss << "[ \"N" << entityId << "\", \"Reference\", \"T" << entityId << "\", \"LIMA\", \"1\", \""
259 << entityNorm << "\" ]";
260 m_norms.push_back(oss.str());
261}
262
264outputRelationString(ostream& out,
265 unsigned int relationId,
266 const std::string& relationType,
267 const std::string& sourceArgString,
268 const std::string& targetArgString) const
269{
270 QString relation = QString::fromUtf8(relationType.c_str());
271 QStringList relations = relation.split(',');
272 unsigned int i = 0;
273 for (auto& rel : relations)
274 {
275 if (rel.isEmpty())
276 {
278 LERROR << "BratJSONDumper::outputRelationString Ignoring relation with empty type:"
279 << relationId << relationType << sourceArgString
280 << targetArgString;
281 continue;
282 }
283 if (sourceArgString.empty())
284 {
286 LERROR << "BratJSONDumper::outputRelationString Ignoring relation with empty source:"
287 << relationId << relationType << sourceArgString
288 << targetArgString;
289 continue;
290 }
291 if (targetArgString.empty())
292 {
294 LERROR << "BratJSONDumper::outputRelationString Ignoring relation with empty target:"
295 << relationId << relationType << sourceArgString
296 << targetArgString;
297 continue;
298 }
299 // filter group name if present
300 string relstr=rel.toUtf8().constData();
301 if (relstr.find(".")!=string::npos) {
302 relstr=relstr.substr(relstr.find("."));
303 }
304
305 if (m_firstRelation) { m_firstRelation=false; out << endl; } else { out << "," << endl; }
306
307 out << "[ \"R" << (relationId+i) << "\", \"" << relstr << "\", ["
308 << "[\"Arg1\", \"T" << sourceArgString << "\"], "
309 << "[\"Arg2\", \"T" << targetArgString << "\"]] ]";
310 i++;
311 }
312 return i;
313}
314
316outputEventString(ostream& out,
317 unsigned int eventId,
318 unsigned int eventMentionId,
319 const std::string& /*eventMentionType*/,
320 const std::vector<unsigned int>& eventRoleId,
321 const std::vector<std::string>& eventRoleType) const
322{
323 if (m_firstEvent) { m_firstEvent=false; out << endl; } else { out << "," << endl; }
324
325 out << "[ \"E" << eventId << "\", ";
326 // mention type is now one of the roles
327 if (eventMentionId!=0) {
328 //out << eventMentionType << "T" << eventMentionId;
329 out << "\"T" << eventMentionId << "\", ";
330 m_eventTriggers.push_back(m_entities[eventMentionId]);
331 m_entities.erase(eventMentionId);
332 }
333 // event slots
334 out << "[";
335 if (eventRoleId.size()==0) {out << "]]" << endl; return; }
336// out << eventRoleType[0] << ":T" << eventRoleId[0]; // first one without space before
337// for (unsigned int i(1), n=eventRoleId.size(); i<n; i++) {
338 for (unsigned int i(0), n=eventRoleId.size(); i<n; i++) {
339 if (i>0) { out << ", "; }
340 out << "[\"" << eventRoleType[i] << "\", \"T" << eventRoleId[i] << "\"]";
341 }
342 out << " ]]"; // close event slots and global event infos
343}
344
345} // AnalysisDumpers
346} // LinguisticProcessing
347} // Lima
This file is the main header file for the data related to annotation graphs.
#define BRATJSONDUMPER_CLASSID
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
#define DUMPERLOGINIT
Defines a Factory to create Object of type Base.
return a message when a 'param' was not found
Manage initialization of InitializableObjects using configuration module and parameters.
virtual void init(Common::XMLConfigurationFiles::GroupConfigurationStructure &unitConfiguration, Manager *manager) override
initialize with parameters from configuration file.
unsigned int outputRelationString(std::ostream &out, unsigned int relationId, const std::string &relationType, const std::string &sourceArgString, const std::string &targetArgString) const override
void outputGlobalHeader(std::ostream &os, const std::string &sourceFile="", const LimaStringText &originalText=LimaStringText("")) const override
specific output functions to deal with actual output format these functions are called inside the pro...
void outputEntityNorm(std::ostream &out, unsigned int entityId, const std::string &entityNorm) const override
void outputEntityString(std::ostream &out, unsigned int entityId, const std::string &entityType, const std::string &entityString, const std::vector< std::pair< uint64_t, uint64_t > > &positions, const Automaton::EntityFeatures &entityFeatures, bool noNorm=false) const override
void outputRelationsHeader(std::ostream &os) const override
void outputEntitiesHeader(std::ostream &os) const override
void outputEventString(std::ostream &out, unsigned int eventId, unsigned int eventMentionId, const std::string &eventMentionType, const std::vector< unsigned int > &eventRoleId, const std::vector< std::string > &eventRoleType) const override
void init(Common::XMLConfigurationFiles::GroupConfigurationStructure &unitConfiguration, Manager *manager) override
initialize with parameters from configuration file.
void outputRelationsFooter(std::ostream &os) const override
void outputAttributesString(std::ostream &out, unsigned int entityId, std::map< std::tuple< std::size_t, std::string, std::string >, std::size_t > &mapAttributes) const override
void outputEntitiesFooter(std::ostream &os) const override
void outputGlobalFooter(std::ostream &os) const override
a list of generic features: each feature is unique (only one feature for a name)
define the limaStringText resource which is the text in limaString formal
std::string limastring2utf8stdstring(const Lima::LimaString &phrase, uint32_t size0)
Convert a wide string to a string , in dest up to size bytes.
std::string jsonEscape(const std::string &str)
SimpleFactory< MediaProcessUnit, BratJSONDumper > bratJSONDumperFactory(BRATJSONDUMPER_CLASSID)
NAUTITIA.
STL namespace.