Project

General

Profile

Download (22 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

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

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

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

    
26
import org.apache.commons.lang.StringUtils;
27
import org.apache.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.common.OriginalSourceType;
34
import eu.etaxonomy.cdm.model.common.TermVocabulary;
35
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
36
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
37
import eu.etaxonomy.cdm.model.description.Distribution;
38
import eu.etaxonomy.cdm.model.description.Feature;
39
import eu.etaxonomy.cdm.model.description.PolytomousKey;
40
import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
41
import eu.etaxonomy.cdm.model.description.TaxonDescription;
42
import eu.etaxonomy.cdm.model.description.TextData;
43
import eu.etaxonomy.cdm.model.name.CultivarPlantName;
44
import eu.etaxonomy.cdm.model.name.NonViralName;
45
import eu.etaxonomy.cdm.model.name.Rank;
46
import eu.etaxonomy.cdm.model.reference.Reference;
47
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
48
import eu.etaxonomy.cdm.model.taxon.Classification;
49
import eu.etaxonomy.cdm.model.taxon.Taxon;
50
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
51

    
52

    
53
/**
54
 * @author a.mueller
55
 * 
56
 */
57
public class MarkupDocumentImportNoComponent extends MarkupImportBase {
58
	@SuppressWarnings("unused")
59
	private static final Logger logger = Logger.getLogger(MarkupDocumentImportNoComponent.class);
60
	
61
	private MarkupKeyImport keyImport;
62

    
63
	private MarkupModsImport modsImport;
64
	private MarkupFeatureImport featureImport;
65
	private MarkupSpecimenImport specimenImport;
66
	private MarkupNomenclatureImport nomenclatureImport;
67

    
68
	public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport) {
69
		super(docImport);
70
		this.keyImport = new MarkupKeyImport(docImport);
71
		this.specimenImport = new MarkupSpecimenImport(docImport);
72
		this.nomenclatureImport = new MarkupNomenclatureImport(docImport, specimenImport);
73
		this.modsImport = new MarkupModsImport(docImport);
74
		this.featureImport = new MarkupFeatureImport(docImport, specimenImport, nomenclatureImport);
75
	}
76

    
77
	public void doInvoke(MarkupImportState state) throws XMLStreamException { 
78
		XMLEventReader reader = state.getReader();
79
		
80
		// publication (= root element)
81
		String elName = PUBLICATION;
82
		boolean hasPublication = false;
83
		
84
		while (reader.hasNext()) {
85
			XMLEvent nextEvent = reader.nextEvent();
86
			if (isStartingElement(nextEvent, elName)) {
87
				handlePublication(state, reader, nextEvent, elName);
88
				hasPublication = true;
89
			} else if (nextEvent.isEndDocument()) {
90
				if (!hasPublication) {
91
					String message = "No publication root element found";
92
					fireWarningEvent(message, nextEvent, 8);
93
				}
94
				// done
95
			} else {
96
				fireSchemaConflictEventExpectedStartTag(elName, reader);
97
			}
98
		}
99

    
100
		
101
		return;
102

    
103
	}
104

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

    
107
		// attributes
108
		StartElement element = currentEvent.asStartElement();
109
		Map<String, Attribute> attributes = getAttributes(element);
110
		String lang = getAndRemoveAttributeValue(attributes, "lang");
111
		if (lang != null){
112
			Language language = getTermService().getLanguageByIso(lang);
113
			state.setDefaultLanguage(language);
114
		}
115
		
116
		handleUnexpectedAttributes(element.getLocation(), attributes, "noNamespaceSchemaLocation");
117

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

    
146
	private void handleMetaData(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
147
		checkNoAttributes(parentEvent);
148

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

    
171
	}
172

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

    
196
				return;
197
			} else if (isStartingElement(next, TAXON)) {
198
				Taxon thisTaxon = handleTaxon(state, reader, next.asStartElement());
199
				doTaxonRelation(state, thisTaxon, lastTaxon, parentEvent.getLocation());
200
				if (state.isTaxonInClassification() == true){
201
					lastTaxon = thisTaxon;
202
					// TODO for imports spanning multiple documents ?? Still needed?
203
					state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());
204
				}
205
			} else if (isStartingElement(next, ADDENDA)) {
206
				handleNotYetImplementedElement(next);
207
			} else {
208
				handleUnexpectedElement(next);
209
			}
210
		}
211
		return;
212
	}
213

    
214
	/**
215
	 * @param taxon
216
	 * @param lastTaxon
217
	 */
218
	private void doTaxonRelation(MarkupImportState state, Taxon taxon, Taxon lastTaxon, Location dataLocation) {
219

    
220
		if (state.isTaxonInClassification() == false){
221
			return;
222
		}
223
		
224
		Classification tree = makeTree(state, dataLocation);
225
		if (lastTaxon == null) {
226
			tree.addChildTaxon(taxon, null, null);
227
			return;
228
		}
229
		Rank thisRank = taxon.getName().getRank();
230
		Rank lastRank = lastTaxon.getName().getRank();
231
		if (lastRank == null){
232
			String message = "Last rank was null. Can't create tree correctly";
233
			fireWarningEvent(message, makeLocationStr(dataLocation), 12);
234
		}
235
		if (lastTaxon.getTaxonNodes().size() > 0) {
236
			TaxonNode lastNode = lastTaxon.getTaxonNodes().iterator().next();
237
			if (thisRank == null){
238
				String message = "Rank is undefined for taxon '%s'. Can't create classification without rank.";
239
				message = String.format(message, taxon.getName().getTitleCache());
240
				fireWarningEvent(message, makeLocationStr(dataLocation), 6);
241
			}else if (thisRank.isLower(lastRank)) {
242
				lastNode.addChildTaxon(taxon, null, null);
243
				fillMissingEpithetsForTaxa(lastTaxon, taxon);
244
			} else if (thisRank.equals(lastRank)) {
245
				TaxonNode parent = lastNode.getParent();
246
				if (parent != null) {
247
					parent.addChildTaxon(taxon, null, null);
248
					fillMissingEpithetsForTaxa(parent.getTaxon(), taxon);
249
				} else {
250
					tree.addChildTaxon(taxon, null, null);
251
				}
252
			} else if (thisRank.isHigher(lastRank)) {
253
				TaxonNode parent = lastNode.getParent();
254
				if (parent != null){
255
					doTaxonRelation(state, taxon, parent.getTaxon(),	dataLocation);
256
				}else{
257
					String warning = "No parent available for lastNode. Classification can not be build correctly. Maybe the rank was missing for the lastNode";
258
					fireWarningEvent(warning, makeLocationStr(dataLocation), 16);
259
					//TODO what to do in this case (haven't spend time to think about yet
260
				}
261
				// TaxonNode parentNode = handleTaxonRelation(state, taxon,
262
				// lastNode.getParent().getTaxon());
263
				// parentNode.addChildTaxon(taxon, null, null, null);
264
			}
265
		} else {
266
			String message = "Last taxon has no node";
267
			fireWarningEvent(message, makeLocationStr(dataLocation), 6);
268
		}
269
	}
270

    
271

    
272

    
273
	/**
274
	 * @param state
275
	 * @param dataLocation 
276
	 * @return
277
	 */
278
	private Classification makeTree(MarkupImportState state, Location dataLocation) {
279
		Classification result = state.getTree(null);
280
		if (result == null) {
281
			UUID uuid = state.getConfig().getClassificationUuid();
282
			if (uuid == null) {
283
				String message = "No classification uuid is defined";
284
				fireWarningEvent(message, makeLocationStr(dataLocation), 6);
285
				result = createNewClassification(state);
286
			} else {
287
				result = getClassificationService().find(uuid);
288
				if (result == null) {
289
					result = createNewClassification(state);
290
					result.setUuid(uuid);
291
				}
292
			}
293
			state.putTree(null, result);
294
		}
295
		save(result, state);
296
		return result;
297
	}
298

    
299
	private Classification createNewClassification(MarkupImportState state) {
300
		Classification result = Classification.NewInstance(state.getConfig().getClassificationName(), getDefaultLanguage(state));
301
		state.putTree(null, result);
302
		return result;
303
	}
304

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

    
316
		Reference<?> descriptionReference = state.getConfig().getSourceReference();
317
		while (reader.hasNext()) {
318
			XMLEvent next = readNoWhitespace(reader);
319
			if (isMyEndingElement(next, parentEvent)) {
320
//				checkMandatoryElement(hasTitle, parentEvent, TAXONTITLE);
321
				checkMandatoryElement(hasNomenclature, parentEvent,	NOMENCLATURE);
322
				boolean inClassification = getAndRemoveBooleanAttributeValue(next, attributes, "inClassification", true);
323
				state.setTaxonInClassification(inClassification);
324
				handleUnexpectedAttributes(parentEvent.getLocation(),attributes);
325
				if (taxon.getName().getRank() == null){
326
					String warning = "No rank exists for taxon " + taxon.getTitleCache();
327
					fireWarningEvent(warning, next, 12);
328
					taxon.getName().setRank(Rank.UNKNOWN_RANK());
329
				}
330
				
331
				keyImport.makeKeyNodes(state, parentEvent, taxonTitle);
332
				state.setCurrentTaxon(null);
333
				state.setCurrentTaxonNum(null);
334
				if (taxon.getName().getRank().isHigher(Rank.GENUS())){
335
					state.setLatestGenusEpithet(null);
336
				}else{
337
					state.setLatestGenusEpithet(((NonViralName<?>)taxon.getName()).getGenusOrUninomial());
338
				}
339
				save(taxon, state);
340
				return taxon;
341
			} else if (next.isStartElement()) {
342
				if (isStartingElement(next, HEADING)) {
343
					handleNotYetImplementedElement(next);
344
				} else if (isStartingElement(next, TAXONTITLE)) {
345
					taxonTitle = handleTaxonTitle(state, reader, next);
346
					hasTitle = true;
347
				} else if (isStartingElement(next, WRITER)) {
348
					makeKeyWriter(state, reader, taxon, taxonTitle, next);
349
				} else if (isStartingElement(next, TEXT_SECTION)) {
350
					handleNotYetImplementedElement(next);
351
				} else if (isStartingElement(next, KEY)) {
352
					keyImport.handleKey(state, reader, next);
353
				} else if (isStartingElement(next, NOMENCLATURE)) {
354
					nomenclatureImport.handleNomenclature(state, reader, next);
355
					hasNomenclature = true;
356
				} else if (isStartingElement(next, FEATURE)) {
357
					featureImport.handleFeature(state, reader, next);
358
				} else if (isStartingElement(next, NOTES)) {
359
					// TODO is this the correct way to handle notes?
360
					String note = handleNotes(state, reader, next);
361

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

    
405
	/**
406
	 * @param state
407
	 * @param reader
408
	 * @param taxon
409
	 * @param taxonTitle
410
	 * @param next
411
	 * @throws XMLStreamException
412
	 */
413
	private void makeKeyWriter(MarkupImportState state, XMLEventReader reader, Taxon taxon, String taxonTitle, XMLEvent next) throws XMLStreamException {
414
		WriterDataHolder writer = handleWriter(state, reader, next);
415
		taxon.addExtension(writer.extension);
416
		// TODO what if taxonTitle comes later
417
		taxonTitle = taxonTitle != null ? taxonTitle : taxon.getName() == null ? null : ((NonViralName)taxon.getName()).getNameCache();
418
		if (writer.extension != null) {
419
			if (StringUtils.isBlank(taxonTitle)){
420
				fireWarningEvent("No taxon title defined for writer. Please add sec.title manually.", next, 6);
421
				taxonTitle = null;
422
			}
423
			Reference<?> sec = ReferenceFactory.newBookSection();
424
			sec.setTitle(taxonTitle);
425
			TeamOrPersonBase<?> author = createAuthor(writer.writer);
426
			sec.setAuthorship(author);
427
			sec.setInReference(state.getConfig().getSourceReference());
428
			taxon.setSec(sec);
429
			registerFootnotes(state, sec, writer.footnotes);
430
		} else {
431
			String message = "There is no writer extension defined";
432
			fireWarningEvent(message, next, 6);
433
		}
434
	}
435

    
436
	private String handleNotes(MarkupImportState state, XMLEventReader reader,
437
			XMLEvent parentEvent) throws XMLStreamException {
438
		checkNoAttributes(parentEvent);
439

    
440
		String text = "";
441
		while (reader.hasNext()) {
442
			XMLEvent next = readNoWhitespace(reader);
443
			if (isMyEndingElement(next, parentEvent)) {
444
				return text;
445
			} else if (next.isStartElement()) {
446
				if (isStartingElement(next, HEADING)) {
447
					handleNotYetImplementedElement(next);
448
				} else if (isStartingElement(next, SUB_HEADING)) {
449
					String subheading = getCData(state, reader, next).trim();
450
					if (! isNoteHeading(subheading)) {
451
						fireNotYetImplementedElement(next.getLocation(), next.asStartElement().getName(), 0);
452
					}
453
				} else if (isStartingElement(next, WRITER)) {
454
					handleNotYetImplementedElement(next);
455
				} else if (isStartingElement(next, NUM)) {
456
					handleNotYetImplementedElement(next);
457
				} else if (isStartingElement(next, STRING)) {
458
					// TODO why multiple strings in schema?
459
					text = makeNotesString(state, reader, text, next);
460
				} else {
461
					handleUnexpectedStartElement(next.asStartElement());
462
				}
463
			} else {
464
				handleUnexpectedElement(next);
465
			}
466
		}
467
		throw new IllegalStateException("<Notes> has no closing tag");
468
	}
469

    
470
	/**
471
	 * @param state
472
	 * @param reader
473
	 * @param text
474
	 * @param next
475
	 * @return
476
	 * @throws XMLStreamException
477
	 */
478
	private String makeNotesString(MarkupImportState state,	XMLEventReader reader, String text, XMLEvent next) throws XMLStreamException {
479
		Map<String, String> stringMap = handleString(state, reader,	next, null);
480
		if (stringMap.size() == 0){
481
			String message = "No text available in <notes>";
482
			fireWarningEvent(message, next, 4);
483
		}else if (stringMap.size() > 1){
484
			String message = "Subheadings not yet supported in <notes>";
485
			fireWarningEvent(message, next, 4);
486
		}else{
487
			String firstSubheading = stringMap.keySet().iterator().next();
488
			if ( firstSubheading != null && ! isNoteHeading (firstSubheading) )  {
489
				String message = "Subheadings not yet supported in <notes>";
490
				fireWarningEvent(message, next, 4);
491
			}
492
		}
493
		for (String subheading : stringMap.keySet()){
494
			text += subheading;
495
			text += stringMap.get(subheading);
496
		}
497
		return text;
498
	}
499

    
500
	private boolean isNoteHeading(String heading) {
501
		String excludePattern = "(i?)(Notes?):?";
502
		return heading.matches(excludePattern);
503
	}
504

    
505
	/**
506
	 * @param state
507
	 * @param attributes
508
	 */
509
	private Taxon createTaxonAndName(MarkupImportState state,
510
			Map<String, Attribute> attributes) {
511
		NonViralName<?> name;
512
		Rank rank = null;  //Rank.SPECIES(); // default
513
		boolean isCultivar = checkAndRemoveAttributeValue(attributes, CLASS, "cultivated");
514
		if (isCultivar) {
515
			name = CultivarPlantName.NewInstance(rank);
516
		} else {
517
			name = createNameByCode(state, rank);
518
		}
519
		Taxon taxon = Taxon.NewInstance(name, state.getConfig().getSourceReference());
520
		if (checkAndRemoveAttributeValue(attributes, CLASS, "dubious")) {
521
			taxon.setDoubtful(true);
522
		} else if (checkAndRemoveAttributeValue(attributes, CLASS, "excluded")) {
523
			taxon.setExcluded(true);
524
		}
525
		// TODO insufficient, new, expected
526
		handleNotYetImplementedAttribute(attributes, CLASS);
527
		// From old version
528
		// MarkerType markerType = getMarkerType(state, attrValue);
529
		// if (markerType == null){
530
		// logger.warn("Class attribute value for taxon not yet supported: " +
531
		// attrValue);
532
		// }else{
533
		// taxon.addMarker(Marker.NewInstance(markerType, true));
534
		// }
535

    
536
		// save(name, state);
537
		// save(taxon, state);
538
		return taxon;
539
	}
540

    
541
	private String handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
542
		//attributes
543
		String text = "";
544
		Map<String, Attribute> attributes = getAttributes(parentEvent);
545
		String rankAttr = getAndRemoveAttributeValue(attributes, RANK);
546
		Rank rank = makeRank(state, rankAttr, false);
547
		String num = getAndRemoveAttributeValue(attributes, NUM);
548
		state.setCurrentTaxonNum(num);
549
		checkNoAttributes(attributes, parentEvent);
550

    
551
		// TODO handle attributes
552
		while (reader.hasNext()) {
553
			XMLEvent next = readNoWhitespace(reader);
554
			if (next.isEndElement()) {
555
				if (isMyEndingElement(next, parentEvent)) {
556
					Taxon taxon = state.getCurrentTaxon();
557
					String titleText = null;
558
					if (checkMandatoryText(text, parentEvent)) {
559
						titleText = normalize(text);
560
						UUID uuidTitle = MarkupTransformer.uuidTaxonTitle;
561
						ExtensionType titleExtension = this.getExtensionType(state, uuidTitle, "Taxon Title ","taxon title", "title");
562
						taxon.addExtension(titleText, titleExtension);
563
					}
564
					taxon.getName().setRank(rank);
565
					// TODO check title exists
566
					return titleText;
567
				} else {
568
					if (isEndingElement(next, FOOTNOTE)) {
569
						// NOT YET IMPLEMENTED
570
						popUnimplemented(next.asEndElement());
571
					} else {
572
						handleUnexpectedEndElement(next.asEndElement());
573
						state.setUnsuccessfull();
574
					}
575
				}
576
			} else if (next.isStartElement()) {
577
				if (isStartingElement(next, FOOTNOTE)) {
578
					handleNotYetImplementedElement(next);
579
				}else if (isStartingElement(next, FOOTNOTE_REF)) {
580
					handleNotYetImplementedElement(next);
581
				} else {
582
					handleUnexpectedStartElement(next);
583
					state.setUnsuccessfull();
584
				}
585
			} else if (next.isCharacters()) {
586
				text += next.asCharacters().getData();
587

    
588
			} else {
589
				handleUnexpectedElement(next);
590
				state.setUnsuccessfull();
591
			}
592
		}
593
		return null;
594

    
595
	}
596

    
597

    
598
}
(7-7/19)