LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
CoreXmlReaderClient.cpp
Go to the documentation of this file.
1// Copyright 2009-2021 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
10
22#include <iostream>
23#include <fstream>
24#include <string>
25#include <typeinfo>
26#include <cassert>
27
28using namespace Lima;
29using namespace std;
30using namespace Lima::Common;
31using namespace Lima::Common::Misc;
33using namespace Lima::DocumentsReader;
34
35namespace Lima
36{
37namespace XmlReader
38{
39
41/*m_delegate(0),*/m_handler(nullptr)
42{
43#ifdef DEBUG_LP
45 LDEBUG << "CoreXmlReaderClient::CoreXmlReaderClient";
46#endif
47 auto& conf = configuration.getModuleConfiguration("lp-structuredXmlreaderclient");
48 m_documentReader = new DocumentsReader::DocumentReader(conf);
49 m_documentReader->setLinguisticXMLDocHandler(this);
50 m_emptyTextChars = utf8stdstring2limastring(" \t\n");
51
52}
53
55{
56 delete m_documentReader;
57}
58
60{
61 m_handler->m_parentlastOpenedNode = 0;
62 m_handler->set_LastStructureId(m_handler->get_LastStructureId() + 1);
63 m_handler->set_lastNodeId(1);
64 m_handler->m_openedNodes.clear();
65 m_handler->m_openedNodes.push_back(0);
66 startNode(contentDocument, false);
67}
68
70{
71 // last element
72 auto absElement = contentDocument.back();
73 auto element =
74 dynamic_cast<DocumentsReader::HierarchyDocumentElement *>(absElement);
75
76 // must be a structured Element
77 assert(element);
78 // get byte offset before the beginning of the closing tag
79 auto offset = m_handler->shiftFrom()->correct_offset(0, element->getOffset());
80 element->setIntValue("offEndPrpty", offset);
81// element->setIntValue("offEndPrpty", element->getOffset());
82
83
84#ifdef DEBUG_LP
86 LDEBUG << "CoreXmlReaderClient::endHierarchy("
87 << element->getElementName() << ")"
88 << " offBegPrpty "
89 << element->getIntValue("offBegPrpty").first
90 << " offEndPrpty "
91 << element->getIntValue("offEndPrpty").first;
92#endif
93
94 // register properties and close block
95 m_handler->endNode(*element);
96}
97
99 const DocumentsReader::ContentStructuredDocument &contentDocument)
100{
101 startNode(contentDocument, true);
102}
103
105 const DocumentsReader::ContentStructuredDocument &contentDocument)
106{
107#ifdef DEBUG_LP
109 LDEBUG << "CoreXmlReaderClient::endIndexing";
110 #endif
111 // last element
112 auto absElement = contentDocument.back();
113 auto element =
114 dynamic_cast<DocumentsReader::IndexingDocumentElement *>(absElement);
115
116 // must be a structured Element
117 if (element == nullptr)
118 {
120 LERROR << "CoreXmlReaderClient::endIndexing must be a structured Element" ;
121 assert(false);
122 }
123 // get byte offset before the beginning of the closing tag
124 auto offset = m_handler->shiftFrom()->correct_offset(0, element->getOffset());
125 element->setIntValue("offEndPrpty", offset);
126// element->setIntValue("offEndPrpty", element->getOffset());
127
128
129#ifdef DEBUG_LP
130 LDEBUG << "CoreXmlReaderClient::endIndexing("
131 << element->getElementName() << ")"
132 << " offBegPrpty "
133 << element->getIntValue("offBegPrpty").first
134 << " offEndPrpty "
135 << element->getIntValue("offEndPrpty").first;
136#endif
137
138 // register properties and close block
139 m_handler->endNode(*element);
140}
141
142
144 const DocumentsReader::ContentStructuredDocument &contentDocument,
145 const Lima::LimaString &text,
146 unsigned long int offset,
147 const string tagName)
148{
149#ifdef DEBUG_LP
151#endif
152
153 auto rtext = m_handler->shiftFrom()->rebuild_text(text, offset);
154 if(std::string(rtext.toStdString()).find_first_not_of(m_emptyTextChars.toStdString()) == string::npos) {
155#ifdef DEBUG_LP
156 LDEBUG << "CoreXmlReaderClient::empty text, not analyzed";
157#endif
158 return;
159 }
160
161 AbstractStructuredDocumentElement* absElement = contentDocument.back();
163 dynamic_cast<DocumentsReader::IndexingDocumentElement*>(absElement);
164 std::string elementName = element->getElementName().toUtf8().constData();
165 const PropagatedProperties& properties = element->getPropertyList();
166
167#ifdef DEBUG_LP
168 if( logger.loggingLevel() == QsLogging::DebugLevel )
169 {
170 LDEBUG << "CoreXmlReaderClient::handle [" << rtext << "], offset ="
171 << offset << ", tagName =" << tagName << ", elementName ="
172 << elementName << ", properties = " << properties;
173 }
174 else if( logger.loggingLevel() == QsLogging::InfoLevel )
175#endif
176 {
177 // Chercher les analyses diponibles
179 LINFO << "CoreXmlReaderClient::handle"
180 << "[" << rtext.left(80) << "], offset =" << offset
181 << ", tagName =" << tagName << ", elementName ="
182 << elementName << ", properties = " << properties;
183 }
184 m_docMetaData["StartOffset"] = std::to_string(offset);
185 m_docMetaData["ElementName"] = tagName;
186 // Set the language to the one associated at init time to the current tag
187 if (m_mapTagMedia.find(elementName) != m_mapTagMedia.end())
188 {
189#ifdef DEBUG_LP
190 LDEBUG << "CoreXmlReaderClient::handle using media" << m_mapTagMedia[elementName];
191#endif
192 m_docMetaData["Lang"] = m_mapTagMedia[elementName];
193 }
194 else if (!m_defaultMedia.empty())
195 {
196#ifdef DEBUG_LP
197 LDEBUG << "CoreXmlReaderClient::handle using default media" << m_defaultMedia;
198#endif
199 m_docMetaData["Lang"] = m_defaultMedia;
200 }
201 else
202 {
204 LERROR << "CoreXmlReaderClient::handle no media associated to tag"
205 << elementName
206 << "and no default media is set. metadata Lang will not be set.";
207 }
208 // cast element to GenericDocumentProperties
209// Common::Misc::GenericDocumentProperties &props = *element;
210 // get byte offset after end of element
211 auto offsetIndexingNode = element->getIntValue("offBegPrpty").first;
212 m_docMetaData["StartOffsetIndexingNode"] = std::to_string(offsetIndexingNode);
213
214 auto strText = rtext.toStdString();
215
216 m_handler->handleProc(
217 tagName,
218 strText,
219 m_docMetaData,
220 m_docMetaData["pipeline"],
221 m_mapHandlers,
222 std::set<std::string>());
223}
224
225
228 const std::string &data)
229{
230
231 if(!property.getId().compare("langPrpty")) {
232 if(data.compare(m_docMetaData["Lang"])) {
233// LWARN << "StructuredXmlReaderLinguisticProcessingClient::handleProperty: "
234// << "it is forbidden to change language inside an indexing unit!";
235// LWARN << data << " != " << m_docMetaData["Lang"];
236 } else {
237 m_docMetaData["Lang"] = data;
238 }
239 }
240 if(!property.getId().compare("identPrpty")) {
241 std::string ident = data;
242 std::replace( ident.begin(), ident.end(), ',', '_');
243 m_docMetaData["Filename"].append(data);
244 m_docMetaData["docid"] = ident;
245 }
246 if(!property.getId().compare("pipelineProperty"))
247 m_docMetaData["pipeline"].append(data);
248
249 // added location
250 if(!property.getId().compare("locationPrpty")) {
251 m_docMetaData["location"] = data;
252 }
253}
254
257std::shared_ptr<AnalysisContent> CoreXmlReaderClient::analyze(
258 const std::string &text,
259 const std::map<std::string, std::string>& metaData,
260 const std::string &pipeline,
261 const std::map<std::string, Lima::AbstractAnalysisHandler *>& handlers,
262 const std::set<std::string>& inactiveUnits) const
263{
264 (void) handlers; // avoid warning
265 (void) inactiveUnits; // avoid warning
266
267
268#ifdef DEBUG_LP
270
271 LDEBUG << "CoreXmlReaderClient::analyze(... pipeline='" << pipeline << "')";
272#endif
273 if (m_handler==0)
274 {
276 LERROR << "Error XMLreader: no handler set. It will crash.";
277 }
278// if ( !m_documentReader->initWithString ( text ) )
279// {
280// LERROR << "CoreXmlReaderClient::analyze: can't init reader with text ! ";
281// throw XmlReaderException();
282// }
283// LDEBUG << "CoreXmlReaderClient::analyze after initWithString";
284//
285 std::map<std::string, std::string>* docMetadataPtr =
286 const_cast<std::map<std::string, std::string>*>(&m_docMetaData);
287 *docMetadataPtr = metaData;
288 (*docMetadataPtr) ["pipeline"] = pipeline;
289
291 m_handler->startDocument(dummyProperties); // NB : ne fait rien!
292#ifdef DEBUG_LP
293 LDEBUG << "CoreXmlReaderClient::analyze: start analyze"
294 << (*docMetadataPtr) ["filePath"] << " ; pipeline='"
295 << std::string((*docMetadataPtr) ["pipeline"]) << "' ; language='"
296 << std::string((*docMetadataPtr)["Lang"]) << "'";
297#endif
298 m_handler->set_lastUri(string((*docMetadataPtr) ["filePath"]));
299 m_handler->set_lang(string((*docMetadataPtr) ["Lang"]));
300
301 if(!m_documentReader->initWithString(QString::fromStdString(text))) {
303 LERROR << "CoreXmlReaderClient::analyze: can't init reader with text !";
304 throw XmlReaderException("CoreXmlReaderClient::analyze: can't init reader with text !");
305 }
306#ifdef DEBUG_LP
307 LDEBUG << "CoreXmlReaderClient::analyze after initWithString";
308#endif
309
310#ifndef DEBUG_LP
311 try {
312#endif
313 m_documentReader->readXMLDocument();
314#ifndef DEBUG_LP
317 LERROR << "Error in XMLreader: " << e.what();
318 } catch (const Lima::LimaException& e) {
320 LERROR << "Error in XMLreader: " << e.what();
321 }
322#endif
323 m_handler->endDocument();
324 return std::make_shared<AnalysisContent>();
325}
326
327void CoreXmlReaderClient::startNode(const DocumentsReader::ContentStructuredDocument &contentDocument,
328 bool isIndexing)
329{
330 AbstractStructuredDocumentElement *absElement = contentDocument.back();
333 assert(element);
334#ifdef DEBUG_LP
336 LDEBUG << "CoreXmlReaderClient::startNode(" << element->getElementName() << ")";
337#endif
338
339 // nom du fichier de la ligne de commande prioritaire
340 element->GenericDocumentProperties::setStringValue("srcePrpty", m_docMetaData["FileName"]);
341 // set the language property to the value associated to the current tag
342 if(m_mapTagMedia.find(element->getElementName().toUtf8().constData()) != m_mapTagMedia.end()) {
343#ifdef DEBUG_LP
344 LDEBUG << "CoreXmlReaderClient::startNode() set langPrpty to: " << m_mapTagMedia[element->getElementName().toUtf8().constData()];
345#endif
346 element->GenericDocumentProperties::setStringValue("langPrpty", m_mapTagMedia[element->getElementName().toUtf8().constData()]);
347 }
348 element->GenericDocumentProperties::setStringValue("encodPrpty", "UTF8");
349 // set date as today
350 element->GenericDocumentProperties::setDateValue("indexDatePrpty", QDate::currentDate());
351
352#if 0
353 if(!m_docMetaData["type"].empty()) {
354 element->GenericDocumentProperties::setStringValue("typPrpty", m_docMetaData["type"]);
355#ifdef DEBUG_LP
356 LDEBUG << "CoreXmlReaderClient::startNode() set typPrpty to: " << m_docMetaData["type"];
357#endif
358 }
359#endif
360
361
362#ifdef DEBUG_LP
363 LDEBUG << "CoreXmlReaderClient::startNode m_handler::startNode(" << element->getElementName() << ")";
364#endif
365 m_handler->startNode(element->getElementName().toUtf8().constData(), isIndexing);
366
367 element->GenericDocumentProperties::setIntValue("StructureId", m_handler->get_LastStructureId());
368 if(m_handler->m_openedNodes.empty()) {
369 // no lastOpenedNode : may happen if no hierarchy node in file (root node is indexing node)
370#ifdef DEBUG_LP
371 LDEBUG << "Warning: No hierarchy node => no NodeId in document properties";
372#endif
373 } else {
374 element->GenericDocumentProperties::setIntValue("NodeId", *m_handler->m_openedNodes.rbegin());
375 }
376 element->GenericDocumentProperties::setIntValue("ContentId", m_handler->get_LastContentId());
377}
378
380{
381#ifdef DEBUG_LP
383 LDEBUG << "CoreXmlReaderClient::setAnalysisHandler (" << handlerId << ", "
384 << handler << ")";
385#endif
386 if (m_mapHandlers.find(handlerId) != m_mapHandlers.end()) {
388 LERROR << "Error: CoreXmlReaderClient::setAnalysisHandler already contains a handler with the ID"
389 << handlerId;
390 return;
391 }
392 auto abstractHandler = dynamic_cast<AbstractXmlDocumentHandler*>(handler);
393 if(abstractHandler != 0) {
394 // lien avec les clients d'analyse
395 m_handler = abstractHandler;
397#ifdef DEBUG_LP
398 LDEBUG << "CoreXmlReaderClient::setAnalysisHandler shiftFrom is " << m_handler->shiftFrom().get();
399#endif
400 m_documentReader->setShiftFrom(m_handler->shiftFrom());
401 m_mapHandlers.insert(make_pair(handlerId, handler));
402 } else {
404 LERROR << "Error: handler " << handlerId
405 << " is not compatible with XML analysis. Segmentation fault to come...";
406 }
407}
408
409void CoreXmlReaderClient::releaseAnalysisHandler(const std::string &handlerId)
410{
411#ifdef DEBUG_LP
413 LDEBUG << "CoreXmlReaderClient::releaseAnalysisHandler (" << handlerId << ")";
414#endif
415 if (m_mapHandlers.find(handlerId) == m_mapHandlers.end()) {
417 LERROR << "Error: CoreXmlReaderClient::releaseAnalysisHandler does not contain a handler with the ID" << handlerId;
418 return;
419 }
420 delete m_mapHandlers[handlerId];
421 m_mapHandlers.erase(handlerId);
422}
423
424//===========================================================================
425// Factory
426//===========================================================================
427CoreXmlReaderClientFactory::CoreXmlReaderClientFactory() :
428 AbstractXmlReaderClientFactory("lp-structuredXmlreaderclient")
429{}
430
433
434std::unique_ptr< CoreXmlReaderClientFactory > CoreXmlReaderClientFactory::s_instance(new CoreXmlReaderClientFactory());
435
436//-----------------------------------------
437// Configuration du lecteur XML
438//-----------------------------------------
441 const std::string& defaultMedia,
442 const std::deque<std::string>& medias,
443 const std::deque<std::string>& pipelines)
444{
445 (void) configuration; // avoid warning
446 m_defaultMedia = defaultMedia; // avoid warning
447 (void) medias; // avoid warning
448 (void) pipelines; // avoid warning
449}
450
451//-----------------------------------------
452// Creation du client de lecture XML
453// Creation des clients d'analyse
454// Associe
455//-----------------------------------------
457{
458#ifdef DEBUG_LP
460 LDEBUG << "CoreXmlReaderClientFactory::createClient";
461#endif
462
463 std::shared_ptr< AbstractXmlReaderClient > client(new CoreXmlReaderClient(*configuration));
464
465 // containeur (map) permettant de les retrouver un client d'analyse
466 // a partir du nom de la fabrique
467 std::map<std::string, std::shared_ptr< AbstractProcessingClient > > mapMediaClient;
468
469 // parcourt des media disponibles: crée les client d'analyse (PC) nécessaires
470 for(auto ItrMedia = m_mapMediaFactory.cbegin();
471 ItrMedia != m_mapMediaFactory.cend(); ItrMedia++)
472 {
473 string media = ItrMedia->first;
474 string PCfactoryName = ItrMedia->second;
475#ifdef DEBUG_LP
476 LDEBUG << "Media [" << media << "] is analyzed by [" << PCfactoryName
477 << "]";
478#endif
479 std::shared_ptr< Lima::ProcessingClientFactory >PCfactory = getFactoryFromId(PCfactoryName);
480
481 if(mapMediaClient.find(PCfactoryName) == mapMediaClient.end())
482 {
483 std::shared_ptr< AbstractProcessingClient > limaClient(PCfactory->createClient("lima-coreclient"));
484 mapMediaClient[PCfactoryName] = limaClient;
485// LDEBUG << "mapMediaClient insert " << PCfactoryName << " (" << (void *)PCfactory << ") " << media << " " << client << " " << mapMediaClient[FactoryName];
486 }
487 }
488
489 // lien des noms de balises (tags) aux clients d'analyse
490 for(auto ItrTags = m_mapTagMedia.begin(); ItrTags != m_mapTagMedia.end(); ItrTags++) {
491 string TagName = ItrTags->first;
492 string media = ItrTags->second;
493 if (m_mapMediaFactory.find(media) == m_mapMediaFactory.end())
494 {
496 LINFO << "Tag [" << TagName << "] corresponding to media [" << media << "] has no factory associated";
497 continue;
498 }
499 std::string PCfactoryName = m_mapMediaFactory.find(media)->second;
500#ifdef DEBUG_LP
501 LDEBUG << "Tag [" << TagName << "] correspond to media [" << media << "], analysed by [" << PCfactoryName << "]";
502#endif
503
504 std::shared_ptr< AbstractProcessingClient > PCclient = mapMediaClient[m_mapMediaFactory.find(media)->second];
505
506 client->m_processingClientHandler.setAnalysisClient(TagName, PCclient);
507 }
508 // Gives the tag to language map to the client to allow it to retrieve the language at analysis time
509 client->setMapTagMedia(m_mapTagMedia);
510 client->setDefaultMedia(m_defaultMedia);
511 client->setDocumentPropertyConfiguration(configuration);
512
513 return client;
514}
515
516} // XmlReader
517} // Lima
#define LDEBUG
Definition LimaCommon.h:157
#define LINFO
Definition LimaCommon.h:158
#define LERROR
Definition LimaCommon.h:161
#define XMLREADERCLIENTLOGINIT
The AbstractAnalysisHandler class defines the callback interface: the functions that are to be define...
virtual void handleProc(const std::string &tagName, const std::string &content, const std::map< std::string, std::string > &metaData, const std::string &pipeline, const std::map< std::string, AbstractAnalysisHandler * > &handlers=std::map< std::string, AbstractAnalysisHandler * >(), const std::set< std::string > &inactiveUnits=std::set< std::string >())
virtual void setAnalysisClients(std::map< std::string, std::shared_ptr< AbstractProcessingClient > > clients)
virtual std::map< std::string, std::shared_ptr< AbstractProcessingClient > > getAnalysisClients() const
std::shared_ptr< const ShiftFrom > shiftFrom() const
virtual void endDocument()=0
notify the end of the document
virtual void startDocument(const Common::Misc::GenericDocumentProperties &props)=0
notify the start of a new document, and give its properties
virtual void startNode(const std::string &elementName, bool forIndexing)=0
notify the start of a new hierarchyNode
virtual void endNode(const Common::Misc::GenericDocumentProperties &props)=0
notify the end of a hierarchyNode
abstract handler for XML processing : just inherits from different handlers
std::pair< uint64_t, bool > getIntValue(std::string propName) const
Read access functions for "only once valued" property propName.
Parser class for the lima's xml configuration files.
ModuleConfigurationStructure & getModuleConfiguration(const std::string &moduleName)
Partie d'un document structure decodee avant analyse.
void setShiftFrom(std::shared_ptr< const ShiftFrom > shiftFrom)
void setLinguisticXMLDocHandler(StructuredXmlDocumentHandler *handler)
bool readXMLDocument()
read the next element in the current file (initFile must have been
bool initWithString(const QString &text)
Element d'un document XML dont content est indexee Exemple <section lang="fre">yeah</section> Il peut...
const std::string & getId() const
get the object id
The main LIMA exception class.
Definition LimaCommon.h:262
virtual const char * what() const override
Definition LimaCommon.h:280
STRUCT_ID get_LastStructureId()
Accesseur de lastStructureId.
void set_LastStructureId(STRUCT_ID)
A factory for the AbstractXmlReaderClient: contains the registration of all implemented clients that ...
std::shared_ptr< Lima::ProcessingClientFactory > getFactoryFromId(const std::string &id) const
std::map< std::string, std::string > m_mapMediaFactory
std::map< std::string, std::string > m_mapTagMedia
Lima::AbstractProcessingClientHandler m_processingClientHandler
std::map< std::string, std::string > m_mapTagMedia
fabrique du client d'analyse de document XML
void configure(const Lima::Common::XMLConfigurationFiles::XMLConfigurationFileParser &configuration, const std::string &defaultMedia, const std::deque< std::string > &medias, const std::deque< std::string > &pipelines) override
std::shared_ptr< AbstractXmlReaderClient > createClient(Lima::Common::XMLConfigurationFiles::XMLConfigurationFileParser *configuration) const override
This function create a XmlReader client
client de lecture des fichier XML faisant appel aux clients d'analyse Lors de la lecture d'un fichier...
void endHierarchy(const DocumentsReader::ContentStructuredDocument &contentDocument) override
void setAnalysisHandler(const std::string &handlerId, Lima::AbstractAnalysisHandler *handler) override
associe un handler recupérant l'analyse XML
void handleProperty(const DocumentsReader::DocumentPropertyType &property, const std::string &data) override
void startHierarchy(const DocumentsReader::ContentStructuredDocument &contentDocument) override
void releaseAnalysisHandler(const std::string &handlerId) override
deletes the analysis handler with the given id and removes it
CoreXmlReaderClient(Lima::Common::XMLConfigurationFiles::XMLConfigurationFileParser &configuration)
constructeur
void startIndexing(const DocumentsReader::ContentStructuredDocument &contentDocument) override
void endIndexing(const DocumentsReader::ContentStructuredDocument &contentDocument) override
std::shared_ptr< AnalysisContent > analyze(const std::string &content, const std::map< std::string, std::string > &metaData, const std::string &pipeline, const std::map< std::string, Lima::AbstractAnalysisHandler * > &handlers=std::map< std::string, Lima::AbstractAnalysisHandler * >(), const std::set< std::string > &inactiveUnits=std::set< std::string >()) const override
analyse effective d'un fichier XML.
void handle(const DocumentsReader::ContentStructuredDocument &contentDocument, const Lima::LimaString &text, unsigned long int offset, const std::string tagName) override
callback to the handler.
LimaString utf8stdstring2limastring(const std::string &src)
NAUTITIA.
QString LimaString
Definition LimaString.h:33
@ DebugLevel
Definition QsLog.h:49
@ InfoLevel
Definition QsLog.h:50
STL namespace.