2 * Copyright (C) 2009 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.io
.markup
;
12 import java
.net
.MalformedURLException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Arrays
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
22 import java
.util
.regex
.Matcher
;
23 import java
.util
.regex
.Pattern
;
25 import javax
.xml
.stream
.Location
;
26 import javax
.xml
.stream
.XMLEventReader
;
27 import javax
.xml
.stream
.XMLStreamException
;
28 import javax
.xml
.stream
.events
.Attribute
;
29 import javax
.xml
.stream
.events
.StartElement
;
30 import javax
.xml
.stream
.events
.XMLEvent
;
32 import org
.apache
.commons
.lang
.StringUtils
;
33 import org
.apache
.commons
.lang
.WordUtils
;
34 import org
.apache
.log4j
.Logger
;
36 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
37 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
.DerivedUnitType
;
38 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacadeCacheStrategy
;
39 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
40 import eu
.etaxonomy
.cdm
.ext
.geo
.GeoServiceArea
;
41 import eu
.etaxonomy
.cdm
.ext
.geo
.IEditGeoService
;
42 import eu
.etaxonomy
.cdm
.io
.common
.CdmImportBase
;
43 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
44 import eu
.etaxonomy
.cdm
.io
.markup
.UnmatchedLeads
.UnmatchedLeadsKey
;
45 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
46 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
47 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
48 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
49 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
50 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
51 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
52 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
53 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
54 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
55 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
56 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
57 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
58 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
59 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
60 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
61 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
62 import eu
.etaxonomy
.cdm
.model
.description
.IndividualsAssociation
;
63 import eu
.etaxonomy
.cdm
.model
.description
.KeyStatement
;
64 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
65 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
66 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
67 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
68 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
69 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
70 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
71 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
72 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
73 import eu
.etaxonomy
.cdm
.model
.media
.IdentifiableMediaEntity
;
74 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
75 import eu
.etaxonomy
.cdm
.model
.name
.CultivarPlantName
;
76 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
77 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignationStatus
;
78 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
79 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
80 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
81 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
82 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
83 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignationStatus
;
84 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
85 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
86 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
87 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
88 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
89 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
90 import eu
.etaxonomy
.cdm
.model
.reference
.IArticle
;
91 import eu
.etaxonomy
.cdm
.model
.reference
.IJournal
;
92 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
93 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceFactory
;
94 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceType
;
95 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
96 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
97 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
98 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
99 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
100 import eu
.etaxonomy
.cdm
.strategy
.parser
.NameTypeParser
;
101 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
102 import eu
.etaxonomy
.cdm
.strategy
.parser
.SpecimenTypeParser
;
103 import eu
.etaxonomy
.cdm
.strategy
.parser
.SpecimenTypeParser
.TypeInfo
;
109 public class MarkupDocumentImportNoComponent
extends MarkupImportBase
{
110 private static final Logger logger
= Logger
.getLogger(MarkupDocumentImportNoComponent
.class);
112 private static final boolean CREATE_NEW
= true;
113 private static final boolean IS_IMAGE_GALLERY
= true;
114 private static final boolean NO_IMAGE_GALLERY
= false;
117 private static final String ACCEPTED
= "accepted";
118 private static final String ACCEPTED_NAME
= "acceptedName";
119 private static final String ADDENDA
= "addenda";
120 private static final String ALTERNATEPUBTITLE
= "alternatepubtitle";
121 private static final String ALTERNATIVE_COLLECTION_TYPE_STATUS
= "alternativeCollectionTypeStatus";
122 private static final String ALTERNATIVE_COLLECTOR
= "alternativeCollector";
123 private static final String ALTERNATIVE_FIELD_NUM
= "alternativeFieldNum";
124 private static final String ALTITUDE
= "altitude";
125 private static final String ANNOTATION
= "annotation";
126 private static final String AUTHOR
= "author";
127 private static final String BIBLIOGRAPHY
= "bibliography";
128 private static final String BIOGRAPHIES
= "biographies";
129 private static final String BOLD
= "bold";
130 private static final String BR
= "br";
131 private static final String CHAR
= "char";
132 private static final String CITATION
= "citation";
133 private static final String COLLECTION_AND_TYPE
= "collectionAndType";
134 private static final String COLLECTION_TYPE_STATUS
= "collectionTypeStatus";
135 private static final String COLLECTOR
= "collector";
136 private static final String COLLECTION
= "collection";
137 private static final String COORDINATES
= "coordinates";
138 private static final String DATES
= "dates";
139 private static final String DEDICATION
= "dedication";
140 private static final String DEFAULT_MEDIA_URL
= "defaultMediaUrl";
141 private static final String DESTROYED
= "destroyed";
142 private static final String DETAILS
= "details";
143 private static final String DISTRIBUTION_LIST
= "distributionList";
144 private static final String DISTRIBUTION_LOCALITY
= "distributionLocality";
145 private static final String EDITION
= "edition";
146 private static final String EDITORS
= "editors";
147 private static final String FEATURE
= "feature";
148 private static final String FIGURE
= "figure";
149 private static final String FIGURE_LEGEND
= "figureLegend";
150 private static final String FIGURE_PART
= "figurePart";
151 private static final String FIGURE_REF
= "figureRef";
152 private static final String FIGURE_TITLE
= "figureTitle";
153 private static final String FOOTNOTE
= "footnote";
154 private static final String FOOTNOTE_REF
= "footnoteRef";
155 private static final String FOOTNOTE_STRING
= "footnoteString";
156 private static final String FIELD_NUM
= "fieldNum";
157 private static final String FREQUENCY
= "frequency";
158 private static final String FULL_NAME
= "fullName";
159 private static final String FULL_TYPE
= "fullType";
160 private static final String GATHERING
= "gathering";
161 private static final String HEADING
= "heading";
162 private static final String HABITAT
= "habitat";
163 private static final String HABITAT_LIST
= "habitatList";
164 private static final String HOMONYM
= "homonym";
165 private static final String HOMOTYPES
= "homotypes";
166 private static final String ID
= "id";
167 private static final String INFRANK
= "infrank";
168 private static final String INFRAUT
= "infraut";
169 private static final String INFRPARAUT
= "infrparaut";
170 private static final String ISSUE
= "issue";
171 private static final String ITALICS
= "italics";
172 private static final String KEY
= "key";
173 private static final String LIFE_CYCLE_PERIODS
= "lifeCyclePeriods";
174 private static final String LOCALITY
= "locality";
175 private static final String LOST
= "lost";
176 private static final String META_DATA
= "metaData";
177 private static final String NAME
= "name";
178 private static final String NAME_TYPE
= "nameType";
179 private static final String NOM
= "nom";
180 private static final String NOMENCLATURE
= "nomenclature";
181 private static final String NOT_FOUND
= "notFound";
182 private static final String NOT_SEEN
= "notSeen";
183 private static final String NOTES
= "notes";
184 private static final String ORIGINAL_DETERMINATION
= "originalDetermination";
185 private static final String PAGES
= "pages";
186 private static final String PARAUT
= "paraut";
187 private static final String PUBFULLNAME
= "pubfullname";
188 private static final String PUBLICATION
= "publication";
189 private static final String PUBNAME
= "pubname";
190 private static final String PUBTITLE
= "pubtitle";
191 private static final String PUBTYPE
= "pubtype";
192 private static final String QUOTE
= "quote";
193 private static final String RANK
= "rank";
194 private static final String REF
= "ref";
195 private static final String REF_NUM
= "refNum";
196 private static final String REF_PART
= "refPart";
197 private static final String REFERENCE
= "reference";
198 private static final String REFERENCES
= "references";
199 private static final String TAXON
= "taxon";
200 private static final String TAXONTITLE
= "taxontitle";
201 private static final String TAXONTYPE
= "taxontype";
202 private static final String TEXT_SECTION
= "textSection";
203 private static final String TYPE
= "type";
204 private static final String TYPE_STATUS
= "typeStatus";
205 private static final String TREATMENT
= "treatment";
206 private static final String SERIALS_ABBREVIATIONS
= "serialsAbbreviations";
207 private static final String SPECIMEN_TYPE
= "specimenType";
208 private static final String STATUS
= "status";
209 private static final String STRING
= "string";
210 private static final String SUB_HEADING
= "subHeading";
211 private static final String SUB_COLLECTION
= "subCollection";
212 private static final String SYNONYM
= "synonym";
213 private static final String UNKNOWN
= "unknown";
214 private static final String URL
= "url";
215 private static final String USAGE
= "usage";
216 private static final String VOLUME
= "volume";
217 private static final String WRITER
= "writer";
218 private static final String YEAR
= "year";
220 private NonViralNameParserImpl parser
= new NonViralNameParserImpl();
222 // TODO make part of state, but state is renewed when invoking the import a
224 private UnmatchedLeads unmatchedLeads
;
227 private IEditGeoService editGeoService
;
229 private MarkupKeyImport keyImport
;
231 public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport
) {
233 this.editGeoService
= docImport
.getEditGeoService();
234 keyImport
= new MarkupKeyImport(docImport
);
237 public void doInvoke(MarkupImportState state
) throws XMLStreamException
{
238 XMLEventReader reader
= state
.getReader();
240 // publication (= root element)
241 String elName
= PUBLICATION
;
242 boolean hasPublication
= false;
244 while (reader
.hasNext()) {
245 XMLEvent nextEvent
= reader
.nextEvent();
246 if (isStartingElement(nextEvent
, elName
)) {
247 handlePublication(state
, reader
, nextEvent
, elName
);
248 hasPublication
= true;
249 } else if (nextEvent
.isEndDocument()) {
250 if (!hasPublication
) {
251 String message
= "No publication root element found";
252 fireWarningEvent(message
, nextEvent
, 8);
256 fireSchemaConflictEventExpectedStartTag(elName
, reader
);
265 private void handlePublication(MarkupImportState state
, XMLEventReader reader
, XMLEvent currentEvent
, String elName
) throws XMLStreamException
{
268 StartElement element
= currentEvent
.asStartElement();
269 Map
<String
, Attribute
> attributes
= getAttributes(element
);
270 String lang
= getAndRemoveAttributeValue(attributes
, "lang");
272 Language language
= getTermService().getLanguageByIso(lang
);
273 state
.setDefaultLanguage(language
);
276 handleUnexpectedAttributes(element
.getLocation(), attributes
, "noNamespaceSchemaLocation");
278 while (reader
.hasNext()) {
279 XMLEvent event
= readNoWhitespace(reader
);
280 // TODO cardinality of alternative
281 if (event
.isEndElement()) {
282 if (isEndingElement(event
, elName
)) {
285 if (isEndingElement(event
, BIOGRAPHIES
)) {
286 // NOT YET IMPLEMENTED
287 popUnimplemented(event
.asEndElement());
288 } else if (isEndingElement(event
, REFERENCES
)) {
289 // NOT YET IMPLEMENTED
290 popUnimplemented(event
.asEndElement());
291 } else if (isEndingElement(event
, TEXT_SECTION
)) {
292 // NOT YET IMPLEMENTED
293 popUnimplemented(event
.asEndElement());
294 } else if (isEndingElement(event
, ADDENDA
)) {
295 // NOT YET IMPLEMENTED
296 popUnimplemented(event
.asEndElement());
298 handleUnexpectedElement(event
);
301 } else if (event
.isStartElement()) {
302 if (isStartingElement(event
, META_DATA
)) {
303 handleMetaData(state
, reader
, event
);
304 } else if (isStartingElement(event
, TREATMENT
)) {
305 handleTreatment(state
, reader
, event
);
306 } else if (isStartingElement(event
, BIOGRAPHIES
)) {
307 handleNotYetImplementedElement(event
);
308 } else if (isStartingElement(event
, REFERENCES
)) {
309 handleNotYetImplementedElement(event
);
310 } else if (isStartingElement(event
, TEXT_SECTION
)) {
311 handleNotYetImplementedElement(event
);
312 } else if (isStartingElement(event
, ADDENDA
)) {
313 handleNotYetImplementedElement(event
);
315 handleUnexpectedStartElement(event
);
318 handleUnexpectedElement(event
);
321 throw new IllegalStateException("Publication has no ending element");
324 private void handleMetaData(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
325 checkNoAttributes(parentEvent
);
327 while (reader
.hasNext()) {
328 XMLEvent next
= readNoWhitespace(reader
);
329 if (isMyEndingElement(next
, parentEvent
)) {
331 } else if (isStartingElement(next
, DEFAULT_MEDIA_URL
)) {
332 String baseUrl
= getCData(state
, reader
, next
);
335 state
.setBaseMediaUrl(baseUrl
);
336 } catch (MalformedURLException e
) {
337 String message
= "defaultMediaUrl '%s' is not a valid URL";
338 message
= String
.format(message
, baseUrl
);
339 fireWarningEvent(message
, next
, 8);
342 handleUnexpectedElement(next
);
345 throw new IllegalStateException("MetaData has no ending element");
349 private void handleTreatment(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
350 checkNoAttributes(parentEvent
);
351 Taxon lastTaxon
= null;
352 while (reader
.hasNext()) {
353 XMLEvent next
= readNoWhitespace(reader
);
354 if (isStartingElement(next
, TAXON
)) {
355 Taxon thisTaxon
= handleTaxon(state
, reader
, next
.asStartElement());
356 doTaxonRelation(state
, thisTaxon
, lastTaxon
, parentEvent
.getLocation());
357 lastTaxon
= thisTaxon
;
358 // TODO for imports spanning multiple documents ?? Still needed?
359 state
.getConfig().setLastTaxonUuid(lastTaxon
.getUuid());
360 } else if (isMyEndingElement(next
, parentEvent
)) {
361 Set
<PolytomousKeyNode
> keyNodesToSave
= state
.getPolytomousKeyNodesToSave();
362 //better save the key then the nodes
363 Set
<PolytomousKey
> keySet
= new HashSet
<PolytomousKey
>();
364 for (PolytomousKeyNode node
: keyNodesToSave
){
365 PolytomousKey key
= node
.getKey();
369 //unmatched key leads
370 UnmatchedLeads unmatched
= state
.getUnmatchedLeads();
371 if (unmatched
.size() > 0){
372 String message
= "The following key leads are unmatched: %s";
373 message
= String
.format(message
, state
.getUnmatchedLeads().toString());
374 fireWarningEvent(message
, next
, 6);
376 // save(keyNodesToSave, state);
380 handleUnexpectedElement(next
);
390 private void doTaxonRelation(MarkupImportState state
, Taxon taxon
,
391 Taxon lastTaxon
, Location dataLocation
) {
393 Classification tree
= makeTree(state
, dataLocation
);
394 if (lastTaxon
== null) {
395 tree
.addChildTaxon(taxon
, null, null, null);
398 Rank thisRank
= taxon
.getName().getRank();
399 Rank lastRank
= lastTaxon
.getName().getRank();
400 if (lastTaxon
.getTaxonNodes().size() > 0) {
401 TaxonNode lastNode
= lastTaxon
.getTaxonNodes().iterator().next();
402 if (thisRank
== null){
403 String message
= "rank is undefined for taxon '%s'. Can't create classification without rank.";
404 message
= String
.format(message
, taxon
.getName().getTitleCache());
405 fireWarningEvent(message
, makeLocationStr(dataLocation
), 6);
406 }else if (thisRank
.isLower(lastRank
)) {
407 lastNode
.addChildTaxon(taxon
, null, null, null);
408 fillMissingEpithetsForTaxa(lastTaxon
, taxon
);
409 } else if (thisRank
.equals(lastRank
)) {
410 TaxonNode parent
= lastNode
.getParent();
411 if (parent
!= null) {
412 parent
.addChildTaxon(taxon
, null, null, null);
413 fillMissingEpithetsForTaxa(parent
.getTaxon(), taxon
);
415 tree
.addChildTaxon(taxon
, null, null, null);
417 } else if (thisRank
.isHigher(lastRank
)) {
418 doTaxonRelation(state
, taxon
, lastNode
.getParent().getTaxon(), dataLocation
);
419 // TaxonNode parentNode = handleTaxonRelation(state, taxon,
420 // lastNode.getParent().getTaxon());
421 // parentNode.addChildTaxon(taxon, null, null, null);
425 String message
= "Last taxon has no node";
426 fireWarningEvent(message
, makeLocationStr(dataLocation
), 6);
434 * @param dataLocation
437 private Classification
makeTree(MarkupImportState state
, Location dataLocation
) {
438 Classification result
= state
.getTree(null);
439 if (result
== null) {
440 UUID uuid
= state
.getConfig().getClassificationUuid();
442 String message
= "No classification uuid is defined";
443 fireWarningEvent(message
, makeLocationStr(dataLocation
), 6);
444 result
= createNewClassification(state
);
446 result
= getClassificationService().find(uuid
);
447 if (result
== null) {
448 result
= createNewClassification(state
);
449 result
.setUuid(uuid
);
452 state
.putTree(null, result
);
458 private Classification
createNewClassification(MarkupImportState state
) {
459 Classification result
;
460 result
= Classification
.NewInstance(state
.getConfig().getClassificationTitle());
461 state
.putTree(null, result
);
465 private Taxon
handleTaxon(MarkupImportState state
, XMLEventReader reader
, StartElement parentEvent
) throws XMLStreamException
{
466 // TODO progress monitoring
467 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
468 Taxon taxon
= createTaxonAndName(state
, attributes
);
469 state
.setCurrentTaxon(taxon
);
471 boolean hasTitle
= false;
472 boolean hasNomenclature
= false;
473 String taxonTitle
= null;
475 while (reader
.hasNext()) {
476 XMLEvent next
= readNoWhitespace(reader
);
477 if (next
.isEndElement()) {
478 if (isMyEndingElement(next
, parentEvent
)) {
479 checkMandatoryElement(hasTitle
, parentEvent
, TAXONTITLE
);
480 checkMandatoryElement(hasNomenclature
, parentEvent
, NOMENCLATURE
);
481 handleUnexpectedAttributes(parentEvent
.getLocation(),attributes
);
482 if (taxon
.getName().getRank() == null){
483 String warning
= "No rank exists for taxon " + taxon
.getTitleCache();
484 fireWarningEvent(warning
, next
, 12);
487 keyImport
.makeKeyNodes(state
, parentEvent
, taxonTitle
);
488 state
.setCurrentTaxon(null);
489 state
.setCurrentTaxonNum(null);
493 if (isEndingElement(next
, HEADING
)) {
494 // NOT YET IMPLEMENTED
495 popUnimplemented(next
.asEndElement());
496 } else if (isEndingElement(next
, TEXT_SECTION
)) {
497 // NOT YET IMPLEMENTED
498 popUnimplemented(next
.asEndElement());
499 } else if (isEndingElement(next
, REFERENCES
)) {
500 // NOT YET IMPLEMENTED
501 popUnimplemented(next
.asEndElement());
502 } else if (isEndingElement(next
, FIGURE_REF
)) {
503 // NOT YET IMPLEMENTED
504 popUnimplemented(next
.asEndElement());
506 handleUnexpectedEndElement(next
.asEndElement());
509 } else if (next
.isStartElement()) {
510 if (isStartingElement(next
, HEADING
)) {
511 handleNotYetImplementedElement(next
);
512 } else if (isStartingElement(next
, TAXONTITLE
)) {
513 taxonTitle
= handleTaxonTitle(state
, reader
, next
);
515 } else if (isStartingElement(next
, WRITER
)) {
516 makeKeyWriter(state
, reader
, taxon
, taxonTitle
, next
);
517 } else if (isStartingElement(next
, TEXT_SECTION
)) {
518 handleNotYetImplementedElement(next
);
519 } else if (isStartingElement(next
, KEY
)) {
520 keyImport
.handleKey(state
, reader
, next
);
521 } else if (isStartingElement(next
, NOMENCLATURE
)) {
522 handleNomenclature(state
, reader
, next
);
523 hasNomenclature
= true;
524 } else if (isStartingElement(next
, FEATURE
)) {
525 handleFeature(state
, reader
, next
);
526 } else if (isStartingElement(next
, NOTES
)) {
527 // TODO is this the correct way to handle notes?
528 String note
= handleNotes(state
, reader
, next
);
532 notesUuid
= state
.getTransformer().getFeatureUuid(
534 Feature feature
= getFeature(state
, notesUuid
, "Notes",
535 "Notes", "note", null);
536 TextData textData
= TextData
.NewInstance(feature
);
537 textData
.putText(Language
.DEFAULT(), note
);
538 TaxonDescription description
= getTaxonDescription(
539 taxon
, null, false, true);
540 description
.addElement(textData
);
541 } catch (UndefinedTransformerMethodException e
) {
542 String message
= "getFeatureUuid method not yet implemented";
543 fireWarningEvent(message
, next
, 8);
545 } else if (isStartingElement(next
, REFERENCES
)) {
546 handleNotYetImplementedElement(next
);
547 } else if (isStartingElement(next
, FIGURE_REF
)) {
548 handleNotYetImplementedElement(next
);
549 } else if (isStartingElement(next
, FIGURE
)) {
550 handleFigure(state
, reader
, next
);
551 } else if (isStartingElement(next
, FOOTNOTE
)) {
552 FootnoteDataHolder footnote
= handleFootnote(state
, reader
, next
);
553 if (footnote
.isRef()) {
554 String message
= "Ref footnote not implemented here";
555 fireWarningEvent(message
, next
, 4);
557 registerGivenFootnote(state
, footnote
);
560 handleUnexpectedStartElement(next
);
563 handleUnexpectedElement(next
);
566 throw new IllegalStateException("<Taxon> has no closing tag");
575 * @throws XMLStreamException
577 private void makeKeyWriter(MarkupImportState state
, XMLEventReader reader
, Taxon taxon
, String taxonTitle
, XMLEvent next
) throws XMLStreamException
{
578 WriterDataHolder writer
= handleWriter(state
, reader
, next
);
579 taxon
.addExtension(writer
.extension
);
580 // TODO what if taxonTitle comes later
581 if (StringUtils
.isNotBlank(taxonTitle
)
582 && writer
.extension
!= null) {
583 Reference
<?
> sec
= ReferenceFactory
.newBookSection();
584 sec
.setTitle(taxonTitle
);
585 TeamOrPersonBase
<?
> author
= createAuthor(writer
.writer
);
586 sec
.setAuthorTeam(author
);
587 sec
.setInReference(state
.getConfig()
588 .getSourceReference());
590 registerFootnotes(state
, sec
, writer
.footnotes
);
592 String message
= "No taxontitle exists for writer";
593 fireWarningEvent(message
, next
, 6);
597 private String
handleNotes(MarkupImportState state
, XMLEventReader reader
,
598 XMLEvent parentEvent
) throws XMLStreamException
{
599 checkNoAttributes(parentEvent
);
602 while (reader
.hasNext()) {
603 XMLEvent next
= readNoWhitespace(reader
);
604 if (isMyEndingElement(next
, parentEvent
)) {
606 } else if (next
.isEndElement()) {
607 if (isEndingElement(next
, HEADING
)) {
608 popUnimplemented(next
.asEndElement());
609 } else if (isEndingElement(next
, WRITER
)) {
610 popUnimplemented(next
.asEndElement());
611 } else if (isEndingElement(next
, NUM
)) {
612 popUnimplemented(next
.asEndElement());
614 handleUnexpectedEndElement(next
.asEndElement());
616 } else if (next
.isStartElement()) {
617 if (isStartingElement(next
, HEADING
)) {
618 handleNotYetImplementedElement(next
);
619 } else if (isStartingElement(next
, SUB_HEADING
)) {
620 String subheading
= getCData(state
, reader
, next
).trim();
621 if (! isNoteHeading(subheading
)) {
622 fireNotYetImplementedElement(next
.getLocation(), next
.asStartElement().getName(), 0);
624 } else if (isStartingElement(next
, WRITER
)) {
625 handleNotYetImplementedElement(next
);
626 } else if (isStartingElement(next
, NUM
)) {
627 handleNotYetImplementedElement(next
);
628 } else if (isStartingElement(next
, STRING
)) {
629 // TODO why multiple strings in schema?
630 text
= makeNotesString(state
, reader
, text
, next
);
632 handleUnexpectedStartElement(next
.asStartElement());
635 handleUnexpectedElement(next
);
638 throw new IllegalStateException("<Notes> has no closing tag");
647 * @throws XMLStreamException
649 private String
makeNotesString(MarkupImportState state
, XMLEventReader reader
, String text
, XMLEvent next
) throws XMLStreamException
{
650 Map
<String
, String
> stringMap
= handleString(state
, reader
, next
, null);
651 if (stringMap
.size() == 0){
652 String message
= "No text available in <notes>";
653 fireWarningEvent(message
, next
, 4);
654 }else if (stringMap
.size() > 1){
655 String message
= "Subheadings not yet supported in <notes>";
656 fireWarningEvent(message
, next
, 4);
658 String firstSubheading
= stringMap
.keySet().iterator().next();
659 if ( firstSubheading
!= null && ! isNoteHeading (firstSubheading
) ) {
660 String message
= "Subheadings not yet supported in <notes>";
661 fireWarningEvent(message
, next
, 4);
664 for (String subheading
: stringMap
.keySet()){
666 text
+= stringMap
.get(subheading
);
671 private boolean isNoteHeading(String heading
) {
672 String excludePattern
= "(i?)(Notes?):?";
673 return heading
.matches(excludePattern
);
680 private Taxon
createTaxonAndName(MarkupImportState state
,
681 Map
<String
, Attribute
> attributes
) {
682 NonViralName
<?
> name
;
683 Rank rank
= null; //Rank.SPECIES(); // default
684 boolean isCultivar
= checkAndRemoveAttributeValue(attributes
, CLASS
, "cultivated");
686 name
= CultivarPlantName
.NewInstance(rank
);
688 name
= createNameByCode(state
, rank
);
690 Taxon taxon
= Taxon
.NewInstance(name
, state
.getConfig().getSourceReference());
691 if (checkAndRemoveAttributeValue(attributes
, CLASS
, "dubious")) {
692 taxon
.setDoubtful(true);
693 } else if (checkAndRemoveAttributeValue(attributes
, CLASS
, "excluded")) {
694 taxon
.setExcluded(true);
696 // TODO insufficient, new, expected
697 handleNotYetImplementedAttribute(attributes
, CLASS
);
699 // MarkerType markerType = getMarkerType(state, attrValue);
700 // if (markerType == null){
701 // logger.warn("Class attribute value for taxon not yet supported: " +
704 // taxon.addMarker(Marker.NewInstance(markerType, true));
707 // save(name, state);
708 // save(taxon, state);
717 private NonViralName
<?
> createNameByCode(MarkupImportState state
, Rank rank
) {
718 NonViralName
<?
> name
;
719 NomenclaturalCode nc
= makeNomenclaturalCode(state
);
720 name
= (NonViralName
<?
>) nc
.getNewTaxonNameInstance(rank
);
728 private NomenclaturalCode
makeNomenclaturalCode(MarkupImportState state
) {
729 NomenclaturalCode nc
= state
.getConfig().getNomenclaturalCode();
731 nc
= NomenclaturalCode
.ICBN
; // default;
736 private String
handleTaxonTitle(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
739 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
740 String rankAttr
= getAndRemoveAttributeValue(attributes
, RANK
);
741 Rank rank
= makeRank(state
, rankAttr
, false);
742 String num
= getAndRemoveAttributeValue(attributes
, NUM
);
743 state
.setCurrentTaxonNum(num
);
744 checkNoAttributes(attributes
, parentEvent
);
746 // TODO handle attributes
747 while (reader
.hasNext()) {
748 XMLEvent next
= readNoWhitespace(reader
);
749 if (next
.isEndElement()) {
750 if (isMyEndingElement(next
, parentEvent
)) {
751 Taxon taxon
= state
.getCurrentTaxon();
752 String titleText
= null;
753 if (checkMandatoryText(text
, parentEvent
)) {
754 titleText
= normalize(text
);
755 UUID uuidTitle
= MarkupTransformer
.uuidTaxonTitle
;
756 ExtensionType titleExtension
= this.getExtensionType(state
, uuidTitle
, "Taxon Title ","taxon title", "title");
757 taxon
.addExtension(titleText
, titleExtension
);
759 taxon
.getName().setRank(rank
);
760 // TODO check title exists
763 if (isEndingElement(next
, FOOTNOTE
)) {
764 // NOT YET IMPLEMENTED
765 popUnimplemented(next
.asEndElement());
767 handleUnexpectedEndElement(next
.asEndElement());
768 state
.setUnsuccessfull();
771 } else if (next
.isStartElement()) {
772 if (isStartingElement(next
, FOOTNOTE
)) {
773 handleNotYetImplementedElement(next
);
775 handleUnexpectedStartElement(next
);
776 state
.setUnsuccessfull();
778 } else if (next
.isCharacters()) {
779 text
+= next
.asCharacters().getData();
782 handleUnexpectedElement(next
);
783 state
.setUnsuccessfull();
790 private WriterDataHolder
handleWriter(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
792 checkNoAttributes(parentEvent
);
793 WriterDataHolder dataHolder
= new WriterDataHolder();
794 List
<FootnoteDataHolder
> footnotes
= new ArrayList
<FootnoteDataHolder
>();
796 // TODO handle attributes
797 while (reader
.hasNext()) {
798 XMLEvent next
= readNoWhitespace(reader
);
799 if (isMyEndingElement(next
, parentEvent
)) {
800 text
= CdmUtils
.removeBrackets(text
);
801 if (checkMandatoryText(text
, parentEvent
)) {
802 text
= normalize(text
);
803 dataHolder
.writer
= text
;
804 dataHolder
.footnotes
= footnotes
;
807 UUID uuidWriterExtension
= MarkupTransformer
.uuidWriterExtension
;
808 ExtensionType writerExtensionType
= this
809 .getExtensionType(state
, uuidWriterExtension
,
810 "Writer", "writer", "writer");
811 Extension extension
= Extension
.NewInstance();
812 extension
.setType(writerExtensionType
);
813 extension
.setValue(text
);
814 dataHolder
.extension
= extension
;
817 UUID uuidWriterAnnotation
= MarkupTransformer
.uuidWriterAnnotation
;
818 AnnotationType writerAnnotationType
= this.getAnnotationType(state
, uuidWriterAnnotation
, "Writer", "writer", "writer", null);
819 Annotation annotation
= Annotation
.NewInstance(text
, writerAnnotationType
, Language
.DEFAULT());
820 dataHolder
.annotation
= annotation
;
826 } else if (isStartingElement(next
, FOOTNOTE_REF
)) {
827 FootnoteDataHolder footNote
= handleFootnoteRef(state
, reader
, next
);
828 if (footNote
.isRef()) {
829 footnotes
.add(footNote
);
831 logger
.warn("Non ref footnotes not yet impelemnted");
833 } else if (next
.isCharacters()) {
834 text
+= next
.asCharacters().getData();
837 handleUnexpectedElement(next
);
838 state
.setUnsuccessfull();
841 throw new IllegalStateException("<writer> has no end tag");
844 private void registerFootnotes(MarkupImportState state
, AnnotatableEntity entity
, List
<FootnoteDataHolder
> footnotes
) {
845 for (FootnoteDataHolder footNote
: footnotes
) {
846 registerFootnoteDemand(state
, entity
, footNote
);
850 private void registerGivenFootnote(MarkupImportState state
, FootnoteDataHolder footnote
) {
851 state
.registerFootnote(footnote
);
852 Set
<AnnotatableEntity
> demands
= state
.getFootnoteDemands(footnote
.id
);
853 if (demands
!= null) {
854 for (AnnotatableEntity entity
: demands
) {
855 attachFootnote(state
, entity
, footnote
);
860 private void registerGivenFigure(MarkupImportState state
, String id
, Media figure
) {
861 state
.registerFigure(id
, figure
);
862 Set
<AnnotatableEntity
> demands
= state
.getFigureDemands(id
);
863 if (demands
!= null) {
864 for (AnnotatableEntity entity
: demands
) {
865 attachFigure(state
, entity
, figure
);
870 private void registerFootnoteDemand(MarkupImportState state
, AnnotatableEntity entity
, FootnoteDataHolder footnote
) {
871 FootnoteDataHolder existingFootnote
= state
.getFootnote(footnote
.ref
);
872 if (existingFootnote
!= null) {
873 attachFootnote(state
, entity
, existingFootnote
);
875 Set
<AnnotatableEntity
> demands
= state
.getFootnoteDemands(footnote
.ref
);
876 if (demands
== null) {
877 demands
= new HashSet
<AnnotatableEntity
>();
878 state
.putFootnoteDemands(footnote
.ref
, demands
);
884 private void registerFigureDemand(MarkupImportState state
, AnnotatableEntity entity
, String figureRef
) {
885 Media existingFigure
= state
.getFigure(figureRef
);
886 if (existingFigure
!= null) {
887 attachFigure(state
, entity
, existingFigure
);
889 Set
<AnnotatableEntity
> demands
= state
.getFigureDemands(figureRef
);
890 if (demands
== null) {
891 demands
= new HashSet
<AnnotatableEntity
>();
892 state
.putFigureDemands(figureRef
, demands
);
898 private void attachFootnote(MarkupImportState state
, AnnotatableEntity entity
, FootnoteDataHolder footnote
) {
899 AnnotationType annotationType
= this.getAnnotationType(state
, MarkupTransformer
.uuidFootnote
, "Footnote", "An e-flora footnote", "fn", null);
900 Annotation annotation
= Annotation
.NewInstance(footnote
.string
,
901 annotationType
, Language
.DEFAULT());
902 // TODO transient objects
903 entity
.addAnnotation(annotation
);
907 private void attachFigure(MarkupImportState state
,
908 AnnotatableEntity entity
, Media figure
) {
909 // IdentifiableEntity<?> toSave;
910 if (entity
.isInstanceOf(TextData
.class)) {
911 TextData deb
= CdmBase
.deproxy(entity
, TextData
.class);
912 deb
.addMedia(figure
);
913 // toSave = ((TaxonDescription)deb.getInDescription()).getTaxon();
914 } else if (entity
.isInstanceOf(IdentifiableMediaEntity
.class)) {
915 IdentifiableMediaEntity
<?
> ime
= CdmBase
.deproxy(entity
,
916 IdentifiableMediaEntity
.class);
917 ime
.addMedia(figure
);
920 String message
= "Unsupported entity to attach media: %s";
921 message
= String
.format(message
, entity
.getClass().getName());
927 private void handleFigure(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
928 // FigureDataHolder result = new FigureDataHolder();
930 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
931 String id
= getAndRemoveAttributeValue(attributes
, ID
);
932 String type
= getAndRemoveAttributeValue(attributes
, TYPE
);
933 checkNoAttributes(attributes
, parentEvent
);
935 String urlString
= null;
936 String legendString
= null;
937 String titleString
= null;
938 String numString
= null;
940 while (reader
.hasNext()) {
941 XMLEvent next
= readNoWhitespace(reader
);
942 if (isMyEndingElement(next
, parentEvent
)) {
943 makeFigure(state
, id
, type
, urlString
, legendString
, titleString
, numString
, next
);
945 } else if (isStartingElement(next
, FIGURE_LEGEND
)) {
946 // TODO same as figurestring ?
947 legendString
= handleFootnoteString(state
, reader
, next
);
948 } else if (isStartingElement(next
, FIGURE_TITLE
)) {
949 titleString
= getCData(state
, reader
, next
);
950 } else if (isStartingElement(next
, URL
)) {
951 String localUrl
= getCData(state
, reader
, next
);
952 urlString
= CdmUtils
.Nz(state
.getBaseMediaUrl()) + localUrl
;
953 } else if (isStartingElement(next
, NUM
)) {
954 numString
= getCData(state
, reader
, next
);
955 } else if (next
.isCharacters()) {
956 text
+= next
.asCharacters().getData();
958 fireUnexpectedEvent(next
, 0);
961 throw new IllegalStateException("<figure> has no end tag");
969 * @param legendString
974 private void makeFigure(MarkupImportState state
, String id
, String type
, String urlString
,
975 String legendString
, String titleString
, String numString
, XMLEvent next
) {
977 boolean isFigure
= false;
979 //TODO maybe everything is a figure as it is all taken from a book
980 if ("lineart".equals(type
)) {
982 // media = Figure.NewInstance(url.toURI(), null, null, null);
983 } else if (type
== null || "photo".equals(type
)
984 || "signature".equals(type
)
985 || "others".equals(type
)) {
987 String message
= "Unknown figure type '%s'";
988 message
= String
.format(message
, type
);
989 fireWarningEvent(message
, next
, 2);
991 media
= docImport
.getImageMedia(urlString
, docImport
.getReadMediaData(), isFigure
);
995 if (StringUtils
.isNotBlank(titleString
)) {
996 media
.putTitle(Language
.DEFAULT(), titleString
);
999 if (StringUtils
.isNotBlank(legendString
)) {
1000 media
.addDescription(legendString
, Language
.DEFAULT());
1002 if (StringUtils
.isNotBlank(numString
)) {
1003 // TODO use concrete source (e.g. DAPHNIPHYLLACEAE in FM
1005 Reference
<?
> citation
= state
.getConfig().getSourceReference();
1006 media
.addSource(numString
, "num", citation
, null);
1007 // TODO name used in source if available
1009 // TODO which citation
1010 if (StringUtils
.isNotBlank(id
)) {
1011 media
.addSource(id
, null, state
.getConfig().getSourceReference(), null);
1013 String message
= "Figure id should never be empty or null";
1014 fireWarningEvent(message
, next
, 6);
1021 } catch (MalformedURLException e
) {
1022 String message
= "Media uri has incorrect syntax: %s";
1023 message
= String
.format(message
, urlString
);
1024 fireWarningEvent(message
, next
, 4);
1025 // } catch (URISyntaxException e) {
1026 // String message = "Media uri has incorrect syntax: %s";
1027 // message = String.format(message, urlString);
1028 // fireWarningEvent(message, next, 4);
1031 registerGivenFigure(state
, id
, media
);
1034 private FigureDataHolder
handleFigureRef(MarkupImportState state
,
1035 XMLEventReader reader
, XMLEvent parentEvent
)
1036 throws XMLStreamException
{
1037 FigureDataHolder result
= new FigureDataHolder();
1038 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1039 result
.ref
= getAndRemoveAttributeValue(attributes
, REF
);
1040 checkNoAttributes(attributes
, parentEvent
);
1042 // text is not handled, needed only for debugging purposes
1044 while (reader
.hasNext()) {
1045 XMLEvent next
= readNoWhitespace(reader
);
1046 if (isMyEndingElement(next
, parentEvent
)) {
1048 } else if (isStartingElement(next
, NUM
)) {
1049 String num
= getCData(state
, reader
, next
);
1050 result
.num
= num
; // num is not handled during import
1051 } else if (isStartingElement(next
, FIGURE_PART
)) {
1052 result
.figurePart
= getCData(state
, reader
, next
);
1053 } else if (next
.isCharacters()) {
1054 text
+= next
.asCharacters().getData();
1056 fireUnexpectedEvent(next
, 0);
1059 throw new IllegalStateException("<figureRef> has no end tag");
1062 private FootnoteDataHolder
handleFootnote(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1063 FootnoteDataHolder result
= new FootnoteDataHolder();
1064 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1065 result
.id
= getAndRemoveAttributeValue(attributes
, ID
);
1066 // result.ref = getAndRemoveAttributeValue(attributes, REF);
1067 checkNoAttributes(attributes
, parentEvent
);
1069 while (reader
.hasNext()) {
1070 XMLEvent next
= readNoWhitespace(reader
);
1071 if (isStartingElement(next
, FOOTNOTE_STRING
)) {
1072 String string
= handleFootnoteString(state
, reader
, next
);
1073 result
.string
= string
;
1074 } else if (isMyEndingElement(next
, parentEvent
)) {
1077 fireUnexpectedEvent(next
, 0);
1083 private FootnoteDataHolder
handleFootnoteRef(MarkupImportState state
,
1084 XMLEventReader reader
, XMLEvent parentEvent
)
1085 throws XMLStreamException
{
1086 FootnoteDataHolder result
= new FootnoteDataHolder();
1087 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1088 result
.ref
= getAndRemoveAttributeValue(attributes
, REF
);
1089 checkNoAttributes(attributes
, parentEvent
);
1091 // text is not handled, needed only for debugging purposes
1093 while (reader
.hasNext()) {
1094 XMLEvent next
= readNoWhitespace(reader
);
1095 // if (isStartingElement(next, FOOTNOTE_STRING)){
1096 // String string = handleFootnoteString(state, reader, next);
1097 // result.string = string;
1099 if (isMyEndingElement(next
, parentEvent
)) {
1101 } else if (next
.isCharacters()) {
1102 text
+= next
.asCharacters().getData();
1105 fireUnexpectedEvent(next
, 0);
1111 private void handleNomenclature(MarkupImportState state
,
1112 XMLEventReader reader
, XMLEvent parentEvent
)
1113 throws XMLStreamException
{
1114 checkNoAttributes(parentEvent
);
1116 while (reader
.hasNext()) {
1117 XMLEvent next
= readNoWhitespace(reader
);
1118 if (isStartingElement(next
, HOMOTYPES
)) {
1119 handleHomotypes(state
, reader
, next
.asStartElement());
1120 } else if (isMyEndingElement(next
, parentEvent
)) {
1123 fireSchemaConflictEventExpectedStartTag(HOMOTYPES
, reader
);
1124 state
.setUnsuccessfull();
1130 private String
handleFootnoteString(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1131 boolean isTextMode
= true;
1133 while (reader
.hasNext()) {
1134 XMLEvent next
= readNoWhitespace(reader
);
1135 if (isMyEndingElement(next
, parentEvent
)) {
1137 } else if (next
.isEndElement()) {
1138 if (isEndingElement(next
, FULL_NAME
)) {
1139 popUnimplemented(next
.asEndElement());
1140 } else if (isEndingElement(next
, BR
)) {
1142 } else if (isHtml(next
)) {
1143 text
+= getXmlTag(next
);
1145 handleUnexpectedEndElement(next
.asEndElement());
1147 } else if (next
.isStartElement()) {
1148 if (isStartingElement(next
, FULL_NAME
)) {
1149 handleNotYetImplementedElement(next
);
1150 } else if (isStartingElement(next
, GATHERING
)) {
1151 text
+= handleInLineGathering(state
, reader
, next
);
1152 } else if (isStartingElement(next
, REFERENCES
)) {
1153 text
+= " " + handleInLineReferences(state
, reader
, next
)+ " ";
1154 } else if (isStartingElement(next
, BR
)) {
1157 } else if (isHtml(next
)) {
1158 text
+= getXmlTag(next
);
1160 handleUnexpectedStartElement(next
.asStartElement());
1162 } else if (next
.isCharacters()) {
1164 String message
= "footnoteString is not in text mode";
1165 fireWarningEvent(message
, next
, 6);
1167 text
+= next
.asCharacters().getData().trim();
1168 // getCData(state, reader, next); does not work as we have inner tags like <references>
1171 handleUnexpectedEndElement(next
.asEndElement());
1174 throw new IllegalStateException("<footnoteString> has no closing tag");
1178 private String
handleInLineGathering(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1179 DerivedUnitFacade facade
= DerivedUnitFacade
.NewInstance(DerivedUnitType
.DerivedUnit
.FieldObservation
);
1180 handleGathering(state
, reader
, parentEvent
, facade
);
1181 FieldObservation fieldObservation
= facade
.innerFieldObservation();
1182 String result
= "<cdm:specimen uuid='%s'>%s</specimen>";
1183 result
= String
.format(result
, fieldObservation
.getUuid(), fieldObservation
.getTitleCache());
1184 save(fieldObservation
, state
);
1188 private String
handleInLineReferences(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1189 checkNoAttributes(parentEvent
);
1191 boolean hasReference
= false;
1193 while (reader
.hasNext()) {
1194 XMLEvent next
= readNoWhitespace(reader
);
1195 if (isMyEndingElement(next
, parentEvent
)) {
1196 checkMandatoryElement(hasReference
, parentEvent
.asStartElement(), REFERENCE
);
1198 } else if (isStartingElement(next
, REFERENCE
)) {
1199 text
+= handleInLineReference(state
, reader
, next
);
1200 hasReference
= true;
1202 handleUnexpectedElement(next
);
1205 throw new IllegalStateException("<References> has no closing tag");
1208 private String
handleInLineReference(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
)throws XMLStreamException
{
1209 Reference
<?
> reference
= handleReference(state
, reader
, parentEvent
);
1210 String result
= "<cdm:ref uuid='%s'>%s</ref>";
1211 result
= String
.format(result
, reference
.getUuid(), reference
.getTitleCache());
1212 save(reference
, state
);
1216 private Reference
<?
> handleReference(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
)throws XMLStreamException
{
1217 checkNoAttributes(parentEvent
);
1219 boolean hasRefPart
= false;
1220 Map
<String
, String
> refMap
= new HashMap
<String
, String
>();
1221 while (reader
.hasNext()) {
1222 XMLEvent next
= readNoWhitespace(reader
);
1223 if (isMyEndingElement(next
, parentEvent
)) {
1224 checkMandatoryElement(hasRefPart
, parentEvent
.asStartElement(),
1226 Reference
<?
> reference
= createReference(state
, refMap
, next
);
1228 } else if (isStartingElement(next
, REF_PART
)) {
1229 handleRefPart(state
, reader
, next
, refMap
);
1232 handleUnexpectedElement(next
);
1235 // TODO handle missing end element
1236 throw new IllegalStateException("<Reference> has no closing tag");
1239 private void handleHomotypes(MarkupImportState state
, XMLEventReader reader
, StartElement parentEvent
)
1240 throws XMLStreamException
{
1241 checkNoAttributes(parentEvent
);
1243 HomotypicalGroup homotypicalGroup
= null;
1245 boolean hasNom
= false;
1246 while (reader
.hasNext()) {
1247 XMLEvent next
= readNoWhitespace(reader
);
1248 if (next
.isEndElement()) {
1249 if (isMyEndingElement(next
, parentEvent
)) {
1250 checkMandatoryElement(hasNom
, parentEvent
, NOM
);
1253 if (isEndingElement(next
, NAME_TYPE
)) {
1254 state
.setNameType(false);
1255 } else if (isEndingElement(next
, NOTES
)) {
1256 // NOT YET IMPLEMENTED
1257 popUnimplemented(next
.asEndElement());
1259 handleUnexpectedEndElement(next
.asEndElement());
1262 } else if (next
.isStartElement()) {
1263 if (isStartingElement(next
, NOM
)) {
1264 NonViralName
<?
> name
= handleNom(state
, reader
, next
, homotypicalGroup
);
1265 homotypicalGroup
= name
.getHomotypicalGroup();
1267 } else if (isStartingElement(next
, NAME_TYPE
)) {
1268 state
.setNameType(true);
1269 handleNameType(state
, reader
, next
, homotypicalGroup
);
1270 } else if (isStartingElement(next
, SPECIMEN_TYPE
)) {
1271 handleSpecimenType(state
, reader
, next
, homotypicalGroup
);
1272 } else if (isStartingElement(next
, NOTES
)) {
1273 handleNotYetImplementedElement(next
);
1275 handleUnexpectedStartElement(next
);
1278 handleUnexpectedElement(next
);
1281 // TODO handle missing end element
1282 throw new IllegalStateException("Homotypes has no closing tag");
1286 private void handleNameType(MarkupImportState state
, XMLEventReader reader
,
1287 XMLEvent parentEvent
, HomotypicalGroup homotypicalGroup
)
1288 throws XMLStreamException
{
1289 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1290 String typeStatus
= getAndRemoveAttributeValue(attributes
, TYPE_STATUS
);
1291 checkNoAttributes(attributes
, parentEvent
);
1293 NameTypeDesignationStatus status
;
1295 status
= NameTypeParser
.parseNameTypeStatus(typeStatus
);
1296 } catch (UnknownCdmTypeException e
) {
1297 String message
= "Type status could not be recognized: %s";
1298 message
= String
.format(message
, typeStatus
);
1299 fireWarningEvent(message
, parentEvent
, 4);
1303 boolean hasNom
= false;
1304 while (reader
.hasNext()) {
1305 XMLEvent next
= readNoWhitespace(reader
);
1306 if (next
.isEndElement()) {
1307 if (isMyEndingElement(next
, parentEvent
)) {
1308 checkMandatoryElement(hasNom
, parentEvent
.asStartElement(),
1310 state
.setNameType(false);
1313 if (isEndingElement(next
, ACCEPTED_NAME
)) {
1314 // NOT YET IMPLEMENTED
1315 popUnimplemented(next
.asEndElement());
1317 handleUnexpectedEndElement(next
.asEndElement());
1320 } else if (next
.isStartElement()) {
1321 if (isStartingElement(next
, NOM
)) {
1322 // TODO should we check if the type is always a species, is
1324 NonViralName
<?
> speciesName
= handleNom(state
, reader
,
1326 for (TaxonNameBase
<?
, ?
> name
: homotypicalGroup
1327 .getTypifiedNames()) {
1328 name
.addNameTypeDesignation(speciesName
, null, null,
1329 null, status
, false, false, false, false);
1332 } else if (isStartingElement(next
, ACCEPTED_NAME
)) {
1333 handleNotYetImplementedElement(next
);
1335 handleUnexpectedStartElement(next
);
1338 handleUnexpectedElement(next
);
1341 // TODO handle missing end element
1342 throw new IllegalStateException("Homotypes has no closing tag");
1346 private void handleSpecimenType(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
,
1347 HomotypicalGroup homotypicalGroup
) throws XMLStreamException
{
1349 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1350 String typeStatus
= getAndRemoveAttributeValue(attributes
, TYPE_STATUS
);
1351 String notSeen
= getAndRemoveAttributeValue(attributes
, NOT_SEEN
);
1352 String unknown
= getAndRemoveAttributeValue(attributes
, UNKNOWN
);
1353 String notFound
= getAndRemoveAttributeValue(attributes
, NOT_FOUND
);
1354 String destroyed
= getAndRemoveAttributeValue(attributes
, DESTROYED
);
1355 String lost
= getAndRemoveAttributeValue(attributes
, LOST
);
1356 checkNoAttributes(attributes
, parentEvent
);
1357 if (StringUtils
.isNotEmpty(typeStatus
)) {
1359 // currently not needed
1360 } else if (StringUtils
.isNotEmpty(notSeen
)) {
1361 handleNotYetImplementedAttribute(attributes
, NOT_SEEN
);
1362 } else if (StringUtils
.isNotEmpty(unknown
)) {
1363 handleNotYetImplementedAttribute(attributes
, UNKNOWN
);
1364 } else if (StringUtils
.isNotEmpty(notFound
)) {
1365 handleNotYetImplementedAttribute(attributes
, NOT_FOUND
);
1366 } else if (StringUtils
.isNotEmpty(destroyed
)) {
1367 handleNotYetImplementedAttribute(attributes
, DESTROYED
);
1368 } else if (StringUtils
.isNotEmpty(lost
)) {
1369 handleNotYetImplementedAttribute(attributes
, LOST
);
1372 NonViralName
<?
> firstName
= null;
1373 Set
<TaxonNameBase
> names
= homotypicalGroup
.getTypifiedNames();
1374 if (names
.isEmpty()) {
1375 String message
= "There is no name in a homotypical group. Can't create the specimen type";
1376 fireWarningEvent(message
, parentEvent
, 8);
1378 firstName
= CdmBase
.deproxy(names
.iterator().next(),NonViralName
.class);
1381 DerivedUnitFacade facade
= DerivedUnitFacade
.NewInstance(DerivedUnitType
.Specimen
);
1384 while (reader
.hasNext()) {
1385 XMLEvent next
= readNoWhitespace(reader
);
1386 if (next
.isEndElement()) {
1387 if (isMyEndingElement(next
, parentEvent
)) {
1388 makeSpecimenType(state
, facade
, text
, firstName
, parentEvent
);
1391 if (isEndingElement(next
, FULL_TYPE
)) {
1392 // NOT YET IMPLEMENTED
1393 popUnimplemented(next
.asEndElement());
1394 } else if (isEndingElement(next
, TYPE_STATUS
)) {
1395 // NOT YET IMPLEMENTED
1396 popUnimplemented(next
.asEndElement());
1397 } else if (isEndingElement(next
, ORIGINAL_DETERMINATION
)) {
1398 // NOT YET IMPLEMENTED
1399 popUnimplemented(next
.asEndElement());
1400 } else if (isEndingElement(next
, SPECIMEN_TYPE
)) {
1401 // NOT YET IMPLEMENTED
1402 popUnimplemented(next
.asEndElement());
1403 } else if (isEndingElement(next
, COLLECTION_AND_TYPE
)) {
1404 // NOT YET IMPLEMENTED
1405 popUnimplemented(next
.asEndElement());
1406 } else if (isEndingElement(next
, CITATION
)) {
1407 // NOT YET IMPLEMENTED
1408 popUnimplemented(next
.asEndElement());
1409 } else if (isEndingElement(next
, NOTES
)) {
1410 // NOT YET IMPLEMENTED
1411 popUnimplemented(next
.asEndElement());
1412 } else if (isEndingElement(next
, ANNOTATION
)) {
1413 // NOT YET IMPLEMENTED
1414 popUnimplemented(next
.asEndElement());
1416 handleUnexpectedEndElement(next
.asEndElement());
1419 } else if (next
.isStartElement()) {
1420 if (isStartingElement(next
, FULL_TYPE
)) {
1421 handleNotYetImplementedElement(next
);
1422 // homotypicalGroup = handleNom(state, reader, next, taxon,
1423 // homotypicalGroup);
1424 } else if (isStartingElement(next
, TYPE_STATUS
)) {
1425 handleNotYetImplementedElement(next
);
1426 } else if (isStartingElement(next
, GATHERING
)) {
1427 handleGathering(state
, reader
, next
, facade
);
1428 } else if (isStartingElement(next
, ORIGINAL_DETERMINATION
)) {
1429 handleNotYetImplementedElement(next
);
1430 } else if (isStartingElement(next
, SPECIMEN_TYPE
)) {
1431 handleNotYetImplementedElement(next
);
1432 } else if (isStartingElement(next
, COLLECTION_AND_TYPE
)) {
1433 handleNotYetImplementedElement(next
);
1434 } else if (isStartingElement(next
, CITATION
)) {
1435 handleNotYetImplementedElement(next
);
1436 } else if (isStartingElement(next
, NOTES
)) {
1437 handleNotYetImplementedElement(next
);
1438 } else if (isStartingElement(next
, ANNOTATION
)) {
1439 handleNotYetImplementedElement(next
);
1441 handleUnexpectedStartElement(next
);
1443 } else if (next
.isCharacters()) {
1444 text
+= next
.asCharacters().getData();
1446 handleUnexpectedElement(next
);
1449 // TODO handle missing end element
1450 throw new IllegalStateException("Specimen type has no closing tag");
1453 private void makeSpecimenType(MarkupImportState state
, DerivedUnitFacade facade
, String text
,
1454 NonViralName name
, XMLEvent parentEvent
) {
1457 if (text
.matches("^\\(.*\\)\\.?$")) {
1458 text
= text
.replaceAll("\\.", "");
1459 text
= text
.substring(1, text
.length() - 1);
1461 String
[] split
= text
.split("[;,]");
1462 for (String str
: split
) {
1464 boolean addToAllNamesInGroup
= true;
1465 TypeInfo typeInfo
= makeSpecimenTypeTypeInfo(str
, parentEvent
);
1466 SpecimenTypeDesignationStatus typeStatus
= typeInfo
.status
;
1467 Collection collection
= createCollection(typeInfo
.collectionString
);
1469 // TODO improve cache strategy handling
1470 DerivedUnitBase typeSpecimen
= facade
.addDuplicate(collection
,
1471 null, null, null, null);
1472 typeSpecimen
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
1473 name
.addSpecimenTypeDesignation((Specimen
) typeSpecimen
, typeStatus
, null, null, null, false, addToAllNamesInGroup
);
1477 private Collection
createCollection(String code
) {
1479 // TODO code <-> name
1480 Collection result
= Collection
.NewInstance();
1481 result
.setCode(code
);
1485 private TypeInfo
makeSpecimenTypeTypeInfo(String originalString
, XMLEvent event
) {
1486 TypeInfo result
= new TypeInfo();
1487 String
[] split
= originalString
.split("\\s+");
1488 for (String str
: split
) {
1489 if (str
.matches(SpecimenTypeParser
.typeTypePattern
)) {
1490 SpecimenTypeDesignationStatus status
;
1492 status
= SpecimenTypeParser
.parseSpecimenTypeStatus(str
);
1493 } catch (UnknownCdmTypeException e
) {
1494 String message
= "Specimen type status '%s' not recognized by parser";
1495 message
= String
.format(message
, str
);
1496 fireWarningEvent(message
, event
, 4);
1499 result
.status
= status
;
1500 } else if (str
.matches(SpecimenTypeParser
.collectionPattern
)) {
1501 result
.collectionString
= str
;
1503 String message
= "Type part '%s' could not be recognized";
1504 message
= String
.format(message
, str
);
1505 fireWarningEvent(message
, event
, 2);
1513 private void handleGathering(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
, DerivedUnitFacade facade
) throws XMLStreamException
{
1514 checkNoAttributes(parentEvent
);
1515 boolean hasCollector
= false;
1516 boolean hasFieldNum
= false;
1519 while (reader
.hasNext()) {
1520 XMLEvent next
= readNoWhitespace(reader
);
1521 if (next
.isEndElement()) {
1522 if (isMyEndingElement(next
, parentEvent
)) {
1523 checkMandatoryElement(hasCollector
,parentEvent
.asStartElement(), COLLECTOR
);
1524 checkMandatoryElement(hasFieldNum
,parentEvent
.asStartElement(), FIELD_NUM
);
1527 if (isEndingElement(next
, ALTERNATIVE_COLLECTOR
)) {
1528 // NOT YET IMPLEMENTED
1529 popUnimplemented(next
.asEndElement());
1530 } else if (isEndingElement(next
, ALTERNATIVE_FIELD_NUM
)) {
1531 // NOT YET IMPLEMENTED
1532 popUnimplemented(next
.asEndElement());
1533 } else if (isEndingElement(next
, COLLECTION_TYPE_STATUS
)) {
1534 // NOT YET IMPLEMENTED
1535 popUnimplemented(next
.asEndElement());
1536 } else if (isEndingElement(next
, COLLECTION_AND_TYPE
)) {
1537 // NOT YET IMPLEMENTED , does this make sense here?
1538 popUnimplemented(next
.asEndElement());
1539 } else if (isEndingElement(next
,
1540 ALTERNATIVE_COLLECTION_TYPE_STATUS
)) {
1541 // NOT YET IMPLEMENTED
1542 popUnimplemented(next
.asEndElement());
1543 } else if (isEndingElement(next
, SUB_COLLECTION
)) {
1544 // NOT YET IMPLEMENTED
1545 popUnimplemented(next
.asEndElement());
1546 } else if (isEndingElement(next
, COLLECTION
)) {
1547 // NOT YET IMPLEMENTED
1548 popUnimplemented(next
.asEndElement());
1549 } else if (isEndingElement(next
, DATES
)) {
1550 // NOT YET IMPLEMENTED
1551 popUnimplemented(next
.asEndElement());
1552 } else if (isEndingElement(next
, NOTES
)) {
1553 // NOT YET IMPLEMENTED
1554 popUnimplemented(next
.asEndElement());
1556 handleUnexpectedEndElement(next
.asEndElement());
1559 } else if (next
.isStartElement()) {
1560 if (isStartingElement(next
, COLLECTOR
)) {
1561 hasCollector
= true;
1562 String collectorStr
= getCData(state
, reader
, next
);
1563 AgentBase
<?
> collector
= createCollector(collectorStr
);
1564 facade
.setCollector(collector
);
1565 } else if (isStartingElement(next
, ALTERNATIVE_COLLECTOR
)) {
1566 handleNotYetImplementedElement(next
);
1567 } else if (isStartingElement(next
, FIELD_NUM
)) {
1569 String fieldNumStr
= getCData(state
, reader
, next
);
1570 facade
.setFieldNumber(fieldNumStr
);
1571 } else if (isStartingElement(next
, ALTERNATIVE_FIELD_NUM
)) {
1572 handleNotYetImplementedElement(next
);
1573 } else if (isStartingElement(next
, COLLECTION_TYPE_STATUS
)) {
1574 handleNotYetImplementedElement(next
);
1575 } else if (isStartingElement(next
, COLLECTION_AND_TYPE
)) { //does this make sense here?
1576 handleNotYetImplementedElement(next
);
1577 } else if (isStartingElement(next
, ALTERNATIVE_COLLECTION_TYPE_STATUS
)) {
1578 handleNotYetImplementedElement(next
);
1579 } else if (isStartingElement(next
, SUB_COLLECTION
)) {
1580 handleNotYetImplementedElement(next
);
1581 } else if (isStartingElement(next
, COLLECTION
)) {
1582 handleNotYetImplementedElement(next
);
1583 } else if (isStartingElement(next
, LOCALITY
)) {
1584 handleLocality(state
, reader
, next
, facade
);
1585 } else if (isStartingElement(next
, DATES
)) {
1586 handleNotYetImplementedElement(next
);
1587 } else if (isStartingElement(next
, NOTES
)) {
1588 handleNotYetImplementedElement(next
);
1590 handleUnexpectedStartElement(next
);
1593 handleUnexpectedElement(next
);
1596 // TODO handle missing end element
1597 throw new IllegalStateException("Collection has no closing tag");
1601 private void handleLocality(MarkupImportState state
, XMLEventReader reader
,XMLEvent parentEvent
, DerivedUnitFacade facade
)throws XMLStreamException
{
1602 String classValue
= getClassOnlyAttribute(parentEvent
);
1603 boolean isLocality
= false;
1604 NamedAreaLevel areaLevel
= null;
1605 if ("locality".equalsIgnoreCase(classValue
)) {
1608 areaLevel
= makeNamedAreaLevel(state
, classValue
, parentEvent
);
1613 while (reader
.hasNext()) {
1614 XMLEvent next
= readNoWhitespace(reader
);
1615 if (next
.isEndElement()) {
1616 if (isMyEndingElement(next
, parentEvent
)) {
1617 if (StringUtils
.isNotBlank(text
)) {
1618 text
= normalize(text
);
1620 facade
.setLocality(text
);
1622 text
= CdmUtils
.removeTrailingDot(text
);
1623 NamedArea area
= makeArea(state
, text
, areaLevel
);
1624 facade
.addCollectingArea(area
);
1630 if (isEndingElement(next
, ALTITUDE
)) {
1631 // NOT YET IMPLEMENTED
1632 popUnimplemented(next
.asEndElement());
1633 } else if (isEndingElement(next
, COORDINATES
)) {
1634 // NOT YET IMPLEMENTED
1635 popUnimplemented(next
.asEndElement());
1636 } else if (isEndingElement(next
, ANNOTATION
)) {
1637 // NOT YET IMPLEMENTED
1638 popUnimplemented(next
.asEndElement());
1640 handleUnexpectedEndElement(next
.asEndElement());
1643 } else if (next
.isStartElement()) {
1644 if (isStartingElement(next
, ALTITUDE
)) {
1645 handleNotYetImplementedElement(next
);
1646 // homotypicalGroup = handleNom(state, reader, next, taxon,
1647 // homotypicalGroup);
1648 } else if (isStartingElement(next
, COORDINATES
)) {
1649 handleNotYetImplementedElement(next
);
1650 } else if (isStartingElement(next
, ANNOTATION
)) {
1651 handleNotYetImplementedElement(next
);
1653 handleUnexpectedStartElement(next
);
1655 } else if (next
.isCharacters()) {
1656 text
+= next
.asCharacters().getData();
1658 handleUnexpectedElement(next
);
1661 throw new IllegalStateException("<SpecimenType> has no closing tag");
1664 // private NamedArea createArea(String text, NamedAreaLevel areaLevel, MarkupImportState state) {
1665 // NamedArea area = NamedArea.NewInstance(text, text, null);
1666 // area.setLevel(areaLevel);
1667 // save(area, state);
1671 private AgentBase
<?
> createCollector(String collectorStr
) {
1672 return createAuthor(collectorStr
);
1676 * Creates the name defined by a nom tag. Adds it to the given homotypical
1677 * group (if not null).
1681 * @param parentEvent
1682 * @param homotypicalGroup
1684 * @throws XMLStreamException
1686 private NonViralName
<?
> handleNom(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
,
1687 HomotypicalGroup homotypicalGroup
) throws XMLStreamException
{
1688 boolean isSynonym
= false;
1689 boolean isNameType
= state
.isNameType();
1691 String classValue
= getClassOnlyAttribute(parentEvent
);
1692 NonViralName
<?
> name
;
1693 if (!isNameType
&& ACCEPTED
.equalsIgnoreCase(classValue
)) {
1695 name
= createName(state
, homotypicalGroup
, isSynonym
);
1696 } else if (!isNameType
&& SYNONYM
.equalsIgnoreCase(classValue
)) {
1698 name
= createName(state
, homotypicalGroup
, isSynonym
);
1699 } else if (isNameType
&& NAME_TYPE
.equalsIgnoreCase(classValue
)) {
1700 // TODO do we need to define the rank here?
1701 name
= createNameByCode(state
, null);
1703 fireUnexpectedAttributeValue(parentEvent
, CLASS
, classValue
);
1704 name
= createNameByCode(state
, null);
1707 Map
<String
, String
> nameMap
= new HashMap
<String
, String
>();
1709 while (reader
.hasNext()) {
1710 XMLEvent next
= readNoWhitespace(reader
);
1711 if (next
.isEndElement()) {
1712 if (isMyEndingElement(next
, parentEvent
)) {
1713 // fill the name with all data gathered
1714 fillName(state
, nameMap
, name
, next
);
1717 if (isEndingElement(next
, FULL_NAME
)) {
1718 // NOT YET IMPLEMENTED
1719 popUnimplemented(next
.asEndElement());
1720 } else if (isEndingElement(next
, HOMONYM
)) {
1721 // NOT YET IMPLEMENTED
1722 popUnimplemented(next
.asEndElement());
1723 } else if (isEndingElement(next
, NOTES
)) {
1724 // NOT YET IMPLEMENTED
1725 popUnimplemented(next
.asEndElement());
1726 } else if (isEndingElement(next
, ANNOTATION
)) {
1727 // NOT YET IMPLEMENTED
1728 popUnimplemented(next
.asEndElement());
1730 handleUnexpectedEndElement(next
.asEndElement());
1733 } else if (next
.isStartElement()) {
1734 if (isStartingElement(next
, FULL_NAME
)) {
1735 handleNotYetImplementedElement(next
);
1736 // homotypicalGroup = handleNom(state, reader, next, taxon,
1737 // homotypicalGroup);
1738 } else if (isStartingElement(next
, NUM
)) {
1739 String num
= getCData(state
, reader
, next
);
1740 num
= num
.replace(".", "");
1741 num
= num
.replace(")", "");
1742 if (StringUtils
.isNotBlank(num
)){
1743 if (state
.getCurrentTaxonNum() != null && ! state
.getCurrentTaxonNum().equals(num
) ){
1744 String message
= "Taxontitle num and homotypes/nom/num differ ( %s <-> %s ). I use the later one.";
1745 message
= String
.format(message
, state
.getCurrentTaxonNum(), num
);
1746 fireWarningEvent(message
, next
, 4);
1748 state
.setCurrentTaxonNum(num
);
1750 } else if (isStartingElement(next
, NAME
)) {
1751 handleName(state
, reader
, next
, nameMap
);
1752 } else if (isStartingElement(next
, CITATION
)) {
1753 handleCitation(state
, reader
, next
, name
);
1754 } else if (isStartingElement(next
, HOMONYM
)) {
1755 handleNotYetImplementedElement(next
);
1756 } else if (isStartingElement(next
, NOTES
)) {
1757 handleNotYetImplementedElement(next
);
1758 } else if (isStartingElement(next
, ANNOTATION
)) {
1759 handleNotYetImplementedElement(next
);
1761 handleUnexpectedStartElement(next
);
1764 handleUnexpectedElement(next
);
1767 // TODO handle missing end element
1768 throw new IllegalStateException("Nom has no closing tag");
1772 private void fillName(MarkupImportState state
, Map
<String
, String
> nameMap
,
1773 NonViralName name
, XMLEvent event
) {
1775 // Ranks: family, subfamily, tribus, genus, subgenus, section,
1776 // subsection, species, subspecies, variety, subvariety, forma
1777 // infrank, paraut, author, infrparaut, infraut, status, notes
1779 String infrank
= getAndRemoveMapKey(nameMap
, INFRANK
);
1780 String authorStr
= getAndRemoveMapKey(nameMap
, AUTHOR
);
1781 String paraut
= getAndRemoveMapKey(nameMap
, PARAUT
);
1783 String infrParAut
= getAndRemoveMapKey(nameMap
, INFRPARAUT
);
1784 String infrAut
= getAndRemoveMapKey(nameMap
, INFRAUT
);
1786 String statusStr
= getAndRemoveMapKey(nameMap
, STATUS
);
1787 String notes
= getAndRemoveMapKey(nameMap
, NOTES
);
1789 makeRankDecision(state
, nameMap
, name
, event
, infrank
);
1791 // test consistency of rank and authors
1792 testRankAuthorConsistency(name
, event
, authorStr
, paraut
, infrParAut
,infrAut
);
1795 makeNomenclaturalAuthors(name
, event
, authorStr
, paraut
, infrParAut
,infrAut
);
1798 // TODO handle pro parte, pro syn. etc.
1799 if (StringUtils
.isNotBlank(statusStr
)) {
1800 String proPartePattern
= "(pro parte|p.p.)";
1801 if (statusStr
.matches(proPartePattern
)) {
1802 state
.setProParte(true);
1805 // TODO handle trim earlier
1806 statusStr
= statusStr
.trim();
1807 NomenclaturalStatusType nomStatusType
= NomenclaturalStatusType
.getNomenclaturalStatusTypeByAbbreviation(statusStr
);
1808 name
.addStatus(NomenclaturalStatus
.NewInstance(nomStatusType
));
1809 } catch (UnknownCdmTypeException e
) {
1810 String message
= "Status '%s' could not be recognized";
1811 message
= String
.format(message
, statusStr
);
1812 fireWarningEvent(message
, event
, 4);
1817 if (StringUtils
.isNotBlank(notes
)) {
1818 handleNotYetImplementedAttributeValue(event
, CLASS
, NOTES
);
1831 private void makeRankDecision(MarkupImportState state
,
1832 Map
<String
, String
> nameMap
, NonViralName
<?
> name
, XMLEvent event
,
1833 String infrankStr
) {
1835 for (String key
: nameMap
.keySet()) {
1836 Rank rank
= makeRank(state
, key
, false);
1838 handleNotYetImplementedAttributeValue(event
, CLASS
, key
);
1840 if (name
.getRank() == null || rank
.isLower(name
.getRank())) {
1843 String value
= nameMap
.get(key
);
1844 if (rank
.isSupraGeneric() || rank
.isGenus()) {
1845 name
.setGenusOrUninomial(toFirstCapital(value
));
1846 } else if (rank
.isInfraGeneric()) {
1847 name
.setInfraGenericEpithet(toFirstCapital(value
));
1848 } else if (rank
.isSpecies()) {
1849 if (isFirstCapitalWord(value
)){ //capital letters are allowed for species epithet in case of person names (e.g. Manilkara Welwitschii Engl.
1850 name
.setSpecificEpithet(value
);
1852 name
.setSpecificEpithet(value
.toLowerCase());
1854 } else if (rank
.isInfraSpecific()) {
1855 name
.setInfraSpecificEpithet(value
.toLowerCase());
1857 String message
= "Invalid rank '%s'. Can't decide which epithet to fill with '%s'";
1858 message
= String
.format(message
, rank
.getTitleCache(),value
);
1859 fireWarningEvent(message
, event
, 4);
1864 // handle given infrank marker
1865 if (StringUtils
.isNotBlank(infrankStr
)) {
1866 Rank infRank
= makeRank(state
, infrankStr
, true);
1868 if (infRank
== null) {
1869 String message
= "Infrank '%s' rank not recognized";
1870 message
= String
.format(message
, infrankStr
);
1871 fireWarningEvent(message
, event
, 4);
1873 if (name
.getRank() == null) {
1874 name
.setRank(infRank
);
1875 } else if (infRank
.isLower(name
.getRank())) {
1876 String message
= "InfRank '%s' is lower than existing rank ";
1877 message
= String
.format(message
, infrankStr
);
1878 fireWarningEvent(message
, event
, 2);
1879 name
.setRank(infRank
);
1880 } else if (infRank
.equals(name
.getRank())) {
1883 String message
= "InfRank '%s' is higher than existing rank ";
1884 message
= String
.format(message
, infrankStr
);
1885 fireWarningEvent(message
, event
, 2);
1891 private String
toFirstCapital(String value
) {
1892 if (StringUtils
.isBlank(value
)){
1896 result
+= value
.substring(0,1).toUpperCase();
1897 if (value
.length()>1){
1898 result
+= value
.substring(1).toLowerCase();
1912 private void makeNomenclaturalAuthors(NonViralName name
, XMLEvent event
,
1913 String authorStr
, String paraut
, String infrParAut
, String infrAut
) {
1914 if (name
.getRank() != null && name
.getRank().isInfraSpecific()) {
1915 if (StringUtils
.isNotBlank(infrAut
)) {
1916 INomenclaturalAuthor
[] authorAndEx
= authorAndEx(infrAut
, event
);
1917 name
.setCombinationAuthorTeam(authorAndEx
[0]);
1918 name
.setExCombinationAuthorTeam(authorAndEx
[1]);
1920 if (StringUtils
.isNotBlank(infrParAut
)) {
1921 INomenclaturalAuthor
[] authorAndEx
= authorAndEx(infrParAut
, event
);
1922 name
.setBasionymAuthorTeam(authorAndEx
[0]);
1923 name
.setExBasionymAuthorTeam(authorAndEx
[1]);
1926 if (name
.getRank() == null){
1927 String message
= "No rank defined. Check correct usage of authors!";
1928 fireWarningEvent(message
, event
, 4);
1929 if (isNotBlank(infrParAut
) || isNotBlank(infrAut
)){
1930 authorStr
= infrAut
;
1931 paraut
= infrParAut
;
1934 if (StringUtils
.isNotBlank(authorStr
)) {
1935 INomenclaturalAuthor
[] authorAndEx
= authorAndEx(authorStr
, event
);
1936 name
.setCombinationAuthorTeam(authorAndEx
[0]);
1937 name
.setExCombinationAuthorTeam(authorAndEx
[1]);
1939 if (StringUtils
.isNotBlank(paraut
)) {
1940 INomenclaturalAuthor
[] authorAndEx
= authorAndEx(paraut
, event
);
1941 name
.setBasionymAuthorTeam(authorAndEx
[0]);
1942 name
.setExBasionymAuthorTeam(authorAndEx
[1]);
1947 private TeamOrPersonBase
[] authorAndEx(String authorAndEx
, XMLEvent xmlEvent
) {
1948 authorAndEx
= authorAndEx
.trim();
1949 TeamOrPersonBase
[] result
= new TeamOrPersonBase
[2];
1951 String
[] split
= authorAndEx
.split("\\sex\\s");
1952 if (split
.length
> 2) {
1953 String message
= "There is more then 1 ' ex ' in author string. Can't separate author and ex-author";
1954 fireWarningEvent(message
, xmlEvent
, 4);
1955 result
[0] = createAuthor(authorAndEx
);
1956 } else if (split
.length
== 2) {
1957 result
[0] = createAuthor(split
[1]);
1958 result
[1] = createAuthor(split
[0]);
1960 result
[0] = createAuthor(split
[0]);
1966 * Tests if the names rank is consistent with the given author strings.
1974 private void testRankAuthorConsistency(NonViralName name
, XMLEvent event
,
1975 String authorStr
, String paraut
, String infrParAut
, String infrAut
) {
1976 if (name
.getRank() == null){
1979 if (name
.getRank().isInfraSpecific()) {
1980 if (StringUtils
.isBlank(infrParAut
)
1981 && StringUtils
.isBlank(infrAut
) //was isNotBlank before 29.5.2012
1982 && (StringUtils
.isNotBlank(paraut
) || StringUtils
.isNotBlank(authorStr
))
1983 && ! name
.isAutonym()) {
1984 String message
= "Rank is infraspecicific but has only specific or higher author(s)";
1985 fireWarningEvent(message
, event
, 4);
1988 // is not infraspecific
1989 if (StringUtils
.isNotBlank(infrParAut
) || StringUtils
.isNotBlank(infrAut
)) {
1990 String message
= "Rank is not infraspecicific but name has infra author(s)";
1991 fireWarningEvent(message
, event
, 4);
1997 * Returns the (empty) name with the correct homotypical group depending on
1998 * the taxon status. Throws NPE if no currentTaxon is set in state.
2001 * @param homotypicalGroup
2005 private NonViralName
<?
> createName(MarkupImportState state
,
2006 HomotypicalGroup homotypicalGroup
, boolean isSynonym
) {
2007 NonViralName
<?
> name
;
2008 Taxon taxon
= state
.getCurrentTaxon();
2010 Rank defaultRank
= Rank
.SPECIES(); // can be any
2011 name
= createNameByCode(state
, defaultRank
);
2012 if (homotypicalGroup
!= null) {
2013 name
.setHomotypicalGroup(homotypicalGroup
);
2015 SynonymRelationshipType synonymType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
2016 if (taxon
.getHomotypicGroup().equals(homotypicalGroup
)) {
2017 synonymType
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
2019 taxon
.addSynonymName(name
, synonymType
);
2021 name
= CdmBase
.deproxy(taxon
.getName(), NonViralName
.class);
2026 private void handleName(MarkupImportState state
, XMLEventReader reader
,
2027 XMLEvent parentEvent
, Map
<String
, String
> nameMap
)
2028 throws XMLStreamException
{
2029 String classValue
= getClassOnlyAttribute(parentEvent
);
2032 while (reader
.hasNext()) {
2033 XMLEvent next
= readNoWhitespace(reader
);
2034 if (isMyEndingElement(next
, parentEvent
)) {
2035 nameMap
.put(classValue
, text
);
2037 } else if (next
.isStartElement()) {
2038 if (isStartingElement(next
, ANNOTATION
)) {
2039 handleNotYetImplementedElement(next
);
2041 handleUnexpectedStartElement(next
.asStartElement());
2043 } else if (next
.isCharacters()) {
2044 text
+= next
.asCharacters().getData();
2046 handleUnexpectedEndElement(next
.asEndElement());
2049 throw new IllegalStateException("name has no closing tag");
2059 private Rank
makeRank(MarkupImportState state
, String value
,
2062 if (StringUtils
.isBlank(value
)) {
2066 boolean useUnknown
= true;
2067 NomenclaturalCode nc
= makeNomenclaturalCode(state
);
2069 rank
= Rank
.getRankByAbbreviation(value
, nc
, useUnknown
);
2071 rank
= Rank
.getRankByEnglishName(value
, nc
, useUnknown
);
2073 if (rank
.equals(Rank
.UNKNOWN_RANK())) {
2076 } catch (UnknownCdmTypeException e
) {
2082 // public void handleNameNotRank(MarkupImportState state, XMLEventReader
2083 // reader, XMLEvent parentEvent, String classValue, NonViralName name)
2084 // throws XMLStreamException {
2085 // if (ACCEPTED.equalsIgnoreCase(classValue)){
2086 // }else if (SYNONYM.equalsIgnoreCase(classValue)){
2088 // //TODO Not yet implemented
2089 // handleNotYetImplementedAttributeValue(parentEvent, CLASS, classValue);
2093 private void handleCitation(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
, NonViralName name
) throws XMLStreamException
{
2094 String classValue
= getClassOnlyAttribute(parentEvent
);
2096 state
.setCitation(true);
2097 boolean hasRefPart
= false;
2098 Map
<String
, String
> refMap
= new HashMap
<String
, String
>();
2099 while (reader
.hasNext()) {
2100 XMLEvent next
= readNoWhitespace(reader
);
2101 if (isMyEndingElement(next
, parentEvent
)) {
2102 checkMandatoryElement(hasRefPart
, parentEvent
.asStartElement(),
2104 Reference
<?
> reference
= createReference(state
, refMap
, next
);
2105 String microReference
= refMap
.get(DETAILS
);
2106 doCitation(state
, name
, classValue
, reference
, microReference
,
2108 state
.setCitation(false);
2110 } else if (isStartingElement(next
, REF_PART
)) {
2111 handleRefPart(state
, reader
, next
, refMap
);
2114 handleUnexpectedElement(next
);
2117 throw new IllegalStateException("Citation has no closing tag");
2121 private void handleRefPart(MarkupImportState state
, XMLEventReader reader
,XMLEvent parentEvent
, Map
<String
, String
> refMap
) throws XMLStreamException
{
2122 String classValue
= getClassOnlyAttribute(parentEvent
);
2125 while (reader
.hasNext()) {
2126 XMLEvent next
= readNoWhitespace(reader
);
2127 if (isMyEndingElement(next
, parentEvent
)) {
2128 refMap
.put(classValue
, text
);
2130 } else if (next
.isStartElement()) {
2131 if (isStartingElement(next
, ANNOTATION
)) {
2132 handleNotYetImplementedElement(next
);
2133 } else if (isStartingElement(next
, ITALICS
)) {
2134 handleNotYetImplementedElement(next
);
2135 } else if (isStartingElement(next
, BOLD
)) {
2136 handleNotYetImplementedElement(next
);
2138 handleUnexpectedStartElement(next
.asStartElement());
2140 } else if (next
.isCharacters()) {
2141 text
+= next
.asCharacters().getData();
2143 handleUnexpectedEndElement(next
.asEndElement());
2146 throw new IllegalStateException("RefPart has no closing tag");
2150 private Reference
<?
> createReference(MarkupImportState state
, Map
<String
, String
> refMap
, XMLEvent parentEvent
) {
2152 Reference
<?
> reference
;
2154 String type
= getAndRemoveMapKey(refMap
, PUBTYPE
);
2155 String authorStr
= getAndRemoveMapKey(refMap
, AUTHOR
);
2156 String titleStr
= getAndRemoveMapKey(refMap
, PUBTITLE
);
2157 String titleCache
= getAndRemoveMapKey(refMap
, PUBFULLNAME
);
2158 String volume
= getAndRemoveMapKey(refMap
, VOLUME
);
2159 String edition
= getAndRemoveMapKey(refMap
, EDITION
);
2160 String editors
= getAndRemoveMapKey(refMap
, EDITORS
);
2161 String year
= getAndRemoveMapKey(refMap
, YEAR
);
2162 String pubName
= getAndRemoveMapKey(refMap
, PUBNAME
);
2163 String pages
= getAndRemoveMapKey(refMap
, PAGES
);
2165 if (state
.isCitation()) {
2166 if (volume
!= null || "journal".equalsIgnoreCase(type
)) {
2167 IArticle article
= ReferenceFactory
.newArticle();
2168 if (pubName
!= null) {
2169 IJournal journal
= ReferenceFactory
.newJournal();
2170 journal
.setTitle(pubName
);
2171 article
.setInJournal(journal
);
2173 reference
= (Reference
<?
>) article
;
2177 if (pubName
!= null){
2178 reference
= ReferenceFactory
.newBookSection();
2180 reference
= ReferenceFactory
.newBook();
2183 // TODO use existing author from name or before
2184 TeamOrPersonBase
<?
> author
= createAuthor(authorStr
);
2185 reference
.setAuthorTeam(author
);
2187 reference
.setTitle(titleStr
);
2188 if (StringUtils
.isNotBlank(titleCache
)) {
2189 reference
.setTitleCache(titleCache
, true);
2191 reference
.setEdition(edition
);
2192 reference
.setEditor(editors
);
2194 if (pubName
!= null) {
2195 Reference
<?
> inReference
;
2196 if (reference
.getType().equals(ReferenceType
.Article
)) {
2197 inReference
= ReferenceFactory
.newJournal();
2199 inReference
= ReferenceFactory
.newGeneric();
2201 inReference
.setTitle(pubName
);
2202 reference
.setInReference(inReference
);
2206 } else { //no citation
2207 if (volume
!= null || "journal".equalsIgnoreCase(type
)) {
2208 IArticle article
= ReferenceFactory
.newArticle();
2209 if (pubName
!= null) {
2210 IJournal journal
= ReferenceFactory
.newJournal();
2211 journal
.setTitle(pubName
);
2212 article
.setInJournal(journal
);
2214 reference
= (Reference
<?
>) article
;
2217 Reference
<?
> bookOrPartOf
= ReferenceFactory
.newGeneric();
2218 reference
= bookOrPartOf
;
2222 TeamOrPersonBase
<?
> author
= createAuthor(authorStr
);
2223 reference
.setAuthorTeam(author
);
2225 reference
.setTitle(titleStr
);
2226 if (StringUtils
.isNotBlank(titleCache
)) {
2227 reference
.setTitleCache(titleCache
, true);
2229 reference
.setEdition(edition
);
2230 reference
.setEditor(editors
);
2232 if (pubName
!= null) {
2233 Reference
<?
> inReference
;
2234 if (reference
.getType().equals(ReferenceType
.Article
)) {
2235 inReference
= ReferenceFactory
.newJournal();
2237 inReference
= ReferenceFactory
.newGeneric();
2239 inReference
.setTitle(pubName
);
2240 reference
.setInReference(inReference
);
2243 reference
.setVolume(volume
);
2244 reference
.setDatePublished(TimePeriod
.parseString(year
));
2245 //TODO check if this is handled correctly in FM markup
2246 reference
.setPages(pages
);
2249 String
[] unhandledList
= new String
[]{ALTERNATEPUBTITLE
, ISSUE
, NOTES
, STATUS
};
2250 for (String unhandled
: unhandledList
){
2251 String value
= getAndRemoveMapKey(refMap
, unhandled
);
2252 if (isNotBlank(value
)){
2253 this.handleNotYetImplementedAttributeValue(parentEvent
, CLASS
, unhandled
);
2257 for (String key
: refMap
.keySet()) {
2258 if (!DETAILS
.equalsIgnoreCase(key
)) {
2259 this.fireUnexpectedAttributeValue(parentEvent
, CLASS
, key
);
2266 private TeamOrPersonBase
createAuthor(String authorTitle
) {
2267 // TODO atomize and also use by name creation
2268 TeamOrPersonBase result
= Team
.NewTitledInstance(authorTitle
,
2273 private String
getAndRemoveMapKey(Map
<String
, String
> map
, String key
) {
2274 String result
= map
.get(key
);
2276 if (result
!= null) {
2277 result
= normalize(result
);
2279 return StringUtils
.stripToNull(result
);
2282 private void doCitation(MarkupImportState state
, NonViralName name
,
2283 String classValue
, Reference reference
, String microCitation
,
2284 XMLEvent parentEvent
) {
2285 if (PUBLICATION
.equalsIgnoreCase(classValue
)) {
2286 name
.setNomenclaturalReference(reference
);
2287 name
.setNomenclaturalMicroReference(microCitation
);
2288 } else if (USAGE
.equalsIgnoreCase(classValue
)) {
2289 Taxon taxon
= state
.getCurrentTaxon();
2290 TaxonDescription td
= getTaxonDescription(taxon
, state
2291 .getConfig().getSourceReference(), false, true);
2292 TextData citation
= TextData
.NewInstance(Feature
.CITATION());
2293 // TODO name used in source
2294 citation
.addSource(null, null, reference
, microCitation
);
2295 td
.addElement(citation
);
2296 } else if (TYPE
.equalsIgnoreCase(classValue
)) {
2297 handleNotYetImplementedAttributeValue(parentEvent
, CLASS
,
2300 // TODO Not yet implemented
2301 handleNotYetImplementedAttributeValue(parentEvent
, CLASS
,
2306 private void handleFeature(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
2307 String classValue
= getClassOnlyAttribute(parentEvent
);
2308 Feature feature
= makeFeature(classValue
, state
, parentEvent
);
2309 Taxon taxon
= state
.getCurrentTaxon();
2310 TaxonDescription taxonDescription
= getTaxonDescription(taxon
, state
.getConfig().getSourceReference(), NO_IMAGE_GALLERY
, CREATE_NEW
);
2311 // TextData figureHolderTextData = null; //for use with one TextData for
2314 boolean isDescription
= feature
.equals(Feature
.DESCRIPTION());
2315 DescriptionElementBase lastDescriptionElement
= null;
2317 while (reader
.hasNext()) {
2318 XMLEvent next
= readNoWhitespace(reader
);
2319 if (isMyEndingElement(next
, parentEvent
)) {
2321 } else if (isEndingElement(next
, DISTRIBUTION_LIST
) || isEndingElement(next
, HABITAT_LIST
)) {
2322 // only handle list elements
2323 } else if (isStartingElement(next
, HEADING
)) {
2324 makeFeatureHeading(state
, reader
, classValue
, feature
, next
);
2325 } else if (isStartingElement(next
, WRITER
)) {
2326 makeFeatureWriter(state
, reader
, feature
, taxon
, next
);
2327 // } else if (isStartingElement(next, DISTRIBUTION_LOCALITY)) {
2328 // if (!feature.equals(Feature.DISTRIBUTION())) {
2329 // String message = "Distribution locality only allowed for feature of type 'distribution'";
2330 // fireWarningEvent(message, next, 4);
2332 // handleDistributionLocality(state, reader, next);
2333 } else if (isStartingElement(next
, DISTRIBUTION_LIST
) || isStartingElement(next
, HABITAT_LIST
)) {
2334 // only handle single list elements
2335 } else if (isStartingElement(next
, HABITAT
)) {
2336 if (!(feature
.equals(Feature
.HABITAT())
2337 || feature
.equals(Feature
.HABITAT_ECOLOGY())
2338 || feature
.equals(Feature
.ECOLOGY()))) {
2339 String message
= "Habitat only allowed for feature of type 'habitat','habitat ecology' or 'ecology'";
2340 fireWarningEvent(message
, next
, 4);
2342 handleHabitat(state
, reader
, next
);
2343 } else if (isStartingElement(next
, CHAR
)) {
2344 TextData textData
= handleChar(state
, reader
, next
);
2345 taxonDescription
.addElement(textData
);
2346 } else if (isStartingElement(next
, STRING
)) {
2347 lastDescriptionElement
= makeFeatureString(state
, reader
,feature
, taxonDescription
, lastDescriptionElement
,next
);
2348 } else if (isStartingElement(next
, FIGURE_REF
)) {
2349 lastDescriptionElement
= makeFeatureFigureRef(state
, reader
, taxonDescription
, isDescription
, lastDescriptionElement
, next
);
2350 } else if (isStartingElement(next
, REFERENCES
)) {
2351 // TODO details/microcitation ??
2353 List
<Reference
<?
>> refs
= handleReferences(state
, reader
, next
);
2354 if (!refs
.isEmpty()) {
2356 Reference
<?
> descriptionRef
= state
.getConfig().getSourceReference();
2357 TaxonDescription description
= getTaxonDescription(taxon
, descriptionRef
, false, true);
2358 TextData featurePlaceholder
= docImport
.getFeaturePlaceholder(state
, description
, feature
, true);
2359 for (Reference
<?
> citation
: refs
) {
2360 featurePlaceholder
.addSource(null, null, citation
, null);
2363 String message
= "No reference found in references";
2364 fireWarningEvent(message
, next
, 6);
2366 } else if (isStartingElement(next
, NUM
)) {
2368 handleNotYetImplementedElement(next
);
2369 } else if (isEndingElement(next
, NUM
)) {
2371 popUnimplemented(next
.asEndElement());
2373 handleUnexpectedElement(next
);
2376 throw new IllegalStateException("<Feature> has no closing tag");
2382 * @param taxonDescription
2383 * @param isDescription
2384 * @param lastDescriptionElement
2387 * @throws XMLStreamException
2389 private DescriptionElementBase
makeFeatureFigureRef(MarkupImportState state
, XMLEventReader reader
,TaxonDescription taxonDescription
,
2390 boolean isDescription
, DescriptionElementBase lastDescriptionElement
, XMLEvent next
)throws XMLStreamException
{
2391 FigureDataHolder figureHolder
= handleFigureRef(state
, reader
, next
);
2392 Feature figureFeature
= getFeature(state
,MarkupTransformer
.uuidFigures
, "Figures", "Figures", "Fig.",null);
2393 if (isDescription
) {
2394 TextData figureHolderTextData
= null;
2395 // if (figureHolderTextData == null){
2396 figureHolderTextData
= TextData
.NewInstance(figureFeature
);
2397 if (StringUtils
.isNotBlank(figureHolder
.num
)) {
2398 String annotationText
= "<num>" + figureHolder
.num
.trim()
2400 Annotation annotation
= Annotation
.NewInstance(annotationText
,
2401 AnnotationType
.TECHNICAL(), Language
.DEFAULT());
2402 figureHolderTextData
.addAnnotation(annotation
);
2404 if (StringUtils
.isNotBlank(figureHolder
.figurePart
)) {
2405 String annotationText
= "<figurePart>"+ figureHolder
.figurePart
.trim() + "</figurePart>";
2406 Annotation annotation
= Annotation
.NewInstance(annotationText
,AnnotationType
.EDITORIAL(), Language
.DEFAULT());
2407 figureHolderTextData
.addAnnotation(annotation
);
2409 // if (StringUtils.isNotBlank(figureText)){
2410 // figureHolderTextData.putText(Language.DEFAULT(), figureText);
2412 taxonDescription
.addElement(figureHolderTextData
);
2414 registerFigureDemand(state
, figureHolderTextData
, figureHolder
.ref
);
2416 if (lastDescriptionElement
== null) {
2417 String message
= "No description element created yet that can be referred by figure. Create new TextData instead";
2418 fireWarningEvent(message
, next
, 4);
2419 lastDescriptionElement
= TextData
.NewInstance(figureFeature
);
2420 taxonDescription
.addElement(lastDescriptionElement
);
2422 registerFigureDemand(state
, lastDescriptionElement
,
2425 return lastDescriptionElement
;
2432 * @param taxonDescription
2433 * @param lastDescriptionElement
2434 * @param distributionList
2437 * @throws XMLStreamException
2439 private DescriptionElementBase
makeFeatureString(MarkupImportState state
,XMLEventReader reader
, Feature feature
,
2440 TaxonDescription taxonDescription
, DescriptionElementBase lastDescriptionElement
, XMLEvent next
) throws XMLStreamException
{
2442 if (feature
.equals(Feature
.SPECIMEN()) || feature
.equals(Feature
.MATERIALS_EXAMINED())){
2444 List
<DescriptionElementBase
> specimens
= handleMaterialsExamined(state
, reader
, next
);
2445 for (DescriptionElementBase specimen
: specimens
){
2446 taxonDescription
.addElement(specimen
);
2447 lastDescriptionElement
= specimen
;
2449 return lastDescriptionElement
;
2453 Map
<String
, String
> subheadingMap
= handleString(state
, reader
, next
, feature
);
2454 for (String subheading
: subheadingMap
.keySet()) {
2455 Feature subheadingFeature
= feature
;
2456 if (StringUtils
.isNotBlank(subheading
) && subheadingMap
.size() > 1) {
2457 subheadingFeature
= makeFeature(subheading
, state
, next
);
2459 if (feature
.equals(Feature
.COMMON_NAME())){
2460 List
<DescriptionElementBase
> commonNames
= makeVernacular(state
, subheading
, subheadingMap
.get(subheading
));
2461 for (DescriptionElementBase commonName
: commonNames
){
2462 taxonDescription
.addElement(commonName
);
2463 lastDescriptionElement
= commonName
;
2466 TextData textData
= TextData
.NewInstance(subheadingFeature
);
2467 textData
.putText(Language
.DEFAULT(), subheadingMap
.get(subheading
));
2468 taxonDescription
.addElement(textData
);
2469 lastDescriptionElement
= textData
;
2470 // TODO how to handle figures when these data are split in
2474 return lastDescriptionElement
;
2477 private List
<DescriptionElementBase
> makeVernacular(MarkupImportState state
, String subheading
, String commonNameString
) throws XMLStreamException
{
2478 List
<DescriptionElementBase
> result
= new ArrayList
<DescriptionElementBase
>();
2479 String
[] splits
= commonNameString
.split(",");
2480 for (String split
: splits
){
2481 split
= split
.trim();
2482 if (! split
.matches(".*\\(.*\\)\\.?")){
2483 fireWarningEvent("Common name string '"+split
+"' does not match given pattern", state
.getReader().peek(), 4);
2486 String name
= split
.replaceAll("\\(.*\\)", "").replace(".", "").trim();
2487 String languageStr
= split
.replaceFirst(".*\\(", "").replaceAll("\\)\\.?", "").trim();
2489 Language language
= null;
2490 if (StringUtils
.isNotBlank(languageStr
)){
2492 UUID langUuid
= state
.getTransformer().getLanguageUuid(languageStr
);
2493 TermVocabulary
<?
> voc
= null;
2494 language
= getLanguage(state
, langUuid
, languageStr
, languageStr
, null, voc
);
2495 if (language
== null){
2496 logger
.warn("Language " + languageStr
+ " not recognized by transformer");
2498 } catch (UndefinedTransformerMethodException e
) {
2499 throw new RuntimeException(e
);
2502 NamedArea area
= null;
2503 CommonTaxonName commonTaxonName
= CommonTaxonName
.NewInstance(name
, language
, area
);
2504 result
.add(commonTaxonName
);
2510 private List
<DescriptionElementBase
> handleMaterialsExamined(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
2511 List
<DescriptionElementBase
> result
= new ArrayList
<DescriptionElementBase
>();
2512 while (reader
.hasNext()) {
2513 XMLEvent next
= readNoWhitespace(reader
);
2514 if (isMyEndingElement(next
, parentEvent
)) {
2515 if (result
.isEmpty()){
2516 fireWarningEvent("Materials examined created empty Individual Associations list", parentEvent
, 4);
2519 } else if (isStartingElement(next
, SUB_HEADING
)) {
2520 handleNotYetImplementedElement(next
);
2521 } else if (isStartingElement(next
, BR
)) {
2522 handleNotYetImplementedElement(next
);
2523 } else if (isStartingElement(next
, GATHERING
)) {
2524 DerivedUnitFacade facade
= DerivedUnitFacade
.NewInstance(DerivedUnitType
.DerivedUnit
.DerivedUnit
);
2525 handleGathering(state
, reader
, next
, facade
);
2526 SpecimenOrObservationBase
<?
> specimen
;
2527 if (facade
.innerDerivedUnit() != null){
2528 specimen
= facade
.innerDerivedUnit();
2530 specimen
= facade
.innerFieldObservation();
2532 IndividualsAssociation individualsAssociation
= IndividualsAssociation
.NewInstance();
2533 individualsAssociation
.setAssociatedSpecimenOrObservation(specimen
);
2534 result
.add(individualsAssociation
);
2536 handleUnexpectedElement(next
);
2539 throw new IllegalStateException("<String> has no closing tag");
2549 * @throws XMLStreamException
2551 private void makeFeatureWriter(MarkupImportState state
,XMLEventReader reader
, Feature feature
, Taxon taxon
, XMLEvent next
) throws XMLStreamException
{
2552 WriterDataHolder writer
= handleWriter(state
, reader
, next
);
2553 if (isNotBlank(writer
.writer
)) {
2555 Reference
<?
> ref
= state
.getConfig().getSourceReference();
2556 TaxonDescription description
= getTaxonDescription(taxon
, ref
,
2558 TextData featurePlaceholder
= docImport
.getFeaturePlaceholder(state
,
2559 description
, feature
, true);
2560 featurePlaceholder
.addAnnotation(writer
.annotation
);
2561 registerFootnotes(state
, featurePlaceholder
, writer
.footnotes
);
2563 String message
= "Writer element is empty";
2564 fireWarningEvent(message
, next
, 4);
2574 * @throws XMLStreamException
2576 private void makeFeatureHeading(MarkupImportState state
, XMLEventReader reader
, String classValue
, Feature feature
, XMLEvent next
) throws XMLStreamException
{
2577 String heading
= handleHeading(state
, reader
, next
);
2578 if (StringUtils
.isNotBlank(heading
)) {
2579 if (!heading
.equalsIgnoreCase(classValue
)) {
2581 if (!feature
.equals(state
.getTransformer().getFeatureByKey(
2583 UUID headerFeatureUuid
= state
.getTransformer()
2584 .getFeatureUuid(heading
);
2585 if (!feature
.getUuid().equals(headerFeatureUuid
)) {
2586 String message
= "Feature heading '%s' differs from feature class '%s' and can not be transformed to feature";
2587 message
= String
.format(message
, heading
,
2589 fireWarningEvent(message
, next
, 1);
2592 } catch (UndefinedTransformerMethodException e
) {
2593 throw new RuntimeException(e
);
2601 private List
<Reference
<?
>> handleReferences(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
2603 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
2604 String bibliography
= getAndRemoveAttributeValue(attributes
,
2606 String serialsAbbreviations
= getAndRemoveAttributeValue(attributes
,
2607 SERIALS_ABBREVIATIONS
);
2608 if (isNotBlank(bibliography
) || isNotBlank(serialsAbbreviations
)) {
2609 String message
= "Attributes not yet implemented for <references>";
2610 fireWarningEvent(message
, parentEvent
, 4);
2613 List
<Reference
<?
>> result
= new ArrayList
<Reference
<?
>>();
2616 while (reader
.hasNext()) {
2617 XMLEvent next
= readNoWhitespace(reader
);
2618 if (next
.isEndElement()) {
2619 if (isMyEndingElement(next
, parentEvent
)) {
2622 if (isEndingElement(next
, HEADING
)) {
2623 // NOT YET IMPLEMENTED
2624 popUnimplemented(next
.asEndElement());
2625 } else if (isEndingElement(next
, WRITER
)) {
2626 // NOT YET IMPLEMENTED
2627 popUnimplemented(next
.asEndElement());
2628 } else if (isEndingElement(next
, FOOTNOTE
)) {
2629 // NOT YET IMPLEMENTED
2630 popUnimplemented(next
.asEndElement());
2631 } else if (isEndingElement(next
, STRING
)) {
2632 // NOT YET IMPLEMENTED
2633 popUnimplemented(next
.asEndElement());
2634 } else if (isEndingElement(next
, REF_NUM
)) {
2635 // NOT YET IMPLEMENTED
2636 popUnimplemented(next
.asEndElement());
2638 handleUnexpectedEndElement(next
.asEndElement());
2641 } else if (next
.isStartElement()) {
2642 if (isStartingElement(next
, HEADING
)) {
2643 handleNotYetImplementedElement(next
);
2644 } else if (isStartingElement(next
, SUB_HEADING
)) {
2645 String subheading
= getCData(state
, reader
, next
).trim();
2646 String excludePattern
= "(i?)(References?|Literature):?";
2647 if (!subheading
.matches(excludePattern
)) {
2648 fireNotYetImplementedElement(next
.getLocation(), next
.asStartElement().getName(), 0);
2650 } else if (isStartingElement(next
, WRITER
)) {
2651 handleNotYetImplementedElement(next
);
2652 } else if (isStartingElement(next
, FOOTNOTE
)) {
2653 handleNotYetImplementedElement(next
);
2654 } else if (isStartingElement(next
, STRING
)) {
2655 handleNotYetImplementedElement(next
);
2656 } else if (isStartingElement(next
, REF_NUM
)) {
2657 handleNotYetImplementedElement(next
);
2658 } else if (isStartingElement(next
, REFERENCE
)) {
2659 Reference
<?
> ref
= handleReference(state
, reader
, next
);
2662 handleUnexpectedStartElement(next
);
2665 handleUnexpectedElement(next
);
2668 throw new IllegalStateException("<References> has no closing tag");
2671 private void handleHabitat(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
2672 checkNoAttributes(parentEvent
);
2673 Taxon taxon
= state
.getCurrentTaxon();
2674 // TODO which ref to take?
2675 Reference
<?
> ref
= state
.getConfig().getSourceReference();
2678 while (reader
.hasNext()) {
2679 XMLEvent next
= readNoWhitespace(reader
);
2680 if (isMyEndingElement(next
, parentEvent
)) {
2681 TaxonDescription description
= getTaxonDescription(taxon
, ref
,
2683 UUID uuidExtractedHabitat
= MarkupTransformer
.uuidExtractedHabitat
;
2684 Feature feature
= getFeature(
2686 uuidExtractedHabitat
,
2687 "Extracted Habitat",
2688 "An structured habitat that was extracted from a habitat text",
2689 "extr. habit.", null);
2690 TextData habitat
= TextData
.NewInstance(feature
);
2691 habitat
.putText(Language
.DEFAULT(), text
);
2692 description
.addElement(habitat
);
2695 } else if (next
.isStartElement()) {
2696 if (isStartingElement(next
, ALTITUDE
)) {
2697 text
= text
.trim() + getTaggedCData(state
, reader
, next
);
2698 } else if (isStartingElement(next
, LIFE_CYCLE_PERIODS
)) {
2699 handleNotYetImplementedElement(next
);
2701 handleUnexpectedStartElement(next
.asStartElement());
2703 } else if (next
.isCharacters()) {
2704 text
+= next
.asCharacters().getData();
2706 handleUnexpectedElement(next
);
2709 throw new IllegalStateException("<Habitat> has no closing tag");
2712 private String
getTaggedCData(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
2713 checkNoAttributes(parentEvent
);
2715 String text
= getXmlTag(parentEvent
);
2716 while (reader
.hasNext()) {
2717 XMLEvent next
= readNoWhitespace(reader
);
2718 if (isMyEndingElement(next
, parentEvent
)) {
2719 text
+= getXmlTag(next
);
2721 } else if (next
.isStartElement()) {
2722 text
+= getTaggedCData(state
, reader
, next
);
2723 } else if (next
.isEndElement()) {
2724 text
+= getTaggedCData(state
, reader
, next
);
2725 } else if (next
.isCharacters()) {
2726 text
+= next
.asCharacters().getData();
2728 handleUnexpectedEndElement(next
.asEndElement());
2731 throw new IllegalStateException("Some tag has no closing tag");
2734 private String
handleDistributionLocality(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
)throws XMLStreamException
{
2735 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
2736 String classValue
= getAndRemoveRequiredAttributeValue(parentEvent
, attributes
, CLASS
);
2737 String statusValue
=getAndRemoveAttributeValue(attributes
, STATUS
);
2738 String frequencyValue
=getAndRemoveAttributeValue(attributes
, FREQUENCY
);
2741 Taxon taxon
= state
.getCurrentTaxon();
2742 // TODO which ref to take?
2743 Reference
<?
> ref
= state
.getConfig().getSourceReference();
2746 while (reader
.hasNext()) {
2747 XMLEvent next
= readNoWhitespace(reader
);
2748 if (isMyEndingElement(next
, parentEvent
)) {
2749 if (StringUtils
.isNotBlank(text
)) {
2750 String label
= CdmUtils
.removeTrailingDot(normalize(text
));
2751 TaxonDescription description
= getTaxonDescription(taxon
, ref
, false, true);
2752 NamedAreaLevel level
= makeNamedAreaLevel(state
,classValue
, next
);
2755 PresenceAbsenceTermBase
<?
> status
= null;
2756 if (isNotBlank(statusValue
)){
2758 status
= state
.getTransformer().getPresenceTermByKey(statusValue
);
2759 if (status
== null){
2761 String message
= "The status '%s' could not be transformed to an CDM status";
2762 fireWarningEvent(message
, next
, 4);
2764 } catch (UndefinedTransformerMethodException e
) {
2765 throw new RuntimeException(e
);
2768 status
= PresenceTerm
.PRESENT();
2771 if (isNotBlank(frequencyValue
)){
2772 String message
= "The frequency attribute is currently not yet available in CDM";
2773 fireWarningEvent(message
, parentEvent
, 6);
2776 NamedArea higherArea
= null;
2777 List
<NamedArea
> areas
= new ArrayList
<NamedArea
>();
2779 String patSingleArea
= "([^,\\(]{3,})";
2780 String patSeparator
= "(,|\\sand\\s)";
2781 String hierarchiePattern
= String
.format("%s\\((%s(%s%s)*)\\)",patSingleArea
, patSingleArea
, patSeparator
, patSingleArea
);
2782 Pattern patHierarchie
= Pattern
.compile(hierarchiePattern
, Pattern
.CASE_INSENSITIVE
);
2783 Matcher matcher
= patHierarchie
.matcher(label
);
2784 if (matcher
.matches()){
2785 String higherAreaStr
= matcher
.group(1).trim();
2786 higherArea
= makeArea(state
, higherAreaStr
, level
);
2787 String
[] innerAreas
= matcher
.group(2).split(patSeparator
);
2788 for (String innerArea
: innerAreas
){
2789 if (isNotBlank(innerArea
)){
2790 NamedArea singleArea
= makeArea(state
, innerArea
.trim(), level
);
2791 areas
.add(singleArea
);
2792 NamedArea partOf
= singleArea
.getPartOf();
2793 // if (partOf == null){
2794 // singleArea.setPartOf(higherArea);
2799 NamedArea singleArea
= makeArea(state
, label
, level
);
2800 areas
.add(singleArea
);
2803 for (NamedArea area
: areas
){
2804 //create distribution
2805 Distribution distribution
= Distribution
.NewInstance(area
,status
);
2806 description
.addElement(distribution
);
2809 String message
= "Empty distribution locality";
2810 fireWarningEvent(message
, next
, 4);
2813 } else if (isStartingElement(next
, COORDINATES
)) {
2815 handleNotYetImplementedElement(next
);
2816 } else if (isEndingElement(next
, COORDINATES
)) {
2818 popUnimplemented(next
.asEndElement());
2819 } else if (next
.isCharacters()) {
2820 text
+= next
.asCharacters().getData();
2822 handleUnexpectedElement(next
);
2825 throw new IllegalStateException("<DistributionLocality> has no closing tag");
2834 private NamedArea
makeArea(MarkupImportState state
, String areaName
, NamedAreaLevel level
) {
2837 //TODO FM vocabulary
2838 TermVocabulary
<NamedArea
> voc
= null;
2839 NamedAreaType areaType
= null;
2841 NamedArea area
= null;
2843 area
= state
.getTransformer().getNamedAreaByKey(areaName
);
2844 } catch (UndefinedTransformerMethodException e
) {
2845 throw new RuntimeException(e
);
2848 boolean isNewInState
= false;
2849 UUID uuid
= state
.getAreaUuid(areaName
);
2851 isNewInState
= true;
2855 uuid
= state
.getTransformer().getNamedAreaUuid(areaName
);
2856 } catch (UndefinedTransformerMethodException e
) {
2857 throw new RuntimeException(e
);
2861 CdmImportBase
.TermMatchMode matchMode
= CdmImportBase
.TermMatchMode
.UUID_LABEL
;
2862 area
= getNamedArea(state
, uuid
, areaName
, areaName
, areaName
, areaType
, level
, voc
, matchMode
);
2864 state
.putAreaUuid(areaName
, area
.getUuid());
2866 //TODO just for testing -> make generic and move to better place
2867 String geoServiceLayer
="vmap0_as_bnd_political_boundary_a";
2868 String layerFieldName
="nam";
2870 if ("Bangka".equals(areaName
)){
2871 String areaValue
= "PULAU BANGKA#SUMATERA SELATAN";
2872 GeoServiceArea geoServiceArea
= new GeoServiceArea();
2873 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
2874 this.editGeoService
.setMapping(area
, geoServiceArea
);
2875 // save(area, state);
2877 if ("Luzon".equals(areaName
)){
2878 GeoServiceArea geoServiceArea
= new GeoServiceArea();
2880 List
<String
> list
= Arrays
.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON",
2881 "HERMANA MENOR ISLAND#CENTRAL LUZON",
2883 for (String areaValue
: list
){
2884 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
2887 this.editGeoService
.setMapping(area
, geoServiceArea
);
2888 // save(area, state);
2890 if ("Mindanao".equals(areaName
)){
2891 GeoServiceArea geoServiceArea
= new GeoServiceArea();
2893 List
<String
> list
= Arrays
.asList("NORTHERN MINDANAO",
2894 "SOUTHERN MINDANAO",
2895 "WESTERN MINDANAO");
2896 //TODO to be continued
2897 for (String areaValue
: list
){
2898 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
2901 this.editGeoService
.setMapping(area
, geoServiceArea
);
2902 // save(area, state);
2904 if ("Palawan".equals(areaName
)){
2905 GeoServiceArea geoServiceArea
= new GeoServiceArea();
2907 List
<String
> list
= Arrays
.asList("PALAWAN#SOUTHERN TAGALOG");
2908 for (String areaValue
: list
){
2909 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
2912 this.editGeoService
.setMapping(area
, geoServiceArea
);
2913 // save(area, state);
2925 * @param levelString
2929 private NamedAreaLevel
makeNamedAreaLevel(MarkupImportState state
,
2930 String levelString
, XMLEvent next
) {
2931 NamedAreaLevel level
;
2933 level
= state
.getTransformer().getNamedAreaLevelByKey(levelString
);
2934 if (level
== null) {
2935 UUID levelUuid
= state
.getTransformer().getNamedAreaLevelUuid(levelString
);
2936 if (levelUuid
== null) {
2937 String message
= "Unknown distribution locality class (named area level): %s. Create new level instead.";
2938 message
= String
.format(message
, levelString
);
2939 fireWarningEvent(message
, next
, 6);
2941 level
= getNamedAreaLevel(state
, levelUuid
, levelString
, levelString
, levelString
, null);
2943 } catch (UndefinedTransformerMethodException e
) {
2944 throw new RuntimeException(e
);
2949 private String
handleHeading(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
)throws XMLStreamException
{
2950 checkNoAttributes(parentEvent
);
2953 while (reader
.hasNext()) {
2954 XMLEvent next
= readNoWhitespace(reader
);
2955 if (isMyEndingElement(next
, parentEvent
)) {
2957 } else if (next
.isStartElement()) {
2958 if (isStartingElement(next
, FOOTNOTE
)) {
2959 handleNotYetImplementedElement(next
);
2961 handleUnexpectedStartElement(next
.asStartElement());
2963 } else if (next
.isCharacters()) {
2964 text
+= next
.asCharacters().getData();
2966 handleUnexpectedEndElement(next
.asEndElement());
2969 throw new IllegalStateException("<String> has no closing tag");
2977 * @param parentEvent
2978 * @param feature only needed for distributionLocalities
2980 * @throws XMLStreamException
2982 private Map
<String
, String
> handleString(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
, Feature feature
)throws XMLStreamException
{
2984 String classValue
= getClassOnlyAttribute(parentEvent
, false);
2985 if (StringUtils
.isNotBlank(classValue
)) {
2986 String message
= "class attribute for <string> not yet implemented";
2987 fireWarningEvent(message
, parentEvent
, 2);
2991 Map
<String
, String
> subHeadingMap
= new HashMap
<String
, String
>();
2992 String currentSubheading
= null;
2994 boolean isTextMode
= true;
2996 while (reader
.hasNext()) {
2997 XMLEvent next
= readNoWhitespace(reader
);
2998 if (isMyEndingElement(next
, parentEvent
)) {
2999 putCurrentSubheading(subHeadingMap
, currentSubheading
, text
);
3000 return subHeadingMap
;
3001 } else if (isStartingElement(next
, BR
)) {
3004 } else if (isEndingElement(next
, BR
)) {
3006 } else if (isHtml(next
)) {
3007 text
+= getXmlTag(next
);
3008 } else if (isStartingElement(next
, SUB_HEADING
)) {
3009 text
= putCurrentSubheading(subHeadingMap
,currentSubheading
, text
);
3011 currentSubheading
= getCData(state
, reader
, next
).trim();
3012 } else if (isStartingElement(next
, DISTRIBUTION_LOCALITY
)) {
3013 if (feature
!= null && !feature
.equals(Feature
.DISTRIBUTION())) {
3014 String message
= "Distribution locality only allowed for feature of type 'distribution'";
3015 fireWarningEvent(message
, next
, 4);
3017 text
+= handleDistributionLocality(state
, reader
, next
);
3018 } else if (next
.isCharacters()) {
3020 String message
= "String is not in text mode";
3021 fireWarningEvent(message
, next
, 6);
3023 text
+= next
.asCharacters().getData();
3025 } else if (isStartingElement(next
, HEADING
)) {
3027 handleNotYetImplementedElement(next
);
3028 } else if (isEndingElement(next
, HEADING
)) {
3030 popUnimplemented(next
.asEndElement());
3031 } else if (isStartingElement(next
, QUOTE
)) {
3033 handleNotYetImplementedElement(next
);
3034 } else if (isEndingElement(next
, QUOTE
)) {
3036 popUnimplemented(next
.asEndElement());
3037 } else if (isStartingElement(next
, DEDICATION
)) {
3039 handleNotYetImplementedElement(next
);
3040 } else if (isEndingElement(next
, DEDICATION
)) {
3042 popUnimplemented(next
.asEndElement());
3043 } else if (isStartingElement(next
, TAXONTYPE
)) {
3045 handleNotYetImplementedElement(next
);
3046 } else if (isEndingElement(next
, TAXONTYPE
)) {
3048 popUnimplemented(next
.asEndElement());
3049 } else if (isStartingElement(next
, FULL_NAME
)) {
3051 handleNotYetImplementedElement(next
);
3052 } else if (isEndingElement(next
, FULL_NAME
)) {
3054 popUnimplemented(next
.asEndElement());
3055 }else if (isStartingElement(next
, REFERENCES
)) {
3057 handleNotYetImplementedElement(next
);
3058 } else if (isEndingElement(next
, REFERENCES
)) {
3060 popUnimplemented(next
.asEndElement());
3061 } else if (isStartingElement(next
, GATHERING
)) {
3063 handleNotYetImplementedElement(next
);
3064 } else if (isEndingElement(next
, GATHERING
)) {
3066 popUnimplemented(next
.asEndElement());
3067 } else if (isStartingElement(next
, ANNOTATION
)) {
3069 handleNotYetImplementedElement(next
);
3070 } else if (isEndingElement(next
, ANNOTATION
)) {
3072 popUnimplemented(next
.asEndElement());
3073 } else if (isStartingElement(next
, HABITAT
)) {
3075 handleNotYetImplementedElement(next
);
3076 } else if (isEndingElement(next
, HABITAT
)) {
3078 popUnimplemented(next
.asEndElement());
3079 } else if (isStartingElement(next
, FIGURE_REF
)) {
3081 handleNotYetImplementedElement(next
);
3082 } else if (isEndingElement(next
, FIGURE_REF
)) {
3084 popUnimplemented(next
.asEndElement());
3085 } else if (isStartingElement(next
, FIGURE
)) {
3087 handleNotYetImplementedElement(next
);
3088 } else if (isEndingElement(next
, FIGURE
)) {
3090 popUnimplemented(next
.asEndElement());
3091 } else if (isStartingElement(next
, FOOTNOTE_REF
)) {
3093 handleNotYetImplementedElement(next
);
3094 } else if (isEndingElement(next
, FOOTNOTE_REF
)) {
3096 popUnimplemented(next
.asEndElement());
3097 } else if (isStartingElement(next
, FOOTNOTE
)) {
3099 handleNotYetImplementedElement(next
);
3100 } else if (isEndingElement(next
, FOOTNOTE
)) {
3102 popUnimplemented(next
.asEndElement());
3103 } else if (isStartingElement(next
, WRITER
)) {
3105 handleNotYetImplementedElement(next
);
3106 } else if (isEndingElement(next
, WRITER
)) {
3108 popUnimplemented(next
.asEndElement());
3109 } else if (isStartingElement(next
, DATES
)) {
3111 handleNotYetImplementedElement(next
);
3112 } else if (isEndingElement(next
, DATES
)) {
3114 popUnimplemented(next
.asEndElement());
3116 handleUnexpectedElement(next
);
3119 throw new IllegalStateException("<String> has no closing tag");
3123 * @param subHeadingMap
3124 * @param currentSubheading
3128 private String
putCurrentSubheading(Map
<String
, String
> subHeadingMap
, String currentSubheading
, String text
) {
3129 if (StringUtils
.isNotBlank(text
)) {
3130 text
= removeStartingMinus(text
);
3131 subHeadingMap
.put(currentSubheading
, text
.trim());
3136 private String
removeStartingMinus(String string
) {
3137 string
= replaceStart(string
, "-");
3138 string
= replaceStart(string
, "\u002d");
3139 string
= replaceStart(string
, "\u2013");
3140 string
= replaceStart(string
, "\u2014");
3141 string
= replaceStart(string
, "--");
3147 * @param replacementString
3149 private String
replaceStart(String value
, String replacementString
) {
3150 if (value
.startsWith(replacementString
) ){
3151 value
= value
.substring(replacementString
.length()).trim();
3153 while (value
.startsWith("-") || value
.startsWith("\u2014") ){
3154 value
= value
.substring("-".length()).trim();
3159 private String
getXmlTag(XMLEvent event
) {
3161 if (event
.isStartElement()) {
3162 result
= "<" + event
.asStartElement().getName().getLocalPart()
3164 } else if (event
.isEndElement()) {
3165 result
= "</" + event
.asEndElement().getName().getLocalPart() + ">";
3167 String message
= "Only start or end elements are allowed as Html tags";
3168 throw new IllegalStateException(message
);
3173 protected static final List
<String
> htmlList
= Arrays
.asList("sub", "sup",
3174 "ol", "ul", "li", "i", "b", "table", "br","tr","td");
3176 private boolean isHtml(XMLEvent event
) {
3177 if (event
.isStartElement()) {
3178 String tag
= event
.asStartElement().getName().getLocalPart();
3179 return htmlList
.contains(tag
);
3180 } else if (event
.isEndElement()) {
3181 String tag
= event
.asEndElement().getName().getLocalPart();
3182 return htmlList
.contains(tag
);
3189 private TextData
handleChar(MarkupImportState state
, XMLEventReader reader
,
3190 XMLEvent parentEvent
) throws XMLStreamException
{
3191 String classValue
= getClassOnlyAttribute(parentEvent
);
3192 Feature feature
= makeFeature(classValue
, state
, parentEvent
);
3194 boolean isTextMode
= true;
3196 while (reader
.hasNext()) {
3197 XMLEvent next
= readNoWhitespace(reader
);
3198 if (isMyEndingElement(next
, parentEvent
)) {
3199 TextData textData
= TextData
.NewInstance(feature
);
3200 textData
.putText(Language
.DEFAULT(), text
);
3202 } else if (isStartingElement(next
, FIGURE_REF
)) {
3204 handleNotYetImplementedElement(next
);
3205 } else if (isEndingElement(next
, FIGURE_REF
)) {
3207 popUnimplemented(next
.asEndElement());
3208 } else if (isStartingElement(next
, FOOTNOTE_REF
)) {
3210 handleNotYetImplementedElement(next
);
3211 } else if (isEndingElement(next
, FOOTNOTE_REF
)) {
3213 popUnimplemented(next
.asEndElement());
3214 } else if (isStartingElement(next
, BR
)) {
3217 } else if (isEndingElement(next
, BR
)) {
3219 } else if (isHtml(next
)) {
3220 text
+= getXmlTag(next
);
3221 } else if (next
.isStartElement()) {
3222 if (isStartingElement(next
, ANNOTATION
)) {
3223 handleNotYetImplementedElement(next
);
3224 } else if (isStartingElement(next
, ITALICS
)) {
3225 handleNotYetImplementedElement(next
);
3226 } else if (isStartingElement(next
, BOLD
)) {
3227 handleNotYetImplementedElement(next
);
3228 } else if (isStartingElement(next
, FIGURE
)) {
3229 handleFigure(state
, reader
, next
);
3230 } else if (isStartingElement(next
, FOOTNOTE
)) {
3231 FootnoteDataHolder footnote
= handleFootnote(state
, reader
, next
);
3232 if (footnote
.isRef()) {
3233 String message
= "Ref footnote not implemented here";
3234 fireWarningEvent(message
, next
, 4);
3236 registerGivenFootnote(state
, footnote
);
3239 handleUnexpectedStartElement(next
.asStartElement());
3241 } else if (next
.isCharacters()) {
3243 String message
= "String is not in text mode";
3244 fireWarningEvent(message
, next
, 6);
3246 text
+= next
.asCharacters().getData();
3249 handleUnexpectedEndElement(next
.asEndElement());
3252 throw new IllegalStateException("RefPart has no closing tag");
3258 * @param parentEvent
3260 * @throws UndefinedTransformerMethodException
3262 private Feature
makeFeature(String classValue
, MarkupImportState state
, XMLEvent parentEvent
) {
3265 Feature feature
= state
.getTransformer().getFeatureByKey(classValue
);
3266 if (feature
!= null) {
3269 uuid
= state
.getTransformer().getFeatureUuid(classValue
);
3272 String message
= "Uuid is not defined for '%s'";
3273 message
= String
.format(message
, classValue
);
3274 fireWarningEvent(message
, parentEvent
, 8);
3276 String featureText
= StringUtils
.capitalize(classValue
);
3278 // TODO eFlora vocabulary
3279 TermVocabulary
<Feature
> voc
= null;
3280 feature
= getFeature(state
, uuid
, featureText
, featureText
, classValue
, voc
);
3281 if (feature
== null) {
3282 throw new NullPointerException(classValue
+ " not recognized as a feature");
3285 } catch (Exception e
) {
3286 String message
= "Could not create feature for %s: %s";
3287 message
= String
.format(message
, classValue
, e
.getMessage());
3288 fireWarningEvent(message
, parentEvent
, 4);
3289 return Feature
.UNKNOWN();