Project

General

Profile

« Previous | Next » 

Revision 9c810b9f

Added by Andreas Müller over 12 years ago

improvements to markup import

View differences:

cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupDocumentImport.java
9 9

  
10 10
package eu.etaxonomy.cdm.io.markup;
11 11

  
12
import java.util.ArrayList;
13 12
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Iterator;
16 13
import java.util.LinkedList;
17
import java.util.List;
18 14
import java.util.Map;
19 15
import java.util.Queue;
20
import java.util.Set;
21 16
import java.util.UUID;
22
import java.util.regex.Matcher;
23
import java.util.regex.Pattern;
24 17

  
25 18
import javax.xml.stream.FactoryConfigurationError;
19
import javax.xml.stream.Location;
26 20
import javax.xml.stream.XMLEventReader;
27 21
import javax.xml.stream.XMLStreamException;
22
import javax.xml.stream.events.Attribute;
28 23
import javax.xml.stream.events.StartElement;
29 24
import javax.xml.stream.events.XMLEvent;
30 25

  
31
import org.apache.commons.lang.CharUtils;
32 26
import org.apache.commons.lang.StringUtils;
33 27
import org.apache.log4j.Logger;
34
import org.jdom.Attribute;
35
import org.jdom.Element;
36 28
import org.springframework.beans.factory.annotation.Autowired;
37 29
import org.springframework.security.access.PermissionEvaluator;
38 30
import org.springframework.security.authentication.AuthenticationManager;
39
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
40 31
import org.springframework.security.core.Authentication;
41
import org.springframework.security.core.context.SecurityContext;
42
import org.springframework.security.core.context.SecurityContextHolder;
43 32
import org.springframework.stereotype.Component;
44 33

  
45
import eu.etaxonomy.cdm.common.CdmUtils;
46
import eu.etaxonomy.cdm.common.ResultWrapper;
47
import eu.etaxonomy.cdm.common.XmlHelp;
48 34
import eu.etaxonomy.cdm.io.common.ICdmIO;
49 35
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
50
import eu.etaxonomy.cdm.io.markup.UnmatchedLeads.UnmatchedLeadsKey;
51
import eu.etaxonomy.cdm.model.agent.Person;
52 36
import eu.etaxonomy.cdm.model.agent.Team;
53 37
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
54
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
55
import eu.etaxonomy.cdm.model.common.Annotation;
56
import eu.etaxonomy.cdm.model.common.AnnotationType;
57 38
import eu.etaxonomy.cdm.model.common.CdmBase;
58
import eu.etaxonomy.cdm.model.common.Credit;
39
import eu.etaxonomy.cdm.model.common.Extension;
59 40
import eu.etaxonomy.cdm.model.common.ExtensionType;
60
import eu.etaxonomy.cdm.model.common.ISourceable;
61 41
import eu.etaxonomy.cdm.model.common.Language;
62
import eu.etaxonomy.cdm.model.common.Marker;
63
import eu.etaxonomy.cdm.model.common.MarkerType;
42
import eu.etaxonomy.cdm.model.common.TermVocabulary;
64 43
import eu.etaxonomy.cdm.model.common.TimePeriod;
65
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
66
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
67 44
import eu.etaxonomy.cdm.model.description.Feature;
68
import eu.etaxonomy.cdm.model.description.KeyStatement;
69
import eu.etaxonomy.cdm.model.description.PolytomousKey;
70
import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
71 45
import eu.etaxonomy.cdm.model.description.TaxonDescription;
72 46
import eu.etaxonomy.cdm.model.description.TextData;
73 47
import eu.etaxonomy.cdm.model.name.BotanicalName;
48
import eu.etaxonomy.cdm.model.name.CultivarPlantName;
74 49
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
75
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
76
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
77 50
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
51
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
52
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
78 53
import eu.etaxonomy.cdm.model.name.NonViralName;
79 54
import eu.etaxonomy.cdm.model.name.Rank;
80
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
81
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
82
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
83
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
84
import eu.etaxonomy.cdm.model.occurrence.Specimen;
85
import eu.etaxonomy.cdm.model.reference.IBook;
55
import eu.etaxonomy.cdm.model.reference.IArticle;
86 56
import eu.etaxonomy.cdm.model.reference.IJournal;
87 57
import eu.etaxonomy.cdm.model.reference.Reference;
88 58
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
89
import eu.etaxonomy.cdm.model.reference.ReferenceType;
90 59
import eu.etaxonomy.cdm.model.taxon.Classification;
91 60
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
92 61
import eu.etaxonomy.cdm.model.taxon.Taxon;
93
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
94 62
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
95
import eu.etaxonomy.cdm.permission.CdmPermissionEvaluator;
96 63
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
97 64
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
98 65

  
......
103 70
 */
104 71
@Component
105 72
public class MarkupDocumentImport  extends MarkupImportBase implements ICdmIO<MarkupImportState> {
73
	private static final String ORIGINAL_DETERMINATION = "originalDetermination";
74

  
75
	private static final String COLLECTION = "collection";
76

  
77
	private static final String FULL_TYPE = "fullType";
78

  
79
	private static final String NOT_FOUND = "notFound";
80

  
106 81
	private static final Logger logger = Logger.getLogger(MarkupDocumentImport.class);
107 82

  
108
	private static int modCount = 30000;
83
	private static final boolean CREATE_NEW = true;
84
	private static final boolean IS_IMAGE_GALLERY = true;
85
	private static final boolean NO_IMAGE_GALLERY = false;
86

  
87
	private static final String ACCEPTED = "accepted";
88
	private static final String ADDENDA = "addenda";
89
	private static final String ALTERNATEPUBTITLE = "alternatepubtitle";
90
	private static final String ANNOTATION = "annotation";
91
	private static final String AUTHOR = "author";
92
	private static final String BIOGRAPHIES = "biographies";
93
	private static final String BOLD = "bold";
94
	private static final String CHAR = "char";
95
	private static final String CITATION = "citation";
96
	private static final String DESTROYED = "destroyed";
97
	private static final String DETAILS = "details";
98
	private static final String DISTRIBUTION_LIST = "distributionList";
99
	private static final String EDITION = "edition";
100
	private static final String EDITORS = "editors";
101
	private static final String EXAUT = "exaut";
102
	private static final String FEATURE = "feature";
103
	private static final String FIGURE = "figure";
104
	private static final String FOOTNOTE = "footnote";
105
	private static final String FULL_NAME = "fullName";
106
	private static final String HEADING = "heading";
107
	private static final String HABITAT_LIST = "habitatList";
108
	private static final String HOMONYM = "homonym";
109
	private static final String HOMOTYPES = "homotypes";
110
	private static final String INFRANK = "infrank";
111
	private static final String INFRAUT = "infraut";
112
	private static final String INFREX = "infrex";
113
	private static final String INFRPARAUT = "infrparaut";
114
	private static final String INFRPAREX = "infrparex";
115
	private static final String ISSUE = "issue";
116
	private static final String ITALICS = "italics";
117
	private static final String KEY = "key";
118
	private static final String LOST = "lost";
119
	private static final String META_DATA = "metaData";
120
	private static final String NAME = "name";
121
	private static final String NAME_TYPE = "nameType";
122
	private static final String NOM = "nom";
123
	private static final String NOMENCLATURE = "nomenclature";
124
	private static final String NOT_SEEN = "notSeen";
125
	private static final String NOTES = "notes";
126
	private static final String NUM = "num";
127
	private static final String PARAUT = "paraut";
128
	private static final String PUBFULLNAME = "pubfullname";
129
	private static final String PUBLICATION = "publication";
130
	private static final String PUBNAME = "pubname";
131
	private static final String PUBTITLE = "pubtitle";
132
	private static final String PUBTYPE = "pubtype";
133
	private static final String RANK = "rank";
134
	private static final String REFERENCES = "references";
135
	private static final String REF_PART = "refPart";
136
	private static final String TAXON = "taxon";
137
	private static final String TAXONTITLE = "taxontitle";
138
	private static final String TEXT_SECTION = "textSection";
139
	private static final String TYPE = "type";
140
	private static final String TYPE_STATUS = "typeStatus";
141
	private static final String TREATMENT = "treatment";
142
	private static final String SPECIMEN_TYPE = "specimenType";
143
	private static final String STRING = "string";
144
	private static final String SYNONYM = "synonym";
145
	private static final String UNKNOWN = "unknown";
146
	private static final String USAGE = "usage";
147
	private static final String VOLUME = "volume";
148
	private static final String WRITER = "writer";
149
	private static final String YEAR = "year";
150

  
151
		
109 152
	private NonViralNameParserImpl parser = new NonViralNameParserImpl();
110 153
	
111 154
	//TODO make part of state, but state is renewed when invoking the import a second time 
......
159 202
			}
160 203
			
161 204
			//publication
162
			String elName = "publication";
205
			String elName = PUBLICATION;
206
			boolean hasPublication = false;
163 207
			while (reader.hasNext()) {
164 208
				XMLEvent nextEvent = reader.nextEvent();
165 209
				if (isStartingElement(nextEvent, elName)){
166 210
					handlePublication(state, reader, nextEvent, elName);
211
					hasPublication = true;
212
				}else if (nextEvent.isEndDocument()){
213
					if (!hasPublication){
214
						String message = "No publication root element found";
215
						fireWarningEvent(message, makeLocationStr(nextEvent.getLocation()), 8);
216
					}
217
					//done
167 218
				}else{
168 219
					fireSchemaConflictEventExpectedStartTag(elName, reader);
169 220
				}
......
188 239

  
189 240
		}
190 241
		 
191
	
242
		
243
		
192 244
		return;
193 245
		
194 246
	}
......
199 251
	private void handlePublication(MarkupImportState state, XMLEventReader reader, XMLEvent currentEvent, String elName) throws XMLStreamException {
200 252
			
201 253
		//attributes
202
		StartElement element = currentEvent.asStartElement().asStartElement();
203
		Map<String, javax.xml.stream.events.Attribute> attributes = getAttributes(element);
204
		handleUnexpectedAttributes(element.getLocation(), attributes);
254
		StartElement element = currentEvent.asStartElement();
255
		Map<String, Attribute> attributes = getAttributes(element);
256
		handleUnexpectedAttributes(element.getLocation(), attributes, "noNamespaceSchemaLocation");
205 257
		
206 258
		while (reader.hasNext()){
207 259
			XMLEvent event = readNoWhitespace(reader);
......
210 262
				if (isEndingElement(event, elName)){
211 263
					return;
212 264
				}else{
213
					if(isEndingElement(event, "metaData")){
265
					if(isEndingElement(event, META_DATA)){
214 266
						//NOT YET IMPLEMENTED
215
					}else if(isStartingElement(event, "treatment")){
267
						popUnimplemented(event.asEndElement());
268
					}else if(isStartingElement(event, TREATMENT)){
216 269
						//NOT YET IMPLEMENTED
217
					}else if(isStartingElement(event, "biographies")){
270
						popUnimplemented(event.asEndElement());
271
					}else if(isStartingElement(event, BIOGRAPHIES)){
218 272
						//NOT YET IMPLEMENTED
219
					}else if(isStartingElement(event, "references")){
273
						popUnimplemented(event.asEndElement());
274
					}else if(isStartingElement(event, REFERENCES)){
220 275
						//NOT YET IMPLEMENTED
221
					}else if(isStartingElement(event, "textSection")){
276
						popUnimplemented(event.asEndElement());
277
					}else if(isStartingElement(event, TEXT_SECTION)){
222 278
						//NOT YET IMPLEMENTED
223
					}else if(isStartingElement(event, "addenda")){
279
						popUnimplemented(event.asEndElement());
280
					}else if(isStartingElement(event, ADDENDA)){
224 281
						//NOT YET IMPLEMENTED
282
						popUnimplemented(event.asEndElement());
225 283
					}else{
226
						handleUnexpectedEndElement(event);
284
						handleUnexpectedElement(event);
227 285
					}
228 286
				}
229 287
			}else if (event.isStartElement()){
230
				if(isStartingElement(event, "metaData")){
288
				if(isStartingElement(event, META_DATA)){
231 289
					handleNotYetImplementedElement(event);
232
				}else if(isStartingElement(event, "treatment")){
290
				}else if(isStartingElement(event, TREATMENT)){
233 291
					handleTreatment(state, reader, event);
234
				}else if(isStartingElement(event, "biographies")){
292
				}else if(isStartingElement(event, BIOGRAPHIES)){
235 293
					handleNotYetImplementedElement(event);
236
				}else if(isStartingElement(event, "references")){
294
				}else if(isStartingElement(event, REFERENCES)){
237 295
					handleNotYetImplementedElement(event);
238
				}else if(isStartingElement(event, "textSection")){
296
				}else if(isStartingElement(event, TEXT_SECTION)){
239 297
					handleNotYetImplementedElement(event);
240
				}else if(isStartingElement(event, "addenda")){
298
				}else if(isStartingElement(event, ADDENDA)){
241 299
					handleNotYetImplementedElement(event);
242 300
				}else{
243 301
					handleUnexpectedStartElement(event);
......
249 307
		return;
250 308
	}
251 309

  
252

  
253

  
254

  
310
	private void handleTreatment(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
311
		checkNoAttributes(parentEvent);
312
		Taxon lastTaxon = null;
313
		while (reader.hasNext()){
314
			XMLEvent next = readNoWhitespace(reader);
315
			if (isStartingElement(next, TAXON)){
316
				Taxon thisTaxon = handleTaxon(state, reader, next.asStartElement(), lastTaxon);
317
				doTaxonRelation(state, thisTaxon, lastTaxon, parentEvent.getLocation());
318
				lastTaxon = thisTaxon;
319
				//TODO for imports spanning multiple documents ?? Still needed?
320
				state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());
321
			}else if(isMyEndingElement(next, parentEvent)){
322
				return;
323
			}else{
324
				fireSchemaConflictEventExpectedStartTag(TAXON, reader);
325
				state.setUnsuccessfull();
326
			}
327
		}
328
		return;
329
	}
330
	
255 331
	/**
256
	 * Read next event. Ignore whitespace events.
257
	 * @param reader
258
	 * @return
259
	 * @throws XMLStreamException
332
	 * @param taxon
333
	 * @param lastTaxon
260 334
	 */
261
	private XMLEvent readNoWhitespace(XMLEventReader reader) throws XMLStreamException {
262
		XMLEvent event = reader.nextEvent();
263
		while (event.isCharacters() && event.asCharacters().isWhiteSpace()){
264
			event = reader.nextEvent();
335
	private void doTaxonRelation(MarkupImportState state, Taxon taxon, Taxon lastTaxon, Location dataLocation) {
336
		
337
		Classification tree = makeTree(state);
338
		if (lastTaxon == null){
339
			tree.addChildTaxon(taxon, null, null, null);
340
			return;
341
		}
342
		Rank thisRank = taxon.getName().getRank();
343
		Rank lastRank = lastTaxon.getName().getRank();
344
		if (lastTaxon.getTaxonNodes().size() > 0){
345
			TaxonNode lastNode = lastTaxon.getTaxonNodes().iterator().next();
346
			if (thisRank.isLower(lastRank )  ){
347
				lastNode.addChildTaxon(taxon, null, null, null);
348
				fillMissingEpithetsForTaxa(lastTaxon, taxon);
349
			}else if (thisRank.equals(lastRank)){
350
				TaxonNode parent = lastNode.getParent();
351
				if (parent != null){
352
					parent.addChildTaxon(taxon, null, null, null);
353
					fillMissingEpithetsForTaxa(parent.getTaxon(), taxon);
354
				}else{
355
					tree.addChildTaxon(taxon, null, null, null);
356
				}
357
			}else if (thisRank.isHigher(lastRank)){
358
				doTaxonRelation(state, taxon, lastNode.getParent().getTaxon(), dataLocation);
359
//				TaxonNode parentNode = handleTaxonRelation(state, taxon, lastNode.getParent().getTaxon());
360
//				parentNode.addChildTaxon(taxon, null, null, null);
361
			}
362
		}else{
363
			
364
			String message = "Last taxon has no node";
365
			fireWarningEvent(message, makeLocationStr(dataLocation), 6);
265 366
		}
266
		return event;
267 367
	}
268 368
	
269
	private boolean handleTreatment(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
270
		boolean success = true;
271
		while (reader.hasNext()){
272
			XMLEvent next = readNoWhitespace(reader);
273
			if (isStartingElement(next, "taxon")){
274
				handleTaxon(state, reader, next.asStartElement());
275
			}else if(isMyEndingElement(next, parentEvent)){
276
				return success;
369

  
370
	/**
371
	 * @param state
372
	 * @return 
373
	 */
374
	private Classification makeTree(MarkupImportState state) {
375
		Classification result = state.getTree(null);
376
		if (result == null){
377
			UUID uuid = state.getConfig().getClassificationUuid();
378
			if (uuid == null){
379
				logger.warn("No classification uuid is defined");
380
				result = createNewClassification(state);
277 381
			}else{
278
				fireSchemaConflictEventExpectedStartTag("taxon", reader);
279
				success = false;
382
				result = getClassificationService().find(uuid);
383
				if (result == null){
384
					result = createNewClassification(state);
385
					result.setUuid(uuid);
386
				}
280 387
			}
388
			state.putTree(null, result);
281 389
		}
282
		return success;
390
		save(result, state);
391
		return result;
392
	}
393
	
394

  
395
	private Classification createNewClassification(MarkupImportState state) {
396
		Classification result;
397
		result = Classification.NewInstance(state.getConfig().getClassificationTitle());
398
		state.putTree(null, result);
399
		return result;
283 400
	}
284 401

  
285 402

  
286
	private void handleTaxon(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) throws XMLStreamException {
403
	private Taxon handleTaxon(MarkupImportState state, XMLEventReader reader, StartElement parentEvent, Taxon lastTaxon) throws XMLStreamException {
404
		//TODO progress monitoring
405
		Map<String, Attribute> attributes = getAttributes(parentEvent);
406
		Taxon taxon = createTaxonAndName(state, attributes);
407
		state.setCurrentTaxon(taxon);
408
		
287 409
		boolean hasTitle = false;
288 410
		boolean hasNomenclature = false;
411
		String taxonTitle = null;
289 412
		while (reader.hasNext()){
290 413
			XMLEvent next = readNoWhitespace(reader);
291 414
			if (next.isEndElement()){
292 415
				if (isMyEndingElement(next, parentEvent)){
293
					handleMandatoryElement(hasTitle, parentEvent, "taxontitle");
294
					handleMandatoryElement(hasNomenclature, parentEvent, "nomenclature");
295
					//TODO check title and nomenclature exists
296
					return;
416
					checkMandatoryElement(hasTitle, parentEvent, TAXONTITLE);
417
					checkMandatoryElement(hasNomenclature, parentEvent, NOMENCLATURE);
418
					handleUnexpectedAttributes(parentEvent.getLocation(), attributes);
419
					state.setCurrentTaxon(null);
420
					save(taxon, state);
421
					return taxon;
297 422
				}else{
298
					if(isEndingElement(next, "heading")){
423
					if(isEndingElement(next, HEADING)){
299 424
						//NOT YET IMPLEMENTED
300
					}else if(isStartingElement(next, "taxontitle")){
425
						popUnimplemented(next.asEndElement());
426
					}else if(isEndingElement(next, TEXT_SECTION)){
301 427
						//NOT YET IMPLEMENTED
302
					}else if(isStartingElement(next, "biographies")){
428
						popUnimplemented(next.asEndElement());
429
					}else if(isEndingElement(next, KEY)){
303 430
						//NOT YET IMPLEMENTED
304
					}else if(isStartingElement(next, "references")){
431
						popUnimplemented(next.asEndElement());
432
					}else if(isEndingElement(next, NOTES)){
305 433
						//NOT YET IMPLEMENTED
306
					}else if(isStartingElement(next, "textSection")){
434
						popUnimplemented(next.asEndElement());
435
					}else if(isEndingElement(next, REFERENCES)){
307 436
						//NOT YET IMPLEMENTED
308
					}else if(isStartingElement(next, "addenda")){
437
						popUnimplemented(next.asEndElement());
438
					}else if(isEndingElement(next, FIGURE)){
309 439
						//NOT YET IMPLEMENTED
440
						popUnimplemented(next.asEndElement());
441
					}else if(isEndingElement(next, FOOTNOTE)){
442
						//NOT YET IMPLEMENTED
443
						popUnimplemented(next.asEndElement());
310 444
					}else{
311
						handleUnexpectedEndElement(next);
445
						handleUnexpectedEndElement(next.asEndElement());
312 446
					}
313 447
				}
314 448
			}else if (next.isStartElement()){
315
				if(isStartingElement(next, "heading")){
316
					handleNotYetImplementedElement(next);
317
				}else if(isStartingElement(next, "taxontitle")){
318
					handleTaxonTitle(state, reader, next);
319
				}else if(isStartingElement(next, "writer")){
449
				if(isStartingElement(next, HEADING)){
320 450
					handleNotYetImplementedElement(next);
321
				}else if(isStartingElement(next, "textsection")){
451
				}else if(isStartingElement(next, TAXONTITLE)){
452
					taxonTitle = handleTaxonTitle(state, reader, next);
453
					hasTitle = true;
454
				}else if(isStartingElement(next, WRITER)){
455
					Extension writerExtension = handleWriter(state, reader, next);
456
					
457
					
458
					taxon.addExtension(writerExtension);
459
				}else if(isStartingElement(next, TEXT_SECTION)){
322 460
					handleNotYetImplementedElement(next);
323
				}else if(isStartingElement(next, "key")){
461
				}else if(isStartingElement(next, KEY)){
324 462
					handleNotYetImplementedElement(next);
325
				}else if(isStartingElement(next, "feature")){
463
				}else if(isStartingElement(next, NOMENCLATURE)){
464
					handleNomenclature(state, reader, next, taxon);
465
					hasNomenclature = true;
466
				}else if(isStartingElement(next, FEATURE)){
467
					handleFeature(state, reader, next);
468
				}else if(isStartingElement(next, NOTES)){
326 469
					handleNotYetImplementedElement(next);
327
				}else if(isStartingElement(next, "notes")){
470
				}else if(isStartingElement(next, REFERENCES)){
328 471
					handleNotYetImplementedElement(next);
329
				}else if(isStartingElement(next, "references")){
472
				}else if(isStartingElement(next, FIGURE)){
330 473
					handleNotYetImplementedElement(next);
331
				}else if(isStartingElement(next, "figure")){
332
					handleNotYetImplementedElement(next);
333
				}else if(isStartingElement(next, "footnote")){
474
				}else if(isStartingElement(next, FOOTNOTE)){
334 475
					handleNotYetImplementedElement(next);
335 476
				}else{
336 477
					handleUnexpectedStartElement(next);
......
339 480
				handleUnexpectedElement(next);
340 481
			}
341 482
		}
342
		return;
483
		//TODO handle missing end element
484
		throw new IllegalStateException("Taxon has no closing tag");
343 485
	}
344 486

  
345
	private void handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
346
		boolean hasTitle = false;
487

  
488
	/**
489
	 * @param state
490
	 * @param attributes 
491
	 */
492
	private Taxon createTaxonAndName(MarkupImportState state, Map<String, Attribute> attributes) {
493
		NonViralName name;
494
		Rank rank = Rank.SPECIES(); //default
495
		if (checkAndRemoveAttributeValue(attributes, CLASS, "cultivated")){
496
			name = CultivarPlantName.NewInstance(rank);
497
		}else{
498
			NomenclaturalCode nc = makeNomenclaturalCode(state);
499
			name = (NonViralName)nc.getNewTaxonNameInstance(rank);
500
		}
501
		Taxon taxon = Taxon.NewInstance(name, state.getConfig().getSourceReference());
502
		if (checkAndRemoveAttributeValue(attributes, CLASS, "dubious")){
503
			taxon.setDoubtful(true);
504
		}else if (checkAndRemoveAttributeValue(attributes, CLASS, "excluded")){
505
			taxon.setExcluded(true);
506
		}
507
		//TODO insufficient, new, expected
508
		handleNotYetImplementedAttribute(attributes, CLASS);
509
		//From old version
510
//		MarkerType markerType = getMarkerType(state, attrValue);
511
//		if (markerType == null){
512
//			logger.warn("Class attribute value for taxon not yet supported: " + attrValue);
513
//		}else{
514
//			taxon.addMarker(Marker.NewInstance(markerType, true));
515
//		}
516
		
517
//		save(name, state);
518
//		save(taxon, state);
519
		return taxon;
520
	}
521

  
522

  
523
	/**
524
	 * @param state
525
	 * @return
526
	 */
527
	private NomenclaturalCode makeNomenclaturalCode(MarkupImportState state) {
528
		NomenclaturalCode nc = state.getConfig().getNomenclaturalCode();
529
		if (nc == null){
530
			nc = NomenclaturalCode.ICBN;  //default;
531
		}
532
		return nc;
533
	}
534

  
535
	private String handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
536
		String text = "";
537
		Map<String, Attribute> attributes = getAttributes(parentEvent);
538
		String rankAttr = getAndRemoveAttributeValue(attributes, RANK);
539
		Rank rank = makeRank(state, rankAttr, false);
540
		//TODO
541
//		String numAttr = getAndRemoveAttributeValue(attributes, NUM);
542
		handleNotYetImplementedAttribute(attributes, NUM);
543
		checkNoAttributes(attributes, parentEvent);
347 544
		
348 545
		//TODO handle attributes
349 546
		while (reader.hasNext()){
350 547
			XMLEvent next = readNoWhitespace(reader);
351 548
			if (next.isEndElement()){
352 549
				if (isMyEndingElement(next, parentEvent)){
550
					Taxon taxon = state.getCurrentTaxon();
551
					String titleText = null;
552
					if (checkMandatoryText(text, parentEvent)){
553
						titleText = normalize(text);
554
						UUID uuidTitle = MarkupTransformer.uuidTaxonTitle;
555
						ExtensionType titleExtension = this.getExtensionType(state, uuidTitle, "Taxon Title ", "taxon title", "title");
556
						taxon.addExtension(titleText, titleExtension);
557
					}
558
					taxon.getName().setRank(rank);
353 559
					//TODO check title exists
354
					return;
560
					return titleText;
355 561
				}else{
356
					if(isEndingElement(next, "footnoteString")){
562
					if(isEndingElement(next, FOOTNOTE)){
357 563
						//NOT YET IMPLEMENTED
564
						popUnimplemented(next.asEndElement());
358 565
					}else{
359
						handleUnexpectedEndElement(next);
360
						state.setSuccessToFalse();
566
						handleUnexpectedEndElement(next.asEndElement());
567
						state.setUnsuccessfull();
361 568
					}
362 569
				}
363 570
			}else if (next.isStartElement()){
364
				if(isStartingElement(next, "footnoteString")){
571
				if(isStartingElement(next, FOOTNOTE)){
365 572
					handleNotYetImplementedElement(next);
366 573
				}else{
367 574
					handleUnexpectedStartElement(next);
368
					state.setSuccessToFalse();
575
					state.setUnsuccessfull();
369 576
				}
577
			}else if (next.isCharacters()){
578
				text +=next.asCharacters().getData();
579
			
370 580
			}else{
371 581
				handleUnexpectedElement(next);
372
				state.setSuccessToFalse();
582
				state.setUnsuccessfull();
373 583
			}
374 584
		}
375
		return;
585
		return null;
376 586
		
377 587
		
378 588
	}
379

  
380

  
381
	private boolean isMyEndingElement(XMLEvent next, XMLEvent event) throws XMLStreamException {
382
		return isEndingElement(next, event.asStartElement().getName().getLocalPart());
383
	}
384

  
385

  
386
	/**
387
	 * This comes from the old version, needs to be checked on need
388
	 * @param state
389
	 */
390
	private void doAllTheOldOtherStuff(MarkupImportState state) {
391
		state.putTree(null, null);
392
		if (unmatchedLeads == null){
393
			unmatchedLeads = UnmatchedLeads.NewInstance();
394
		}
395
		state.setUnmatchedLeads(unmatchedLeads);
396
		
397
//		TransactionStatus tx = startTransaction();
398
		unmatchedLeads.saveToSession(getPolytomousKeyNodeService());
399
		
589
	
590
	private Extension handleWriter(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
591
		String text = "";
592
		checkNoAttributes(parentEvent);
400 593
		
401
		//TODO generally do not store the reference object in the config
402
		Reference sourceReference = state.getConfig().getSourceReference();
403
		getReferenceService().saveOrUpdate(sourceReference);
594
		//TODO handle attributes
595
		while (reader.hasNext()){
596
			XMLEvent next = readNoWhitespace(reader);
597
			if (next.isEndElement()){
598
				if (isMyEndingElement(next, parentEvent)){
599
					if (checkMandatoryText(text, parentEvent)){
600
						UUID uuidWriter = MarkupTransformer.uuidWriter;
601
						ExtensionType titleExtensionType = this.getExtensionType(state, uuidWriter, "Writer", "writer", "writer");
602
						Extension extension = Extension.NewInstance();
603
						extension.setType(titleExtensionType);
604
						extension.setValue(normalize(text));
605
						return extension;
606
					}else{
607
						return null;
608
					}
609
				}else{
610
					if(isEndingElement(next, FOOTNOTE)){
611
						//NOT YET IMPLEMENTED
612
						popUnimplemented(next.asEndElement());
613
					}else{
614
						handleUnexpectedEndElement(next.asEndElement());
615
						state.setUnsuccessfull();
616
					}
617
				}
618
			}else if (next.isStartElement()){
619
				if(isStartingElement(next, FOOTNOTE)){
620
					handleNotYetImplementedElement(next);
621
				}else{
622
					handleUnexpectedStartElement(next);
623
					state.setUnsuccessfull();
624
				}
625
			}else if (next.isCharacters()){
626
				text +=next.asCharacters().getData();
627
			
628
			}else{
629
				handleUnexpectedElement(next);
630
				state.setUnsuccessfull();
631
			}
632
		}
633
		return null;
404 634
	}
405 635

  
406

  
407
	private boolean doInvoke_old(MarkupImportState state){
408
		Set<TaxonBase> taxaToSave = new HashSet<TaxonBase>();
409
		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
410

  
411
	//	Element elbody= getBodyElement(state.getConfig());
412
		Element elbody = null;
413
		List<Element> elTaxonList = elbody.getChildren();
414
		
415
		int i = 0;
636
	private void handleNomenclature(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, Taxon taxon) throws XMLStreamException {
637
		checkNoAttributes(parentEvent);
416 638
		
417
		Set<String> unhandledTitleClassess = new HashSet<String>();
418
		Set<String> unhandledNomeclatureChildren = new HashSet<String>();
419
		Set<String> unhandledDescriptionChildren = new HashSet<String>();
420
		
421
		Taxon lastTaxon = getLastTaxon(state);
422
		
423
		//for each taxon
424
		for (Element elTaxon : elTaxonList){
425
			try {
426
				if ((i++ % modCount) == 0 && i > 1){ logger.info("Taxa handled: " + (i-1));}
427
				if (! elTaxon.getName().equalsIgnoreCase("taxon")){
428
					logger.warn("body has element other than 'taxon'");
429
				}
430
				
431
				BotanicalName botanicalName = BotanicalName.NewInstance(Rank.SPECIES());
432
				Taxon taxon = Taxon.NewInstance(botanicalName, state.getConfig().getSourceReference());
433
				
434
				handleTaxonAttributes(elTaxon, taxon, state);
435
	
436
				
437
				List<Element> children = elTaxon.getChildren();
438
				handleTaxonElement(state, unhandledTitleClassess, unhandledNomeclatureChildren,	unhandledDescriptionChildren, taxon, children);
439
				handleTaxonRelation(state, taxon, lastTaxon);
440
				lastTaxon = taxon;
441
				taxaToSave.add(taxon);
442
				state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());
443
				
444
			} catch (Exception e) {
445
				logger.warn("Exception occurred in Sapindacea taxon import: " + e);
446
				e.printStackTrace();
639
		while (reader.hasNext()){
640
			XMLEvent next = readNoWhitespace(reader);
641
			if (isStartingElement(next, HOMOTYPES)){
642
				handleHomotypes(state, reader, next.asStartElement(), taxon);
643
			}else if(isMyEndingElement(next, parentEvent)){
644
				return;
645
			}else{
646
				fireSchemaConflictEventExpectedStartTag(HOMOTYPES, reader);
647
				state.setUnsuccessfull();
447 648
			}
448
			
449 649
		}
450
		
451
		System.out.println(state.getUnmatchedLeads().toString());
452
		logger.warn("There are taxa with attributes 'excluded' and 'dubious'");
453
		
454
		logger.info("Children for nomenclature are: " + unhandledNomeclatureChildren);
455
		logger.info("Children for description are: " + unhandledDescriptionChildren);
456
		logger.info("Children for homotypes are: " + unhandledHomotypeChildren);
457
		logger.info("Children for nom are: " + unhandledNomChildren);
458
		
459
		
460
		//invokeRelations(source, cdmApp, deleteAll, taxonMap, referenceMap);
461
		logger.info(i + " taxa handled. Saving ...");
462
		getTaxonService().saveOrUpdate(taxaToSave);
463
		getFeatureTreeService().saveOrUpdateFeatureNodesAll(state.getFeatureNodesToSave());
464
		state.getFeatureNodesToSave().clear();
465
//		commitTransaction(tx);
466
		
467
		logger.info("end makeTaxa ...");
468
		logger.info("start makeKey ...");
469
	//	invokeDoKey(state);
470
		logger.info("end makeKey ...");
471
		
472
		return success.getValue();
650
		return;
473 651
	}
474 652

  
475
	
476 653

  
477 654

  
478
	private void handleTaxonAttributes(Element elTaxon, Taxon taxon, MarkupImportState state) {
479
		List<Attribute> attrList = elTaxon.getAttributes();
480
		for (Attribute attr : attrList){
481
			String attrName = attr.getName();
482
			String attrValue = attr.getValue();
483
			if ("class".equals(attrName)){
484
				if (attrValue.equalsIgnoreCase("dubious") || attrValue.equalsIgnoreCase("DUBIOUS GENUS") || attrValue.equalsIgnoreCase("DOUBTFUL SPECIES")  ){
485
					taxon.setDoubtful(true);
655
	private void handleHomotypes(MarkupImportState state, XMLEventReader reader, StartElement parentEvent, Taxon taxon) throws XMLStreamException {
656
		checkNoAttributes(parentEvent);
657
		
658
		HomotypicalGroup homotypicalGroup = null;
659
		
660
		boolean hasNom = false;
661
		while (reader.hasNext()){
662
			XMLEvent next = readNoWhitespace(reader);
663
			if (next.isEndElement()){
664
				if (isMyEndingElement(next, parentEvent)){
665
					checkMandatoryElement(hasNom, parentEvent, NOM);
666
					return;
486 667
				}else{
487
					MarkerType markerType = getMarkerType(state, attrValue);
488
					if (markerType == null){
489
						logger.warn("Class attribute value for taxon not yet supported: " + attrValue);
668
					if(isEndingElement(next, NAME_TYPE)){
669
						state.setNameType(false);
670
						//NOT YET IMPLEMENTED
671
						popUnimplemented(next.asEndElement());
672
					}else if(isEndingElement(next, NOTES)){
673
						//NOT YET IMPLEMENTED
674
						popUnimplemented(next.asEndElement());
490 675
					}else{
491
						taxon.addMarker(Marker.NewInstance(markerType, true));
676
						handleUnexpectedEndElement(next.asEndElement());
492 677
					}
493 678
				}
494
			}else if ("num".equals(attrName)){
495
				logger.warn("num not yet supported");
679
			}else if (next.isStartElement()){
680
				if(isStartingElement(next, NOM)){
681
					homotypicalGroup = handleNom(state, reader, next, homotypicalGroup);
682
					hasNom = true;
683
				}else if(isStartingElement(next, NAME_TYPE)){
684
					state.setNameType(true);
685
					handleNotYetImplementedElement(next);
686
				}else if(isStartingElement(next, SPECIMEN_TYPE)){
687
					handleSpecimenType(state, reader, next, homotypicalGroup);
688
				}else if(isStartingElement(next, NOTES)){
689
					handleNotYetImplementedElement(next);
690
				}else{
691
					handleUnexpectedStartElement(next);
692
				}
496 693
			}else{
497
				logger.warn("Attribute " + attrName + " not yet supported for element taxon");
694
				handleUnexpectedElement(next);
498 695
			}
499 696
		}
500

  
501
	}
502

  
503

  
504
	private Taxon getLastTaxon(MarkupImportState state) {
505
		if (state.getConfig().getLastTaxonUuid() == null){
506
			return null;
507
		}else{
508
			return (Taxon)getTaxonService().find(state.getConfig().getLastTaxonUuid());
509
		}
697
		//TODO handle missing end element
698
		throw new IllegalStateException("Homotypes has no closing tag");
699
		
510 700
	}
511 701

  
512 702

  
513
//	private void invokeDoKey(SapindaceaeImportState state) {
514
//		TransactionStatus tx = startTransaction();
515
//		
516
//		Set<FeatureNode> nodesToSave = new HashSet<FeatureNode>();
517
//		ITaxonService taxonService = getTaxonService();
518
//		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
519
//
520
//		Element elbody= getBodyElement(state.getConfig());
521
//		List<Element> elTaxonList = elbody.getChildren();
522
//		
523
//		int i = 0;
524
//		
525
//		//for each taxon
526
//		for (Element elTaxon : elTaxonList){
527
//			if ((i++ % modCount) == 0 && i > 1){ logger.info("Taxa handled: " + (i-1));}
528
//			if (! elTaxon.getName().equalsIgnoreCase("taxon")){
529
//				continue;
530
//			}
531
//			
532
//			List<Element> children = elTaxon.getChildren("key");
533
//			for (Element element : children){
534
//				handleKeys(state, element, null);
535
//			}
536
//			nodesToSave.add(taxon);
537
//
538
//		}
539
//		
540
//	}
541

  
542

  
543
	// body/taxon/*
544
	private void handleTaxonElement(MarkupImportState state, Set<String> unhandledTitleClassess, Set<String> unhandledNomeclatureChildren, Set<String> unhandledDescriptionChildren, Taxon taxon, List<Element> children) {
545
		AnnotatableEntity lastEntity = null;
546
		for (Element element : children){
547
			String elName = element.getName();
548
			
549
			if (elName.equalsIgnoreCase("title")){
550
				handleTitle(state, element, taxon, unhandledTitleClassess);
551
				lastEntity = null;
552
			}else if(elName.equalsIgnoreCase("nomenclature")){
553
				handleNomenclature(state, element, taxon, unhandledNomeclatureChildren);
554
				lastEntity = null;
555
			}else if(elName.equalsIgnoreCase("description")){
556
				handleDescription(state, element, taxon, unhandledDescriptionChildren);
557
				lastEntity = null;
558
			}else if(elName.equalsIgnoreCase("habitatecology")){
559
				lastEntity = handleEcology(state, element, taxon);
560
			}else if(elName.equalsIgnoreCase("distribution")){
561
				lastEntity = handleDistribution(state, element, taxon);
562
			}else if(elName.equalsIgnoreCase("uses")){
563
				lastEntity = handleUses(state, element, taxon);
564
			}else if(elName.equalsIgnoreCase("notes")){
565
				lastEntity = handleTaxonNotes(state, element, taxon);
566
			}else if(elName.equalsIgnoreCase("chromosomes")){
567
				lastEntity = handleChromosomes(state, element, taxon);
568
			}else if(elName.equalsIgnoreCase("vernacularnames")){
569
				handleVernaculars(state, element, taxon);
570
			}else if(elName.equalsIgnoreCase("key")){
571
				lastEntity = handleKeys(state, element, taxon);
572
			}else if(elName.equalsIgnoreCase("references")){
573
				handleReferences(state, element, taxon, lastEntity);
574
				lastEntity = null;
575
			}else if(elName.equalsIgnoreCase("taxon")){
576
				logger.warn("A taxon should not be part of a taxon");
577
			}else if(elName.equalsIgnoreCase("homotypes")){
578
				logger.warn("Homotypes should be included in the nomenclature flag but is child of taxon [XPath: body/taxon/homotypes]");
703
	private void handleSpecimenType(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, HomotypicalGroup homotypicalGroup) throws XMLStreamException {
704
		//attributes
705
		Map<String, Attribute> attributes = getAttributes(parentEvent);
706
		String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS);
707
		String notSeen = getAndRemoveAttributeValue(attributes, NOT_SEEN);
708
		String unknown = getAndRemoveAttributeValue(attributes, UNKNOWN);
709
		String notFound = getAndRemoveAttributeValue(attributes, NOT_FOUND);
710
		String destroyed = getAndRemoveAttributeValue(attributes, DESTROYED);
711
		String lost = getAndRemoveAttributeValue(attributes, LOST);
712
		checkNoAttributes(attributes, parentEvent);
713
		if (StringUtils.isNotEmpty(typeStatus)){
714
			//TODO
715
			//currently not needed
716
		} else if (StringUtils.isNotEmpty(notSeen)){
717
			handleNotYetImplementedAttribute(attributes, NOT_SEEN);
718
		}else if (StringUtils.isNotEmpty(unknown)){
719
			handleNotYetImplementedAttribute(attributes, UNKNOWN);
720
		}else if (StringUtils.isNotEmpty(notFound)){
721
			handleNotYetImplementedAttribute(attributes, NOT_FOUND);
722
		}else if (StringUtils.isNotEmpty(destroyed)){
723
			handleNotYetImplementedAttribute(attributes, DESTROYED);
724
		}else if (StringUtils.isNotEmpty(lost)){
725
			handleNotYetImplementedAttribute(attributes, LOST);
726
		}
727
		
728
		//elements
729
		while (reader.hasNext()){
730
			XMLEvent next = readNoWhitespace(reader);
731
			if (next.isEndElement()){
732
				if (isMyEndingElement(next, parentEvent)){
733
					return;
734
				}else{
735
					if(isEndingElement(next, FULL_TYPE)){
736
						//NOT YET IMPLEMENTED
737
						popUnimplemented(next.asEndElement());
738
					}else if(isEndingElement(next,TYPE_STATUS)){
739
						//NOT YET IMPLEMENTED
740
						popUnimplemented(next.asEndElement());
741
					}else if(isEndingElement(next, COLLECTION)){
742
						//NOT YET IMPLEMENTED
743
						popUnimplemented(next.asEndElement());
744
					}else if(isEndingElement(next, ORIGINAL_DETERMINATION)){
745
						//NOT YET IMPLEMENTED
746
						popUnimplemented(next.asEndElement());
747
					}else if(isEndingElement(next, SPECIMEN_TYPE)){
748
						//NOT YET IMPLEMENTED
749
						popUnimplemented(next.asEndElement());
750
					}else if(isEndingElement(next, CITATION)){
751
						//NOT YET IMPLEMENTED
752
						popUnimplemented(next.asEndElement());
753
					}else if(isEndingElement(next, NOTES)){
754
						//NOT YET IMPLEMENTED
755
						popUnimplemented(next.asEndElement());
756
					}else if(isEndingElement(next, ANNOTATION)){
757
						//NOT YET IMPLEMENTED
758
						popUnimplemented(next.asEndElement());
759
					}else{
760
						handleUnexpectedEndElement(next.asEndElement());
761
					}
762
				}
763
			}else if (next.isStartElement()){
764
				if(isStartingElement(next, FULL_TYPE)){
765
					handleNotYetImplementedElement(next);
766
//					homotypicalGroup = handleNom(state, reader, next, taxon, homotypicalGroup);
767
				}else if(isStartingElement(next, TYPE_STATUS)){
768
					handleNotYetImplementedElement(next);
769
				}else if(isStartingElement(next, COLLECTION)){
770
					handleNotYetImplementedElement(next);
771
//					handleName(state, reader, next, name);
772
				}else if(isStartingElement(next, ORIGINAL_DETERMINATION)){
773
					handleNotYetImplementedElement(next);
774
				}else if(isStartingElement(next, SPECIMEN_TYPE)){
775
					handleNotYetImplementedElement(next);
776
				}else if(isStartingElement(next, NOTES)){
777
					handleNotYetImplementedElement(next);
778
				}else if(isStartingElement(next, ANNOTATION)){
779
					handleNotYetImplementedElement(next);
780
				}else{
781
					handleUnexpectedStartElement(next);
782
				}
579 783
			}else{
580
				logger.warn("Unexpected child for taxon: " + elName);
784
				handleUnexpectedElement(next);
581 785
			}
582 786
		}
583
	}
584
	
585
	
586
	private void handleVernaculars(MarkupImportState state, Element elVernacular, Taxon taxon) {
587
		verifyNoAttribute(elVernacular);
588
		verifyNoChildren(elVernacular, false);
589
		String value = elVernacular.getTextNormalize();
590
		Feature feature = Feature.COMMON_NAME();
591
		value = replaceStart(value, "Noms vernaculaires");
592
		String[] dialects = value.split(";");
593
		for (String singleDialect : dialects){
594
			handleSingleDialect(taxon, singleDialect, feature, state);
595
		}
596
		return;
787
		//TODO handle missing end element
788
		throw new IllegalStateException("Nom has no closing tag");		// TODO Auto-generated method stub
789
		
597 790
	}
598 791

  
599 792

  
600
	private void handleSingleDialect(Taxon taxon, String singleDialect, Feature feature, MarkupImportState state) {
601
		singleDialect = singleDialect.trim();
602
		TaxonDescription description = getDescription(taxon);
603
		String reDialect = "\\(dial\\.\\s.*\\)";
604
//		String reDialect = "\\(.*\\)";
605
		Pattern patDialect = Pattern.compile(reDialect);
606
		Matcher matcher = patDialect.matcher(singleDialect);
607
		if (matcher.find()){
608
			String dialect = singleDialect.substring(matcher.start(), matcher.end());
609
			dialect = dialect.replace("(dial. ", "").replace(")", "");
610
			
611
			Language language = null;
612
			try {
613
				language = this.getLanguage(state, state.getTransformer().getLanguageUuid(dialect), dialect, dialect, dialect);
614
			} catch (UndefinedTransformerMethodException e) {
615
				logger.error(e.getMessage());
616
			}
617
			
618
			String commonNames = singleDialect.substring(0, matcher.start());
619
			String[] splitNames = commonNames.split(",");
620
			for (String commonNameString : splitNames){
621
				commonNameString = commonNameString.trim();
622
				CommonTaxonName commonName = CommonTaxonName.NewInstance(commonNameString, language);
623
				description.addElement(commonName);
624
			}
793
	private HomotypicalGroup handleNom(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, 
794
				HomotypicalGroup homotypicalGroup) throws XMLStreamException {
795
		HomotypicalGroup resultHomGroup = null;
796
		boolean isSynonym = false;
797
		boolean isNameType = state.isNameType();
798
		//attributes
799
		String classValue = getClassOnlyAttribute(parentEvent);
800
		if (! isNameType && ACCEPTED.equalsIgnoreCase(classValue)){
801
			isSynonym = false;
802
		}else if (! isNameType && SYNONYM.equalsIgnoreCase(classValue)){
803
			isSynonym = true;
804
		}else if (isNameType && NAME_TYPE.equalsIgnoreCase(classValue)){
805
			handleNotYetImplementedAttributeValue(parentEvent, CLASS, classValue);
625 806
		}else{
626
			logger.warn("No dialect match: " +  singleDialect);
807
			//TODO Not yet implemented
808
			fireUnexpectedAttributeValue(parentEvent, CLASS, classValue);
627 809
		}
628
	}
629

  
630

  
631
	private void handleReferences(MarkupImportState state, Element elReferences, Taxon taxon, AnnotatableEntity lastEntity) {
632
		verifyNoAttribute(elReferences);
633
		verifyNoChildren(elReferences, true);
634
		String refString = elReferences.getTextNormalize(); 
635
		if (lastEntity == null){
636
			logger.warn("No last entity defined: " + refString);
637
			return;
638
		}
639
		
640
		Annotation annotation = Annotation.NewInstance(refString, AnnotationType.EDITORIAL(), Language.DEFAULT());
641
		lastEntity.addAnnotation(annotation);
642
	}
643

  
644

  
645
	private PolytomousKey handleKeys(MarkupImportState state, Element elKey, Taxon taxon) {
646
		UnmatchedLeads openKeys = state.getUnmatchedLeads();
647
		
648
		//title
649
		String title = makeKeyTitle(elKey);
650
		
651
		//key
652
		PolytomousKey key = PolytomousKey.NewTitledInstance(title);
653
		
654
		//TODO add covered taxa etc.
655
		verifyNoAttribute(elKey);
810
		NonViralName name = makeName(state.getCurrentTaxon(), homotypicalGroup, isSynonym);
656 811
		
657
		//notes
658
		makeKeyNotes(elKey, key);
659 812
		
660
		//keycouplets
661
		List<Element> keychoices = new ArrayList<Element>();
662
		keychoices.addAll(elKey.getChildren("keycouplet"));
663
		keychoices.addAll(elKey.getChildren("keychoice"));
664
		
665
		
666
		for (Element elKeychoice : keychoices){
667
			handleKeyChoices(state, openKeys, key, elKeychoice, taxon);
668
			elKey.removeContent(elKeychoice);
813
		while (reader.hasNext()){
814
			XMLEvent next = readNoWhitespace(reader);
815
			if (next.isEndElement()){
816
				if (isMyEndingElement(next, parentEvent)){
817
//					logger.warn(name.getTitleCache());
818
					return resultHomGroup;
819
				}else{
820
					if(isEndingElement(next, FULL_NAME)){
821
						//NOT YET IMPLEMENTED
822
						popUnimplemented(next.asEndElement());
823
					}else if(isEndingElement(next, NUM)){
824
						//NOT YET IMPLEMENTED
825
						popUnimplemented(next.asEndElement());
826
					}else if(isEndingElement(next, HOMONYM)){
827
						//NOT YET IMPLEMENTED
828
						popUnimplemented(next.asEndElement());
829
					}else if(isEndingElement(next, NOTES)){
830
						//NOT YET IMPLEMENTED
831
						popUnimplemented(next.asEndElement());
832
					}else if(isEndingElement(next, ANNOTATION)){
833
						//NOT YET IMPLEMENTED
834
						popUnimplemented(next.asEndElement());
835
					}else{
836
						handleUnexpectedEndElement(next.asEndElement());
837
					}
838
				}
839
			}else if (next.isStartElement()){
840
				if(isStartingElement(next, FULL_NAME)){
841
					handleNotYetImplementedElement(next);
842
//					homotypicalGroup = handleNom(state, reader, next, taxon, homotypicalGroup);
843
				}else if(isStartingElement(next, NUM)){
844
					handleNotYetImplementedElement(next);
845
				}else if(isStartingElement(next, NAME)){
846
					handleName(state, reader, next, name);
847
				}else if(isStartingElement(next, CITATION)){
848
					handleCitation(state, reader, next, name);
849
				}else if(isStartingElement(next, HOMONYM)){
850
					handleNotYetImplementedElement(next);
851
				}else if(isStartingElement(next, NOTES)){
852
					handleNotYetImplementedElement(next);
853
				}else if(isStartingElement(next, ANNOTATION)){
854
					handleNotYetImplementedElement(next);
855
				}else{
856
					handleUnexpectedStartElement(next);
857
				}
858
			}else{
859
				handleUnexpectedElement(next);
860
			}
669 861
		}
862
		//TODO handle missing end element
863
		throw new IllegalStateException("Nom has no closing tag");
670 864
		
671
		//
672
		verifyNoChildren(elKey);
673
		logger.info("Unmatched leads after key handling:" + openKeys.toString());
674
		
675

  
676
		if (state.getConfig().isDoPrintKeys()){
677
			key.print(System.err);
678
		}
679
		getPolytomousKeyService().save(key);
680
		return key;
681 865
	}
682 866

  
683

  
684 867
	/**
685
	 * @param state
686
	 * @param elKey
687
	 * @param openKeys
688
	 * @param key
689
	 * @param elKeychoice
690
	 * @param taxon 
868
	 * Returns the (empty) name with the correct homotypical group depending on the taxon status
869
	 * @param taxon
870
	 * @param homotypicalGroup
871
	 * @param isSynonym
872
	 * @return
691 873
	 */
692
	private void handleKeyChoices(MarkupImportState state, UnmatchedLeads openKeys, PolytomousKey key, Element elKeychoice, Taxon taxon) {
874
	private NonViralName makeName(Taxon taxon,HomotypicalGroup homotypicalGroup, boolean isSynonym) {
875
		NonViralName name;
876
		if (isSynonym){
877
			Rank defaultRank = Rank.SPECIES();  //can be any
878
			name = BotanicalName.NewInstance(defaultRank, homotypicalGroup);
879
			SynonymRelationshipType synonymType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
880
			if (taxon.getHomotypicGroup().equals(homotypicalGroup)){
881
				synonymType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
882
			}
883
			taxon.addSynonymName(name, synonymType);
884
		}else{
885
			name = (NonViralName)taxon.getName();
886
		}
887
		return name;
888
	}
889
	
890
	private void handleName(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, NonViralName name) throws XMLStreamException {
891
		//attributes
892
		Map<String, Attribute> attributes = getAttributes(parentEvent);
893
		String classValue = getAndRemoveRequiredAttributeValue(parentEvent, attributes, CLASS);
894
		checkNoAttributes(attributes, parentEvent);
693 895
		
694
		//char Attribute
695
		//TODO it's still unclear if char is a feature and needs to be a new attribute 
696
		//or if it is handled as question. Therefore both cases are handled but feature
697
		//is finally not yet set
698
		KeyStatement question = handleKeychoiceChar(state, elKeychoice);
699
		Feature feature = handleKeychoiceCharAsFeature(state, elKeychoice);
896
		//Ranks: family, subfamily, tribus, genus, subgenus, section, subsection, species, subspecies, variety, subvariety, forma
897
		//infrank, exaut, paraut, author, infrparaut, infraut, infrex, status, notes
700 898
		
701
		//lead
702
		List<PolytomousKeyNode> childNodes = handleKeychoiceLeads(state, key, elKeychoice, taxon, question, feature);
899
		//ranks
900
		Rank rank = makeRank(state, classValue, false);
703 901
		
704
		//num -> match with unmatched leads
705
		handleKeychoiceNum(openKeys, key, elKeychoice, childNodes);
706

  
707
		//others
708
		verifyNoAttribute(elKeychoice);
709
	}
710

  
711

  
712
	/**
713
	 * @param openKeys
714
	 * @param key
715
	 * @param elKeychoice
716
	 * @param childNodes
717
	 */
718
	private void handleKeychoiceNum(UnmatchedLeads openKeys, PolytomousKey key, Element elKeychoice, List<PolytomousKeyNode> childNodes) {
719
		Attribute numAttr = elKeychoice.getAttribute("num");
720
		String num = CdmUtils.removeTrailingDot(numAttr == null? "":numAttr.getValue());
721
		UnmatchedLeadsKey okk = UnmatchedLeadsKey.NewInstance(key, num);
722
		Set<PolytomousKeyNode> matchingNodes = openKeys.getNodes(okk);
723
		for (PolytomousKeyNode matchingNode : matchingNodes){
724
			for (PolytomousKeyNode childNode : childNodes){
725
				matchingNode.addChild(childNode);
726
			}
727
			openKeys.removeNode(okk, matchingNode);
728
		}
729
		if (matchingNodes.isEmpty()){
730
			for (PolytomousKeyNode childNode : childNodes){
731
				key.getRoot().addChild(childNode);
902
		String text = "";
903
		while (reader.hasNext()){
904
			XMLEvent next = readNoWhitespace(reader);
905
			if (isStartingElement(next, ANNOTATION)){
906
				handleNotYetImplementedElement(next);
907
//				handleAnnotation(state, reader, next);
908
			}else if(isMyEndingElement(next, parentEvent)){
909
				doNameEnd(name, rank, text, classValue, next, state);
910
				return;
911
			}else if (next.isCharacters()){
912
				text += next.asCharacters().getData();
913
			}else if (next.isEndElement()){
914
				if(isEndingElement(next, ANNOTATION)){
915
					//NOT YET IMPLEMENTED
916
					popUnimplemented(next.asEndElement());
917
				}else{
918
					handleUnexpectedEndElement(next.asEndElement());
919
				}
920
			}else{
921
				fireSchemaConflictEventExpectedStartTag("annotation", reader);
922
				state.setUnsuccessfull();
732 923
			}
733 924
		}
925
		return;
734 926
		
735
		elKeychoice.removeAttribute("num");
736 927
	}
737 928

  
738 929

  
739 930
	/**
740 931
	 * @param state
741
	 * @param key
742
	 * @param elKeychoice
743
	 * @param taxon
744
	 * @param feature
932
	 * @param classValue
933
	 * @param byAbbrev 
745 934
	 * @return
746 935
	 */
747
	private List<PolytomousKeyNode> handleKeychoiceLeads(	MarkupImportState state, PolytomousKey key,	Element elKeychoice, Taxon taxon, KeyStatement question, Feature feature) {
748
		List<PolytomousKeyNode> childNodes = new ArrayList<PolytomousKeyNode>();
749
		List<Element> leads = elKeychoice.getChildren("lead");
750
		for(Element elLead : leads){
751
			PolytomousKeyNode childNode = handleLead(state, key, elLead, taxon, question, feature);
752
			childNodes.add(childNode);
936
	private Rank makeRank(MarkupImportState state, String value, boolean byAbbrev) {
937
		Rank rank = null;
938
		if (StringUtils.isBlank(value)){
939
			return null;
753 940
		}
754
		return childNodes;
755
	}
756

  
757

  
758
	/**
759
	 * @param state
760
	 * @param elKeychoice
761
	 * @return
762
	 */
763
	private KeyStatement handleKeychoiceChar(MarkupImportState state, Element elKeychoice) {
764
		KeyStatement statement = null;
765
		Attribute charAttr = elKeychoice.getAttribute("char");
766
		if (charAttr != null){
767
			String charStr = charAttr.getValue();
768
			if (StringUtils.isNotBlank(charStr)){
769
				statement = KeyStatement.NewInstance(charStr);
941
		try {
942
			boolean useUnknown = true;
943
			NomenclaturalCode nc = makeNomenclaturalCode(state);
944
			if (byAbbrev){
945
				rank = Rank.getRankByAbbreviation(value, nc, useUnknown);
946
			}else{	
947
				rank = Rank.getRankByEnglishName(value, nc, useUnknown);
948
			}
949
			if (rank.equals(Rank.UNKNOWN_RANK())){
950
				rank = null;
770 951
			}
771
			elKeychoice.removeAttribute("char");
952
		} catch (UnknownCdmTypeException e) {
953
			//doNothing
772 954
		}
773
		return statement;
955
		return rank;
774 956
	}
775 957
	
776
	/**
777
	 * @param state
778
	 * @param elKeychoice
779
	 * @return
780
	 */
781
	private Feature handleKeychoiceCharAsFeature(MarkupImportState state, Element elKeychoice) {
782
		Feature feature = null;
783
		Attribute charAttr = elKeychoice.getAttribute("char");
784
		if (charAttr != null){
785
			String charStr = charAttr.getValue();
786
			feature = getFeature(charStr, state);
787
			elKeychoice.removeAttribute("char");
958
	private void doNameEnd(NonViralName name, Rank rank, String text, String classValue, XMLEvent xmlEvent, MarkupImportState state) {
959
		Location location = xmlEvent.getLocation();
960
		if (rank != null){
961
			name.setRank(rank);
962
			if (rank.isSupraGeneric() || rank.isGenus()){
963
				name.setGenusOrUninomial(text);
964
			}else if (rank.isInfraGeneric()){
965
				name.setInfraGenericEpithet(text);
966
			}else if (rank.isSpecies()){
967
				name.setSpecificEpithet(text);
968
			}else if (rank.isInfraSpecific()){
969
				name.setInfraSpecificEpithet(text);
970
			}else{
971
				String message = "Invalid rank '%s'. Can't decide which epithet to fill with '%s'";
972
				message = String.format(message, rank.getTitleCache(), text);
973
				fireWarningEvent(message, makeLocationStr(location), 4);
974
			}
975
		}else{
976
			//infrank, infrparaut, infraut, infrex, notes
977
			//DONE: status,  exaut, paraut, author,
978
			
979
			//STATUS
980
			if (classValue.equalsIgnoreCase("status")){
981
				try {
982
					NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(text);
983
					name.addStatus(NomenclaturalStatus.NewInstance(nomStatusType));
984
				} catch (UnknownCdmTypeException e) {
985
					String message = "Nom. status could not be recognized in '%s'";
986
					message = String.format(message, text);
987
					fireWarningEvent(message, makeLocationStr(location), 2);
988
				}
989
			//NOTES
990
			}else if(classValue.equalsIgnoreCase(NOTES)){
991
				handleNotYetImplementedAttributeValue(xmlEvent, CLASS, classValue);
992
			
993
			//Authors
994
			}else if(classValue.equalsIgnoreCase(AUTHOR)){
995
				//TODO parse
996
				TeamOrPersonBase author = Team.NewTitledInstance(text, text);
997
				name.setCombinationAuthorTeam(author);
998
			}else if(classValue.equalsIgnoreCase(EXAUT)){
999
				//TODO parse
1000
				TeamOrPersonBase exAuthor = Team.NewTitledInstance(text, text);
1001
				name.setExCombinationAuthorTeam(exAuthor);
1002
			}else if(classValue.equalsIgnoreCase(PARAUT)){
1003
				//TODO parse
1004
				TeamOrPersonBase parAuthor = Team.NewTitledInstance(text, text);
1005
				name.setBasionymAuthorTeam(parAuthor);
1006
			}else if(classValue.equalsIgnoreCase("parexaut")){
1007
				//TODO parse
1008
				TeamOrPersonBase parExAuthor = Team.NewTitledInstance(text, text);
1009
				name.setExBasionymAuthorTeam(parExAuthor);
1010
			}else if(classValue.equalsIgnoreCase(INFRPARAUT)){
1011
				//TODO infrparaut <-> paraut
1012
				//TODO parse
1013
				TeamOrPersonBase parAuthor = Team.NewTitledInstance(text, text);
1014
				name.setBasionymAuthorTeam(parAuthor);
1015
			}else if(classValue.equalsIgnoreCase(INFRAUT)){
1016
				//TODO infraut <-> author
1017
				//TODO parse
1018
				TeamOrPersonBase author = Team.NewTitledInstance(text, text);
1019
				name.setCombinationAuthorTeam(author);
1020
			}else if(classValue.equalsIgnoreCase(INFREX)){
1021
				//TODO infrex <-> exaut
1022
				//TODO parse
1023
				TeamOrPersonBase exAuthor = Team.NewTitledInstance(text, text);
1024
				name.setExCombinationAuthorTeam(exAuthor);
1025
			}else if(classValue.equalsIgnoreCase(INFRPAREX)){
1026
				//TODO infrparex <-> parexaut
1027
				//TODO parse
1028
				TeamOrPersonBase exParAuthor = Team.NewTitledInstance(text, text);
1029
				name.setExBasionymAuthorTeam(exParAuthor);
1030
			}else if(classValue.equalsIgnoreCase(INFRANK)){
1031
				if (classValue.equalsIgnoreCase(INFRANK)){
1032
					rank = makeRank(state, text, true);
1033
					if (rank == null){
1034
						//TODO make event
1035
						logger.warn("Rank not recognized: " + text);
1036
					}
1037
				}
1038
				
1039
			}else{
1040
				String message = "Nom.class attribute has unhandled value '%s'";
1041
				message = String.format(message, classValue);
1042
				fireWarningEvent(message, makeLocationStr(location), 2);
1043
			}
788 1044
		}
789
		return feature;
790 1045
	}
791 1046

  
1047
//	public void handleNameNotRank(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, String classValue, NonViralName name) throws XMLStreamException {
1048
//		if (ACCEPTED.equalsIgnoreCase(classValue)){
1049
//		}else if (SYNONYM.equalsIgnoreCase(classValue)){
1050
//		}else{
1051
//			//TODO Not yet implemented
1052
//			handleNotYetImplementedAttributeValue(parentEvent, CLASS, classValue);
1053
//		}
1054
//	}
1055
	
1056

  
1057
	private void handleCitation(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, NonViralName name) throws XMLStreamException {
1058
		String classValue = getClassOnlyAttribute(parentEvent);
792 1059

  
793
	private PolytomousKeyNode handleLead(MarkupImportState state, PolytomousKey key, Element elLead, Taxon taxon, KeyStatement question, Feature feature) {
794
		PolytomousKeyNode node = PolytomousKeyNode.NewInstance();
795
		//TODO the char attribute in the keychoice is more a feature than a question
796
		//needs to be discussed on model side
797
		node.setQuestion(question);
798
//		node.setFeature(feature);
799
		
800
		//text
801
		String text = handleLeadText(elLead, node);
802
		
803
		//num
804
		handleLeadNum(elLead, text);
805
		
806
		//goto
807
		handleLeadGoto(state, key, elLead, taxon, node);
1060
		state.setCitation(true);
1061
		boolean hasRefPart = false;
1062
		Reference reference = ReferenceFactory.newGeneric();
1063
		Map<String, String> refMap = new HashMap<String, String>();
1064
		while (reader.hasNext()){
1065
			XMLEvent next = readNoWhitespace(reader);
1066
			if (isMyEndingElement(next, parentEvent)){
1067
				checkMandatoryElement(hasRefPart, parentEvent.asStartElement(), REF_PART);
1068
				reference = createReference(state, refMap, next);
1069
				String microReference = refMap.get(DETAILS);
1070
				doCitation(state, name, classValue, reference, microReference, parentEvent);
1071
				state.setCitation(false);
1072
				return;
1073
			}else if(isStartingElement(next, REF_PART)){
1074
				handleRefPart(state, reader, next, refMap);
1075
				hasRefPart = true;
1076
			}else{
1077
				handleUnexpectedElement(next);
1078
			}
1079
		}
1080
		throw new IllegalStateException("Citation has no closing tag");
808 1081
		
809
		//others
810
		verifyNoAttribute(elLead);
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff