Project

General

Profile

Download (22.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2009 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.cdm.io.markup;
10

    
11
import java.net.MalformedURLException;
12
import java.net.URL;
13
import java.util.HashSet;
14
import java.util.Map;
15
import java.util.Set;
16
import java.util.UUID;
17

    
18
import javax.xml.stream.Location;
19
import javax.xml.stream.XMLEventReader;
20
import javax.xml.stream.XMLStreamException;
21
import javax.xml.stream.events.Attribute;
22
import javax.xml.stream.events.StartElement;
23
import javax.xml.stream.events.XMLEvent;
24

    
25
import org.apache.commons.lang.StringUtils;
26
import org.apache.logging.log4j.LogManager;
27
import org.apache.logging.log4j.Logger;
28

    
29
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
30
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
31
import eu.etaxonomy.cdm.model.common.ExtensionType;
32
import eu.etaxonomy.cdm.model.common.Language;
33
import eu.etaxonomy.cdm.model.description.Feature;
34
import eu.etaxonomy.cdm.model.description.PolytomousKey;
35
import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
36
import eu.etaxonomy.cdm.model.description.TaxonDescription;
37
import eu.etaxonomy.cdm.model.description.TextData;
38
import eu.etaxonomy.cdm.model.name.INonViralName;
39
import eu.etaxonomy.cdm.model.name.Rank;
40
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
41
import eu.etaxonomy.cdm.model.reference.Reference;
42
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
43
import eu.etaxonomy.cdm.model.taxon.Classification;
44
import eu.etaxonomy.cdm.model.taxon.Taxon;
45
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
46
import eu.etaxonomy.cdm.model.taxon.TaxonNodeStatus;
47

    
48
/**
49
 * @author a.mueller
50
 */
51
public class MarkupDocumentImportNoComponent extends MarkupImportBase {
52
	@SuppressWarnings("unused")
53
	private static final Logger logger = LogManager.getLogger(MarkupDocumentImportNoComponent.class);
54

    
55
	private final MarkupKeyImport keyImport;
56

    
57
	private final MarkupModsImport modsImport;
58
	private final MarkupSpecimenImport specimenImport;
59
	private final MarkupNomenclatureImport nomenclatureImport;
60

    
61
	public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport) {
62
		super(docImport);
63
		this.keyImport = new MarkupKeyImport(docImport);
64
		this.specimenImport = new MarkupSpecimenImport(docImport);
65
		this.nomenclatureImport = new MarkupNomenclatureImport(docImport, specimenImport);
66
		this.modsImport = new MarkupModsImport(docImport);
67
		this.featureImport = new MarkupFeatureImport(docImport, specimenImport, nomenclatureImport, keyImport);
68
	}
69

    
70
	public void doInvoke(MarkupImportState state) throws XMLStreamException {
71
		XMLEventReader reader = state.getReader();
72

    
73
		// publication (= root element)
74
		String elName = PUBLICATION;
75
		boolean hasPublication = false;
76

    
77
		while (reader.hasNext()) {
78
			XMLEvent nextEvent = reader.nextEvent();
79
			if (isStartingElement(nextEvent, elName)) {
80
				handlePublication(state, reader, nextEvent, elName);
81
				hasPublication = true;
82
			} else if (nextEvent.isEndDocument()) {
83
				if (!hasPublication) {
84
					String message = "No publication root element found";
85
					fireWarningEvent(message, nextEvent, 8);
86
				}
87
				// done
88
			} else {
89
				fireSchemaConflictEventExpectedStartTag(elName, reader);
90
			}
91
		}
92

    
93

    
94
		return;
95

    
96
	}
97

    
98
	private void handlePublication(MarkupImportState state, XMLEventReader reader, XMLEvent currentEvent, String elName) throws XMLStreamException {
99

    
100
		// attributes
101
		StartElement element = currentEvent.asStartElement();
102
		Map<String, Attribute> attributes = getAttributes(element);
103
		String lang = getAndRemoveAttributeValue(attributes, "lang");
104
		if (lang != null){
105
			Language language = getTermService().getLanguageByIso(lang);
106
			state.setDefaultLanguage(language);
107
		}
108

    
109
		handleUnexpectedAttributes(element.getLocation(), attributes, "noNamespaceSchemaLocation");
110

    
111
		while (reader.hasNext()) {
112
			XMLEvent event = readNoWhitespace(reader);
113
			// TODO cardinality of alternative
114
			if (isEndingElement(event, elName)) {
115
				return;
116
			} else if (event.isStartElement()) {
117
				if (isStartingElement(event, META_DATA)) {
118
					handleMetaData(state, reader, event);
119
				} else if (isStartingElement(event, TREATMENT)) {
120
					handleTreatment(state, reader, event);
121
				} else if (isStartingElement(event, BIOGRAPHIES)) {
122
					handleNotYetImplementedElement(event);
123
				} else if (isStartingElement(event, REFERENCES)) {
124
					handleNotYetImplementedElement(event);
125
				} else if (isStartingElement(event, TEXT_SECTION)) {
126
					handleNotYetImplementedElement(event);
127
				} else if (isStartingElement(event, ADDENDA)) {
128
					handleNotYetImplementedElement(event);
129
				} else {
130
					handleUnexpectedStartElement(event);
131
				}
132
			} else {
133
				handleUnexpectedElement(event);
134
			}
135
		}
136
		throw new IllegalStateException("Publication has no ending element");
137
	}
138

    
139
	private void handleMetaData(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
140
		checkNoAttributes(parentEvent);
141

    
142
		while (reader.hasNext()) {
143
			XMLEvent next = readNoWhitespace(reader);
144
			if (isMyEndingElement(next, parentEvent)) {
145
				return;
146
			} else if (isStartingElement(next, DEFAULT_MEDIA_URL)) {
147
				String baseUrl = getCData(state, reader, next);
148
				try {
149
					new URL(baseUrl);
150
					state.setBaseMediaUrl(baseUrl);
151
				} catch (MalformedURLException e) {
152
					String message = "defaultMediaUrl '%s' is not a valid URL";
153
					message = String.format(message, baseUrl);
154
					fireWarningEvent(message, next, 8);
155
				}
156
			} else if (isStartingElement(next, MODS)){
157
				modsImport.handleMods(state, reader, next);
158
			} else {
159
				handleUnexpectedElement(next);
160
			}
161
		}
162
		throw new IllegalStateException("MetaData has no ending element");
163

    
164
	}
165

    
166
	private void handleTreatment(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
167
		checkNoAttributes(parentEvent);
168
		Taxon lastTaxon = null;
169
		while (reader.hasNext()) {
170
			XMLEvent next = readNoWhitespace(reader);
171
			if (isMyEndingElement(next, parentEvent)) {
172
				Set<PolytomousKeyNode> keyNodesToSave = state.getPolytomousKeyNodesToSave();
173
				//better save the key then the nodes
174
				Set<PolytomousKey> keySet = new HashSet<>();
175
				for (PolytomousKeyNode node : keyNodesToSave){
176
					PolytomousKey key = node.getKey();
177
					keySet.add(key);
178
				}
179
				save(keySet, state);
180
				//unmatched key leads
181
				UnmatchedLeads unmatched = state.getUnmatchedLeads();
182
				if (unmatched.size() > 0){
183
					String message = "The following %d key leads are unmatched: %s";
184
					message = String.format(message, unmatched.size(), state.getUnmatchedLeads().toString());
185
					fireWarningEvent(message, next, 6);
186
				}
187
//				save(keyNodesToSave, state);
188

    
189
				return;
190
			} else if (isStartingElement(next, TAXON)) {
191
				state.setCurrentTaxonExcluded(false);
192
			    Taxon thisTaxon = handleTaxon(state, reader, next.asStartElement());
193
				doTaxonRelation(state, thisTaxon, lastTaxon, parentEvent.getLocation());
194
				if (state.isTaxonInClassification() == true){
195
					lastTaxon = thisTaxon;
196
					// TODO for imports spanning multiple documents ?? Still needed?
197
					state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());
198
				}
199
			} else if (isStartingElement(next, ADDENDA)) {
200
				handleNotYetImplementedElement(next);
201
			} else {
202
				handleUnexpectedElement(next);
203
			}
204
		}
205
		return;
206
	}
207

    
208
	private TaxonNode doTaxonRelation(MarkupImportState state, Taxon taxon, Taxon lastTaxon, Location dataLocation) {
209

    
210
		if (state.isTaxonInClassification() == false){
211
			return null;
212
		}
213

    
214
		boolean excluded = state.isCurrentTaxonExcluded();
215
		TaxonNode node;
216
		Classification tree = makeTree(state, dataLocation);
217
		if (lastTaxon == null) {
218
			node = tree.addChildTaxon(taxon, null, null);
219
			if (excluded){
220
			    node.setStatus(TaxonNodeStatus.EXCLUDED);
221
			}
222
			return node;
223
		}
224
		Rank thisRank = taxon.getName().getRank();
225
		Rank lastRank = lastTaxon.getName().getRank();
226
		if (lastRank == null){
227
			String message = "Last rank was null. Can't create tree correctly";
228
			fireWarningEvent(message, makeLocationStr(dataLocation), 12);
229
		}
230
		if (!lastTaxon.getTaxonNodes().isEmpty()) {
231
			TaxonNode lastNode = lastTaxon.getTaxonNodes().iterator().next();
232
			if (thisRank == null){
233
			    String message = "Rank is undefined for taxon '%s'. Can't create classification without rank.";
234
				message = String.format(message, taxon.getName().getTitleCache());
235
				fireWarningEvent(message, makeLocationStr(dataLocation), 6);
236
				node = null;
237
			}else if (thisRank.isLower(lastRank)) {
238
			    node = null;
239
	            node = lastNode.addChildTaxon(taxon, null, null);
240
				fillMissingEpithetsForTaxa(lastTaxon, taxon);
241
			} else if (thisRank.equals(lastRank)) {
242
			    TaxonNode parent = lastNode.getParent();
243
				if (parent != null && parent.getTaxon() != null) {
244
					node = parent.addChildTaxon(taxon, null, null);
245
					fillMissingEpithetsForTaxa(parent.getTaxon(), taxon);
246
				} else {
247
					node = tree.addChildTaxon(taxon, null, null);
248
				}
249
			} else if (thisRank.isHigher(lastRank)) {
250
			    TaxonNode parent = lastNode.getParent();
251
				if (parent != null){
252
					node = doTaxonRelation(state, taxon, parent.getTaxon(), dataLocation);
253
				}else{
254
					String warning = "No parent available for lastNode. Classification can not be build correctly. Maybe the rank was missing for the lastNode";
255
					fireWarningEvent(warning, makeLocationStr(dataLocation), 16);
256
					//TODO what to do in this case (haven't spend time to think about yet
257
					node = null;
258
				}
259

    
260
				// TaxonNode parentNode = handleTaxonRelation(state, taxon,
261
				// lastNode.getParent().getTaxon());
262
				// parentNode.addChildTaxon(taxon, null, null, null);
263
			}else{
264
			    fireWarningEvent("Unhandled case", makeLocationStr(dataLocation), 8);
265
			    node = null;
266
			}
267
		} else {
268
			String message = "Last taxon has no node";
269
			fireWarningEvent(message, makeLocationStr(dataLocation), 6);
270
			node = null;
271
		}
272
		if (excluded){
273
		    if (node != null){
274
		        node.setStatus(TaxonNodeStatus.EXCLUDED);
275
		    }else{
276
		        fireWarningEvent("Taxon is excluded but no taxon node can be created", makeLocationStr(dataLocation), 4);
277
		    }
278
		}
279
		return node;
280
	}
281

    
282
	private Classification makeTree(MarkupImportState state, Location dataLocation) {
283
		Classification result = state.getTree(null);
284
		if (result == null) {
285
			UUID uuid = state.getConfig().getClassificationUuid();
286
			if (uuid == null) {
287
				String message = "No classification uuid is defined";
288
				fireWarningEvent(message, makeLocationStr(dataLocation), 6);
289
				result = createNewClassification(state);
290
			} else {
291
				result = getClassificationService().find(uuid);
292
				if (result == null) {
293
					result = createNewClassification(state);
294
					result.setUuid(uuid);
295
				}
296
			}
297
			state.putTree(null, result);
298
		}
299
		save(result, state);
300
		return result;
301
	}
302

    
303
	private Classification createNewClassification(MarkupImportState state) {
304
		Classification result = Classification.NewInstance(state.getConfig().getClassificationName(), getDefaultLanguage(state));
305
		state.putTree(null, result);
306
		return result;
307
	}
308

    
309
	private Taxon handleTaxon(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) throws XMLStreamException {
310
		// TODO progress monitoring
311
		Map<String, Attribute> attributes = getAttributes(parentEvent);
312
		Taxon taxon = createTaxonAndName(state, attributes, parentEvent);
313
		state.setCurrentTaxon(taxon);
314
		state.addNewFeatureSorterLists(taxon.getUuid().toString());
315

    
316
		boolean hasTitle = false;
317
		boolean hasNomenclature = false;
318
		String taxonTitle = null;
319

    
320
		Reference sourceReference = state.getConfig().getSourceReference();
321
		while (reader.hasNext()) {
322
			XMLEvent next = readNoWhitespace(reader);
323
			if (isMyEndingElement(next, parentEvent)) {
324
//				checkMandatoryElement(hasTitle, parentEvent, TAXONTITLE);
325
				checkMandatoryElement(hasNomenclature, parentEvent,	NOMENCLATURE);
326
				boolean inClassification = getAndRemoveBooleanAttributeValue(next, attributes, "inClassification", true);
327
				state.setTaxonInClassification(inClassification);
328
				handleUnexpectedAttributes(parentEvent.getLocation(),attributes);
329
				if (taxon.getName().getRank() == null){
330
					String warning = "No rank exists for taxon " + taxon.getTitleCache();
331
					fireWarningEvent(warning, next, 12);
332
					taxon.getName().setRank(Rank.UNKNOWN_RANK());
333
				}
334
				//hybrid
335
				if (state.isTaxonIsHybrid() && !taxon.getName().isHybrid()){
336
				    fireWarningEvent("Taxon is hybrid but name is not a hybrid name", next, 4);
337
				}
338
				state.setTaxonIsHybrid(false);
339

    
340
				keyImport.makeKeyNodes(state, parentEvent, taxonTitle);
341
				state.setCurrentTaxon(null);
342
				state.setCurrentTaxonNum(null);
343
				if (taxon.getName().getRank().isHigher(Rank.GENUS())){
344
					state.setLatestGenusEpithet(null);
345
				}else{
346
					state.setLatestGenusEpithet(taxon.getName().getGenusOrUninomial());
347
				}
348
				save(taxon, state);
349
				return taxon;
350
			} else if (next.isStartElement()) {
351
				if (isStartingElement(next, HEADING)) {
352
					handleNotYetImplementedElement(next);
353
				} else if (isStartingElement(next, TAXONTITLE)) {
354
					taxonTitle = handleTaxonTitle(state, reader, next);
355
					hasTitle = true;
356
				} else if (isStartingElement(next, WRITER)) {
357
					makeKeyWriter(state, reader, taxon, taxonTitle, next);
358
				} else if (isStartingElement(next, TEXT_SECTION)) {
359
					handleNotYetImplementedElement(next);
360
				} else if (isStartingElement(next, KEY)) {
361
					keyImport.handleKey(state, reader, next);
362
				} else if (isStartingElement(next, NOMENCLATURE)) {
363
					nomenclatureImport.handleNomenclature(state, reader, next);
364
					hasNomenclature = true;
365
				} else if (isStartingElement(next, FEATURE)) {
366
					featureImport.handleFeature(state, reader, next);
367
				} else if (isStartingElement(next, NOTES)) {
368
					// TODO is this the correct way to handle notes?
369
					String note = handleNotes(state, reader, next);
370

    
371
					UUID notesUuid;
372
					try {
373
						notesUuid = state.getTransformer().getFeatureUuid("notes");
374
						Feature feature = getFeature(state, notesUuid, "Notes",	"Notes", "note", null);
375
						TextData textData = TextData.NewInstance(feature);
376
						textData.addPrimaryTaxonomicSource(sourceReference);
377
						textData.putText(getDefaultLanguage(state), note);
378
						TaxonDescription description = getDefaultTaxonDescription(taxon, false, true, sourceReference);
379
						description.addElement(textData);
380
					} catch (UndefinedTransformerMethodException e) {
381
						String message = "getFeatureUuid method not yet implemented";
382
						fireWarningEvent(message, next, 8);
383
					}
384
				} else if (isStartingElement(next, REFERENCES)) {
385
					handleNotYetImplementedElement(next);
386
				} else if (isStartingElement(next, FIGURE_REF)) {
387
					TaxonDescription desc = getTaxonDescription(taxon, sourceReference, IMAGE_GALLERY, CREATE_NEW);
388
					TextData textData;
389
					if (desc.getElements().isEmpty()){
390
						textData = TextData.NewInstance(Feature.IMAGE());
391
						textData.addPrimaryTaxonomicSource(sourceReference);
392
						desc.addElement(textData);
393
					}
394
					textData = (TextData)desc.getElements().iterator().next();
395
					featureImport.makeFeatureFigureRef(state, reader, desc, false, textData, sourceReference, next);
396
				} else if (isStartingElement(next, FIGURE)) {
397
					handleFigure(state, reader, next, specimenImport, nomenclatureImport);
398
				} else if (isStartingElement(next, FOOTNOTE)) {
399
					FootnoteDataHolder footnote = handleFootnote(state, reader,	next, specimenImport, nomenclatureImport);
400
					if (footnote.isRef()) {
401
						String message = "Ref footnote not implemented here";
402
						fireWarningEvent(message, next, 4);
403
					} else {
404
						registerGivenFootnote(state, footnote);
405
					}
406
				} else {
407
					handleUnexpectedStartElement(next);
408
				}
409
			} else {
410
				handleUnexpectedElement(next);
411
			}
412
		}
413
		throw new IllegalStateException("<Taxon> has no closing tag");
414
	}
415

    
416
	/**
417
	 * @param state
418
	 * @param reader
419
	 * @param taxon
420
	 * @param taxonTitle
421
	 * @param next
422
	 * @throws XMLStreamException
423
	 */
424
	private void makeKeyWriter(MarkupImportState state, XMLEventReader reader, Taxon taxon, String taxonTitle, XMLEvent next) throws XMLStreamException {
425
		WriterDataHolder writer = handleWriter(state, reader, next);
426
		if (state.getConfig().isHandleWriterManually()){
427
		    fireWarningEvent("<Writer> is expected to be handled manually", next, 1);
428
		}else{
429
		    taxon.addExtension(writer.extension);
430
	        // TODO what if taxonTitle comes later
431
	        taxonTitle = taxonTitle != null ? taxonTitle : taxon.getName() == null ? null : taxon.getName().getNameCache();
432
	        if (writer.extension != null) {
433
	            if (StringUtils.isBlank(taxonTitle)){
434
	                fireWarningEvent("No taxon title defined for writer. Please add sec.title manually.", next, 6);
435
	                taxonTitle = null;
436
	            }
437
	            Reference sec = ReferenceFactory.newBookSection();
438
	            sec.setTitle(taxonTitle);
439
	            TeamOrPersonBase<?> author = createAuthor(state, writer.writer);
440
	            sec.setAuthorship(author);
441
	            sec.setInReference(state.getConfig().getSourceReference());
442
	            taxon.setSec(sec);
443
	            registerFootnotes(state, sec, writer.footnotes);
444
	        } else {
445
	            String message = "There is no writer extension defined";
446
	            fireWarningEvent(message, next, 6);
447
	        }
448
		}
449
	}
450

    
451
	private String handleNotes(MarkupImportState state, XMLEventReader reader,
452
			XMLEvent parentEvent) throws XMLStreamException {
453
		checkNoAttributes(parentEvent);
454

    
455
		String text = "";
456
		while (reader.hasNext()) {
457
			XMLEvent next = readNoWhitespace(reader);
458
			if (isMyEndingElement(next, parentEvent)) {
459
				return text;
460
			} else if (next.isStartElement()) {
461
				if (isStartingElement(next, HEADING)) {
462
					handleNotYetImplementedElement(next);
463
				} else if (isStartingElement(next, SUB_HEADING)) {
464
					String subheading = getCData(state, reader, next).trim();
465
					if (! isNoteHeading(subheading)) {
466
						fireNotYetImplementedElement(next.getLocation(), next.asStartElement().getName(), 0);
467
					}
468
				} else if (isStartingElement(next, WRITER)) {
469
					handleNotYetImplementedElement(next);
470
				} else if (isStartingElement(next, NUM)) {
471
					handleNotYetImplementedElement(next);
472
				} else if (isStartingElement(next, STRING)) {
473
					// TODO why multiple strings in schema?
474
					text = makeNotesString(state, reader, text, next);
475
				} else {
476
					handleUnexpectedStartElement(next.asStartElement());
477
				}
478
			} else {
479
				handleUnexpectedElement(next);
480
			}
481
		}
482
		throw new IllegalStateException("<Notes> has no closing tag");
483
	}
484

    
485
	/**
486
	 * @param state
487
	 * @param reader
488
	 * @param text
489
	 * @param next
490
	 * @return
491
	 * @throws XMLStreamException
492
	 */
493
	private String makeNotesString(MarkupImportState state,	XMLEventReader reader, String text, XMLEvent next) throws XMLStreamException {
494
		Map<String, SubheadingResult> stringMap = handleString(state, reader,	next, null);
495
		if (stringMap.size() == 0){
496
			String message = "No text available in <notes>";
497
			fireWarningEvent(message, next, 4);
498
		}else if (stringMap.size() > 1){
499
			String message = "Subheadings not yet supported in <notes>";
500
			fireWarningEvent(message, next, 4);
501
		}else{
502
			String firstSubheading = stringMap.keySet().iterator().next();
503
			if ( firstSubheading != null && ! isNoteHeading (firstSubheading) )  {
504
				String message = "Subheadings not yet supported in <notes>";
505
				fireWarningEvent(message, next, 4);
506
			}
507
		}
508
		for (String subheading : stringMap.keySet()){
509
			text += subheading;
510
			text += stringMap.get(subheading);
511
		}
512
		return text;
513
	}
514

    
515
	private boolean isNoteHeading(String heading) {
516
		String excludePattern = "(i?)(Notes?):?";
517
		return heading.matches(excludePattern);
518
	}
519

    
520
	/**
521
	 * @param state
522
	 * @param attributes
523
	 * @param event
524
	 */
525
	private Taxon createTaxonAndName(MarkupImportState state,
526
			Map<String, Attribute> attributes, StartElement event) {
527

    
528
		INonViralName name;
529
		Rank rank = null;  //Rank.SPECIES(); // default
530
		boolean isCultivar = checkAndRemoveAttributeValue(attributes, CLASS, "cultivated");
531

    
532
		if (isCultivar) {
533
			name = TaxonNameFactory.NewCultivarInstance(rank);
534
		} else {
535
			name = createNameByCode(state, rank);
536
		}
537
		Taxon taxon = Taxon.NewInstance(name, state.getConfig().getSourceReference());
538
		if (checkAndRemoveAttributeValue(attributes, CLASS, "dubious")) {
539
			taxon.setDoubtful(true);
540
		} else if (checkAndRemoveAttributeValue(attributes, CLASS, "excluded")) {
541
			state.setCurrentTaxonExcluded(true);
542
		}
543
        state.setTaxonIsHybrid(checkAndRemoveAttributeValue(attributes, CLASS, "hybrid"));
544

    
545
		// TODO insufficient, new, expected
546
		handleNotYetImplementedAttribute(attributes, CLASS, event);
547
		// From old version
548
		// MarkerType markerType = getMarkerType(state, attrValue);
549
		// if (markerType == null){
550
		// logger.warn("Class attribute value for taxon not yet supported: " +
551
		// attrValue);
552
		// }else{
553
		// taxon.addMarker(Marker.NewInstance(markerType, true));
554
		// }
555

    
556
		// save(name, state);
557
		// save(taxon, state);
558
		return taxon;
559
	}
560

    
561
	private String handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
562
		//attributes
563
		String text = "";
564
		Map<String, Attribute> attributes = getAttributes(parentEvent);
565
		String rankAttr = getAndRemoveAttributeValue(attributes, RANK);
566
		Rank rank = makeRank(state, rankAttr, false);
567
		String num = getAndRemoveAttributeValue(attributes, NUM);
568
		state.setCurrentTaxonNum(num);
569
		checkNoAttributes(attributes, parentEvent);
570

    
571
		// TODO handle attributes
572
		while (reader.hasNext()) {
573
			XMLEvent next = readNoWhitespace(reader);
574
			if (next.isEndElement()) {
575
				if (isMyEndingElement(next, parentEvent)) {
576
					Taxon taxon = state.getCurrentTaxon();
577
					String titleText = null;
578
					if (state.getConfig().isDoExtensionForTaxonTitle() && checkMandatoryText(text, parentEvent)) {
579
						titleText = normalize(text);
580
						UUID uuidTitle = MarkupTransformer.uuidTaxonTitle;
581
						ExtensionType titleExtension = this.getExtensionType(state, uuidTitle, "Taxon Title ","taxon title", "title");
582
						taxon.addExtension(titleText, titleExtension);
583
					}
584
					taxon.getName().setRank(rank);
585
					// TODO check title exists
586
					return titleText;
587
				} else {
588
					if (isEndingElement(next, FOOTNOTE)) {
589
						// NOT YET IMPLEMENTED
590
						popUnimplemented(next.asEndElement());
591
					} else {
592
						handleUnexpectedEndElement(next.asEndElement());
593
						state.setUnsuccessfull();
594
					}
595
				}
596
			} else if (next.isStartElement()) {
597
				if (isStartingElement(next, FOOTNOTE)) {
598
					handleNotYetImplementedElement(next);
599
				}else if (isStartingElement(next, FOOTNOTE_REF)) {
600
					handleNotYetImplementedElement(next);
601
				} else {
602
					handleUnexpectedStartElement(next);
603
					state.setUnsuccessfull();
604
				}
605
			} else if (next.isCharacters()) {
606
				text += next.asCharacters().getData();
607

    
608
			} else {
609
				handleUnexpectedElement(next);
610
				state.setUnsuccessfull();
611
			}
612
		}
613
		return null;
614

    
615
	}
616

    
617

    
618
}
(7-7/19)