From 65d41694e93cc44e3daaa07ba129c842b1ee6e71 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andreas=20M=C3=BCller?= Date: Tue, 30 Apr 2013 23:05:30 +0000 Subject: [PATCH] created markup nomenclaturalImport and specimen import --- .gitattributes | 1 + .../MarkupDocumentImportNoComponent.java | 1771 ++--------------- .../cdm/io/markup/MarkupImportBase.java | 219 +- .../cdm/io/markup/MarkupKeyImport.java | 1 - .../io/markup/MarkupNomenclatureImport.java | 827 ++++++++ .../cdm/io/markup/MarkupSpecimenImport.java | 436 +++- 6 files changed, 1678 insertions(+), 1577 deletions(-) create mode 100644 cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupNomenclatureImport.java diff --git a/.gitattributes b/.gitattributes index 8e5ea7383e..55cf75aa72 100644 --- a/.gitattributes +++ b/.gitattributes @@ -414,6 +414,7 @@ cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportConfigurator.java cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportState.java -text cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupInputStream.java -text cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupKeyImport.java -text +cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupNomenclatureImport.java -text cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupSpecimenImport.java -text cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupTransformer.java -text cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/UnmatchedLeads.java -text diff --git a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupDocumentImportNoComponent.java b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupDocumentImportNoComponent.java index 449805c9b8..38c2507c4d 100644 --- a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupDocumentImportNoComponent.java +++ b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupDocumentImportNoComponent.java @@ -30,21 +30,10 @@ import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.WordUtils; import org.apache.log4j.Logger; -import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade; -import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType; -import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeCacheStrategy; import eu.etaxonomy.cdm.common.CdmUtils; -import eu.etaxonomy.cdm.ext.geo.GeoServiceArea; -import eu.etaxonomy.cdm.ext.geo.IEditGeoService; -import eu.etaxonomy.cdm.io.common.CdmImportBase; import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException; -import eu.etaxonomy.cdm.io.markup.UnmatchedLeads.UnmatchedLeadsKey; -import eu.etaxonomy.cdm.model.agent.AgentBase; -import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor; -import eu.etaxonomy.cdm.model.agent.Team; import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase; import eu.etaxonomy.cdm.model.common.AnnotatableEntity; import eu.etaxonomy.cdm.model.common.Annotation; @@ -54,13 +43,10 @@ import eu.etaxonomy.cdm.model.common.Extension; import eu.etaxonomy.cdm.model.common.ExtensionType; import eu.etaxonomy.cdm.model.common.Language; import eu.etaxonomy.cdm.model.common.TermVocabulary; -import eu.etaxonomy.cdm.model.common.TimePeriod; import eu.etaxonomy.cdm.model.description.CommonTaxonName; import eu.etaxonomy.cdm.model.description.DescriptionElementBase; import eu.etaxonomy.cdm.model.description.Distribution; import eu.etaxonomy.cdm.model.description.Feature; -import eu.etaxonomy.cdm.model.description.IndividualsAssociation; -import eu.etaxonomy.cdm.model.description.KeyStatement; import eu.etaxonomy.cdm.model.description.PolytomousKey; import eu.etaxonomy.cdm.model.description.PolytomousKeyNode; import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase; @@ -69,38 +55,17 @@ import eu.etaxonomy.cdm.model.description.TaxonDescription; import eu.etaxonomy.cdm.model.description.TextData; import eu.etaxonomy.cdm.model.location.NamedArea; import eu.etaxonomy.cdm.model.location.NamedAreaLevel; -import eu.etaxonomy.cdm.model.location.NamedAreaType; import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity; import eu.etaxonomy.cdm.model.media.Media; import eu.etaxonomy.cdm.model.name.CultivarPlantName; -import eu.etaxonomy.cdm.model.name.HomotypicalGroup; -import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus; -import eu.etaxonomy.cdm.model.name.NomenclaturalCode; -import eu.etaxonomy.cdm.model.name.NomenclaturalStatus; -import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType; import eu.etaxonomy.cdm.model.name.NonViralName; import eu.etaxonomy.cdm.model.name.Rank; -import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus; -import eu.etaxonomy.cdm.model.name.TaxonNameBase; -import eu.etaxonomy.cdm.model.occurrence.Collection; -import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase; -import eu.etaxonomy.cdm.model.occurrence.FieldObservation; -import eu.etaxonomy.cdm.model.occurrence.Specimen; -import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; -import eu.etaxonomy.cdm.model.reference.IArticle; -import eu.etaxonomy.cdm.model.reference.IJournal; import eu.etaxonomy.cdm.model.reference.Reference; import eu.etaxonomy.cdm.model.reference.ReferenceFactory; -import eu.etaxonomy.cdm.model.reference.ReferenceType; import eu.etaxonomy.cdm.model.taxon.Classification; -import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType; import eu.etaxonomy.cdm.model.taxon.Taxon; import eu.etaxonomy.cdm.model.taxon.TaxonNode; -import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException; -import eu.etaxonomy.cdm.strategy.parser.NameTypeParser; -import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl; -import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser; -import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser.TypeInfo; + /** * @author a.mueller @@ -110,40 +75,16 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { private static final Logger logger = Logger.getLogger(MarkupDocumentImportNoComponent.class); private static final boolean CREATE_NEW = true; - private static final boolean IS_IMAGE_GALLERY = true; private static final boolean NO_IMAGE_GALLERY = false; - - private static final String ACCEPTED = "accepted"; - private static final String ACCEPTED_NAME = "acceptedName"; private static final String ADDENDA = "addenda"; - private static final String ALTERNATEPUBTITLE = "alternatepubtitle"; - private static final String ALTERNATIVE_COLLECTION_TYPE_STATUS = "alternativeCollectionTypeStatus"; - private static final String ALTERNATIVE_COLLECTOR = "alternativeCollector"; - private static final String ALTERNATIVE_FIELD_NUM = "alternativeFieldNum"; - private static final String ALTITUDE = "altitude"; - private static final String ANNOTATION = "annotation"; - private static final String AUTHOR = "author"; private static final String BIBLIOGRAPHY = "bibliography"; private static final String BIOGRAPHIES = "biographies"; - private static final String BOLD = "bold"; - private static final String BR = "br"; private static final String CHAR = "char"; - private static final String CITATION = "citation"; - private static final String COLLECTION_AND_TYPE = "collectionAndType"; - private static final String COLLECTION_TYPE_STATUS = "collectionTypeStatus"; - private static final String COLLECTOR = "collector"; - private static final String COLLECTION = "collection"; - private static final String COORDINATES = "coordinates"; - private static final String DATES = "dates"; private static final String DEDICATION = "dedication"; private static final String DEFAULT_MEDIA_URL = "defaultMediaUrl"; - private static final String DESTROYED = "destroyed"; - private static final String DETAILS = "details"; private static final String DISTRIBUTION_LIST = "distributionList"; private static final String DISTRIBUTION_LOCALITY = "distributionLocality"; - private static final String EDITION = "edition"; - private static final String EDITORS = "editors"; private static final String FEATURE = "feature"; private static final String FIGURE = "figure"; private static final String FIGURE_LEGEND = "figureLegend"; @@ -153,85 +94,41 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { private static final String FOOTNOTE = "footnote"; private static final String FOOTNOTE_REF = "footnoteRef"; private static final String FOOTNOTE_STRING = "footnoteString"; - private static final String FIELD_NUM = "fieldNum"; private static final String FREQUENCY = "frequency"; - private static final String FULL_NAME = "fullName"; - private static final String FULL_TYPE = "fullType"; - private static final String GATHERING = "gathering"; private static final String HEADING = "heading"; private static final String HABITAT = "habitat"; private static final String HABITAT_LIST = "habitatList"; - private static final String HOMONYM = "homonym"; - private static final String HOMOTYPES = "homotypes"; private static final String ID = "id"; - private static final String INFRANK = "infrank"; - private static final String INFRAUT = "infraut"; - private static final String INFRPARAUT = "infrparaut"; - private static final String ISSUE = "issue"; - private static final String ITALICS = "italics"; private static final String KEY = "key"; private static final String LIFE_CYCLE_PERIODS = "lifeCyclePeriods"; - private static final String LOCALITY = "locality"; - private static final String LOST = "lost"; private static final String META_DATA = "metaData"; - private static final String NAME = "name"; - private static final String NAME_TYPE = "nameType"; - private static final String NOM = "nom"; private static final String NOMENCLATURE = "nomenclature"; - private static final String NOT_FOUND = "notFound"; - private static final String NOT_SEEN = "notSeen"; - private static final String NOTES = "notes"; - private static final String ORIGINAL_DETERMINATION = "originalDetermination"; - private static final String PAGES = "pages"; - private static final String PARAUT = "paraut"; - private static final String PUBFULLNAME = "pubfullname"; - private static final String PUBLICATION = "publication"; - private static final String PUBNAME = "pubname"; - private static final String PUBTITLE = "pubtitle"; - private static final String PUBTYPE = "pubtype"; private static final String QUOTE = "quote"; private static final String RANK = "rank"; private static final String REF = "ref"; private static final String REF_NUM = "refNum"; - private static final String REF_PART = "refPart"; private static final String REFERENCE = "reference"; private static final String REFERENCES = "references"; private static final String TAXON = "taxon"; private static final String TAXONTITLE = "taxontitle"; private static final String TAXONTYPE = "taxontype"; private static final String TEXT_SECTION = "textSection"; - private static final String TYPE = "type"; - private static final String TYPE_STATUS = "typeStatus"; private static final String TREATMENT = "treatment"; private static final String SERIALS_ABBREVIATIONS = "serialsAbbreviations"; - private static final String SPECIMEN_TYPE = "specimenType"; - private static final String STATUS = "status"; private static final String STRING = "string"; - private static final String SUB_HEADING = "subHeading"; - private static final String SUB_COLLECTION = "subCollection"; - private static final String SYNONYM = "synonym"; - private static final String UNKNOWN = "unknown"; private static final String URL = "url"; - private static final String USAGE = "usage"; - private static final String VOLUME = "volume"; private static final String WRITER = "writer"; - private static final String YEAR = "year"; - - private NonViralNameParserImpl parser = new NonViralNameParserImpl(); - - // TODO make part of state, but state is renewed when invoking the import a - // second time - private UnmatchedLeads unmatchedLeads; - - - private IEditGeoService editGeoService; private MarkupKeyImport keyImport; + private MarkupSpecimenImport specimenImport; + + private MarkupNomenclatureImport nomenclatureImport; public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport) { super(docImport); - this.editGeoService = docImport.getEditGeoService(); keyImport = new MarkupKeyImport(docImport); + specimenImport = new MarkupSpecimenImport(docImport); + nomenclatureImport = new MarkupNomenclatureImport(docImport, keyImport, specimenImport); } public void doInvoke(MarkupImportState state) throws XMLStreamException { @@ -519,7 +416,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } else if (isStartingElement(next, KEY)) { keyImport.handleKey(state, reader, next); } else if (isStartingElement(next, NOMENCLATURE)) { - handleNomenclature(state, reader, next); + nomenclatureImport.handleNomenclature(state, reader, next); hasNomenclature = true; } else if (isStartingElement(next, FEATURE)) { handleFeature(state, reader, next); @@ -529,14 +426,11 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { UUID notesUuid; try { - notesUuid = state.getTransformer().getFeatureUuid( - "notes"); - Feature feature = getFeature(state, notesUuid, "Notes", - "Notes", "note", null); + notesUuid = state.getTransformer().getFeatureUuid("notes"); + Feature feature = getFeature(state, notesUuid, "Notes", "Notes", "note", null); TextData textData = TextData.NewInstance(feature); textData.putText(Language.DEFAULT(), note); - TaxonDescription description = getTaxonDescription( - taxon, null, false, true); + TaxonDescription description = getTaxonDescription(taxon, null, false, true); description.addElement(textData); } catch (UndefinedTransformerMethodException e) { String message = "getFeatureUuid method not yet implemented"; @@ -1084,24 +978,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { return result; } - private void handleNomenclature(MarkupImportState state, - XMLEventReader reader, XMLEvent parentEvent) - throws XMLStreamException { - checkNoAttributes(parentEvent); - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isStartingElement(next, HOMOTYPES)) { - handleHomotypes(state, reader, next.asStartElement()); - } else if (isMyEndingElement(next, parentEvent)) { - return; - } else { - fireSchemaConflictEventExpectedStartTag(HOMOTYPES, reader); - state.setUnsuccessfull(); - } - } - return; - } private String handleFootnoteString(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { boolean isTextMode = true; @@ -1124,7 +1001,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { if (isStartingElement(next, FULL_NAME)) { handleNotYetImplementedElement(next); } else if (isStartingElement(next, GATHERING)) { - text += handleInLineGathering(state, reader, next); + text += specimenImport.handleInLineGathering(state, reader, next); } else if (isStartingElement(next, REFERENCES)) { text += " " + handleInLineReferences(state, reader, next)+ " "; } else if (isStartingElement(next, BR)) { @@ -1151,16 +1028,6 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } - private String handleInLineGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { - DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.FieldObservation); - handleGathering(state, reader, parentEvent, facade); - FieldObservation fieldObservation = facade.innerFieldObservation(); - String result = "%s"; - result = String.format(result, fieldObservation.getUuid(), fieldObservation.getTitleCache()); - save(fieldObservation, state); - return result; - } - private String handleInLineReferences(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { checkNoAttributes(parentEvent); @@ -1182,1338 +1049,216 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } private String handleInLineReference(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException { - Reference reference = handleReference(state, reader, parentEvent); + Reference reference = nomenclatureImport.handleReference(state, reader, parentEvent); String result = "%s"; result = String.format(result, reference.getUuid(), reference.getTitleCache()); save(reference, state); return result; } - private Reference handleReference(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException { - checkNoAttributes(parentEvent); - boolean hasRefPart = false; - Map refMap = new HashMap(); + private void handleFeature(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { + String classValue = getClassOnlyAttribute(parentEvent); + Feature feature = makeFeature(classValue, state, parentEvent); + Taxon taxon = state.getCurrentTaxon(); + TaxonDescription taxonDescription = getTaxonDescription(taxon, state.getConfig().getSourceReference(), NO_IMAGE_GALLERY, CREATE_NEW); + // TextData figureHolderTextData = null; //for use with one TextData for + // all figure only + + boolean isDescription = feature.equals(Feature.DESCRIPTION()); + DescriptionElementBase lastDescriptionElement = null; + while (reader.hasNext()) { XMLEvent next = readNoWhitespace(reader); if (isMyEndingElement(next, parentEvent)) { - checkMandatoryElement(hasRefPart, parentEvent.asStartElement(), - REF_PART); - Reference reference = createReference(state, refMap, next); - return reference; - } else if (isStartingElement(next, REF_PART)) { - handleRefPart(state, reader, next, refMap); - hasRefPart = true; - } else { - handleUnexpectedElement(next); - } - } - // TODO handle missing end element - throw new IllegalStateException(" has no closing tag"); - } - - private void handleHomotypes(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) - throws XMLStreamException { - checkNoAttributes(parentEvent); - - HomotypicalGroup homotypicalGroup = null; + return; + } else if (isEndingElement(next, DISTRIBUTION_LIST) || isEndingElement(next, HABITAT_LIST)) { + // only handle list elements + } else if (isStartingElement(next, HEADING)) { + makeFeatureHeading(state, reader, classValue, feature, next); + } else if (isStartingElement(next, WRITER)) { + makeFeatureWriter(state, reader, feature, taxon, next); +// } else if (isStartingElement(next, DISTRIBUTION_LOCALITY)) { +// if (!feature.equals(Feature.DISTRIBUTION())) { +// String message = "Distribution locality only allowed for feature of type 'distribution'"; +// fireWarningEvent(message, next, 4); +// } +// handleDistributionLocality(state, reader, next); + } else if (isStartingElement(next, DISTRIBUTION_LIST) || isStartingElement(next, HABITAT_LIST)) { + // only handle single list elements + } else if (isStartingElement(next, HABITAT)) { + if (!(feature.equals(Feature.HABITAT()) + || feature.equals(Feature.HABITAT_ECOLOGY()) + || feature.equals(Feature.ECOLOGY()))) { + String message = "Habitat only allowed for feature of type 'habitat','habitat ecology' or 'ecology'"; + fireWarningEvent(message, next, 4); + } + handleHabitat(state, reader, next); + } else if (isStartingElement(next, CHAR)) { + TextData textData = handleChar(state, reader, next); + taxonDescription.addElement(textData); + } else if (isStartingElement(next, STRING)) { + lastDescriptionElement = makeFeatureString(state, reader,feature, taxonDescription, lastDescriptionElement,next); + } else if (isStartingElement(next, FIGURE_REF)) { + lastDescriptionElement = makeFeatureFigureRef(state, reader, taxonDescription, isDescription, lastDescriptionElement, next); + } else if (isStartingElement(next, REFERENCES)) { + // TODO details/microcitation ?? - boolean hasNom = false; - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - checkMandatoryElement(hasNom, parentEvent, NOM); - return; - } else { - if (isEndingElement(next, NAME_TYPE)) { - state.setNameType(false); - } else if (isEndingElement(next, NOTES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); + List> refs = handleReferences(state, reader, next); + if (!refs.isEmpty()) { + // TODO + Reference descriptionRef = state.getConfig().getSourceReference(); + TaxonDescription description = getTaxonDescription(taxon, descriptionRef, false, true); + TextData featurePlaceholder = docImport.getFeaturePlaceholder(state, description, feature, true); + for (Reference citation : refs) { + featurePlaceholder.addSource(null, null, citation, null); } - } - } else if (next.isStartElement()) { - if (isStartingElement(next, NOM)) { - NonViralName name = handleNom(state, reader, next, homotypicalGroup); - homotypicalGroup = name.getHomotypicalGroup(); - hasNom = true; - } else if (isStartingElement(next, NAME_TYPE)) { - state.setNameType(true); - handleNameType(state, reader, next, homotypicalGroup); - } else if (isStartingElement(next, SPECIMEN_TYPE)) { - handleSpecimenType(state, reader, next, homotypicalGroup); - } else if (isStartingElement(next, NOTES)) { - handleNotYetImplementedElement(next); } else { - handleUnexpectedStartElement(next); + String message = "No reference found in references"; + fireWarningEvent(message, next, 6); } + } else if (isStartingElement(next, NUM)) { + //TODO + handleNotYetImplementedElement(next); + } else if (isEndingElement(next, NUM)) { + //TODO + popUnimplemented(next.asEndElement()); } else { handleUnexpectedElement(next); } } - // TODO handle missing end element - throw new IllegalStateException("Homotypes has no closing tag"); - + throw new IllegalStateException(" has no closing tag"); } - private void handleNameType(MarkupImportState state, XMLEventReader reader, - XMLEvent parentEvent, HomotypicalGroup homotypicalGroup) - throws XMLStreamException { - Map attributes = getAttributes(parentEvent); - String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS); - checkNoAttributes(attributes, parentEvent); - - NameTypeDesignationStatus status; - try { - status = NameTypeParser.parseNameTypeStatus(typeStatus); - } catch (UnknownCdmTypeException e) { - String message = "Type status could not be recognized: %s"; - message = String.format(message, typeStatus); - fireWarningEvent(message, parentEvent, 4); - status = null; + /** + * @param state + * @param reader + * @param taxonDescription + * @param isDescription + * @param lastDescriptionElement + * @param next + * @return + * @throws XMLStreamException + */ + private DescriptionElementBase makeFeatureFigureRef(MarkupImportState state, XMLEventReader reader,TaxonDescription taxonDescription, + boolean isDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next)throws XMLStreamException { + FigureDataHolder figureHolder = handleFigureRef(state, reader, next); + Feature figureFeature = getFeature(state,MarkupTransformer.uuidFigures, "Figures", "Figures", "Fig.",null); + if (isDescription) { + TextData figureHolderTextData = null; + // if (figureHolderTextData == null){ + figureHolderTextData = TextData.NewInstance(figureFeature); + if (StringUtils.isNotBlank(figureHolder.num)) { + String annotationText = "" + figureHolder.num.trim() + + ""; + Annotation annotation = Annotation.NewInstance(annotationText, + AnnotationType.TECHNICAL(), Language.DEFAULT()); + figureHolderTextData.addAnnotation(annotation); + } + if (StringUtils.isNotBlank(figureHolder.figurePart)) { + String annotationText = ""+ figureHolder.figurePart.trim() + ""; + Annotation annotation = Annotation.NewInstance(annotationText,AnnotationType.EDITORIAL(), Language.DEFAULT()); + figureHolderTextData.addAnnotation(annotation); + } + // if (StringUtils.isNotBlank(figureText)){ + // figureHolderTextData.putText(Language.DEFAULT(), figureText); + // } + taxonDescription.addElement(figureHolderTextData); + // } + registerFigureDemand(state, figureHolderTextData, figureHolder.ref); + } else { + if (lastDescriptionElement == null) { + String message = "No description element created yet that can be referred by figure. Create new TextData instead"; + fireWarningEvent(message, next, 4); + lastDescriptionElement = TextData.NewInstance(figureFeature); + taxonDescription.addElement(lastDescriptionElement); + } + registerFigureDemand(state, lastDescriptionElement, + figureHolder.ref); } + return lastDescriptionElement; + } - boolean hasNom = false; - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - checkMandatoryElement(hasNom, parentEvent.asStartElement(), - NOM); - state.setNameType(false); - return; - } else { - if (isEndingElement(next, ACCEPTED_NAME)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } + /** + * @param state + * @param reader + * @param feature + * @param taxonDescription + * @param lastDescriptionElement + * @param distributionList + * @param next + * @return + * @throws XMLStreamException + */ + private DescriptionElementBase makeFeatureString(MarkupImportState state,XMLEventReader reader, Feature feature, + TaxonDescription taxonDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next) throws XMLStreamException { + //for specimen only + if (feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.MATERIALS_EXAMINED())){ + + List specimens = specimenImport.handleMaterialsExamined(state, reader, next); + for (DescriptionElementBase specimen : specimens){ + taxonDescription.addElement(specimen); + lastDescriptionElement = specimen; + } + return lastDescriptionElement; + } + + //others + Map subheadingMap = handleString(state, reader, next, feature); + for (String subheading : subheadingMap.keySet()) { + Feature subheadingFeature = feature; + if (StringUtils.isNotBlank(subheading) && subheadingMap.size() > 1) { + subheadingFeature = makeFeature(subheading, state, next); + } + if (feature.equals(Feature.COMMON_NAME())){ + List commonNames = makeVernacular(state, subheading, subheadingMap.get(subheading)); + for (DescriptionElementBase commonName : commonNames){ + taxonDescription.addElement(commonName); + lastDescriptionElement = commonName; } - } else if (next.isStartElement()) { - if (isStartingElement(next, NOM)) { - // TODO should we check if the type is always a species, is - // this a rule? - NonViralName speciesName = handleNom(state, reader, - next, null); - for (TaxonNameBase name : homotypicalGroup - .getTypifiedNames()) { - name.addNameTypeDesignation(speciesName, null, null, - null, status, false, false, false, false); + }else { + TextData textData = TextData.NewInstance(subheadingFeature); + textData.putText(Language.DEFAULT(), subheadingMap.get(subheading)); + taxonDescription.addElement(textData); + lastDescriptionElement = textData; + // TODO how to handle figures when these data are split in + // subheadings + } + } + return lastDescriptionElement; + } + + private List makeVernacular(MarkupImportState state, String subheading, String commonNameString) throws XMLStreamException { + List result = new ArrayList(); + String[] splits = commonNameString.split(","); + for (String split : splits){ + split = split.trim(); + if (! split.matches(".*\\(.*\\)\\.?")){ + fireWarningEvent("Common name string '"+split+"' does not match given pattern", state.getReader().peek(), 4); + } + + String name = split.replaceAll("\\(.*\\)", "").replace(".", "").trim(); + String languageStr = split.replaceFirst(".*\\(", "").replaceAll("\\)\\.?", "").trim(); + + Language language = null; + if (StringUtils.isNotBlank(languageStr)){ + try { + UUID langUuid = state.getTransformer().getLanguageUuid(languageStr); + TermVocabulary voc = null; + language = getLanguage(state, langUuid, languageStr, languageStr, null, voc); + if (language == null){ + logger.warn("Language " + languageStr + " not recognized by transformer"); } - hasNom = true; - } else if (isStartingElement(next, ACCEPTED_NAME)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next); + } catch (UndefinedTransformerMethodException e) { + throw new RuntimeException(e); } - } else { - handleUnexpectedElement(next); } + NamedArea area = null; + CommonTaxonName commonTaxonName = CommonTaxonName.NewInstance(name, language, area); + result.add(commonTaxonName); } - // TODO handle missing end element - throw new IllegalStateException("Homotypes has no closing tag"); - - } - - private void handleSpecimenType(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, - HomotypicalGroup homotypicalGroup) throws XMLStreamException { - // attributes - Map attributes = getAttributes(parentEvent); - String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS); - String notSeen = getAndRemoveAttributeValue(attributes, NOT_SEEN); - String unknown = getAndRemoveAttributeValue(attributes, UNKNOWN); - String notFound = getAndRemoveAttributeValue(attributes, NOT_FOUND); - String destroyed = getAndRemoveAttributeValue(attributes, DESTROYED); - String lost = getAndRemoveAttributeValue(attributes, LOST); - checkNoAttributes(attributes, parentEvent); - if (StringUtils.isNotEmpty(typeStatus)) { - // TODO - // currently not needed - } else if (StringUtils.isNotEmpty(notSeen)) { - handleNotYetImplementedAttribute(attributes, NOT_SEEN); - } else if (StringUtils.isNotEmpty(unknown)) { - handleNotYetImplementedAttribute(attributes, UNKNOWN); - } else if (StringUtils.isNotEmpty(notFound)) { - handleNotYetImplementedAttribute(attributes, NOT_FOUND); - } else if (StringUtils.isNotEmpty(destroyed)) { - handleNotYetImplementedAttribute(attributes, DESTROYED); - } else if (StringUtils.isNotEmpty(lost)) { - handleNotYetImplementedAttribute(attributes, LOST); - } - - NonViralName firstName = null; - Set names = homotypicalGroup.getTypifiedNames(); - if (names.isEmpty()) { - String message = "There is no name in a homotypical group. Can't create the specimen type"; - fireWarningEvent(message, parentEvent, 8); - } else { - firstName = CdmBase.deproxy(names.iterator().next(),NonViralName.class); - } - - DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.Specimen); - String text = ""; - // elements - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - makeSpecimenType(state, facade, text, firstName, parentEvent); - return; - } else { - if (isEndingElement(next, FULL_TYPE)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, TYPE_STATUS)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, ORIGINAL_DETERMINATION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, SPECIMEN_TYPE)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, COLLECTION_AND_TYPE)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, CITATION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, NOTES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, ANNOTATION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - } else if (next.isStartElement()) { - if (isStartingElement(next, FULL_TYPE)) { - handleNotYetImplementedElement(next); - // homotypicalGroup = handleNom(state, reader, next, taxon, - // homotypicalGroup); - } else if (isStartingElement(next, TYPE_STATUS)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, GATHERING)) { - handleGathering(state, reader, next, facade); - } else if (isStartingElement(next, ORIGINAL_DETERMINATION)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, SPECIMEN_TYPE)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, COLLECTION_AND_TYPE)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, CITATION)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, NOTES)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, ANNOTATION)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next); - } - } else if (next.isCharacters()) { - text += next.asCharacters().getData(); - } else { - handleUnexpectedElement(next); - } - } - // TODO handle missing end element - throw new IllegalStateException("Specimen type has no closing tag"); - } - - private void makeSpecimenType(MarkupImportState state, DerivedUnitFacade facade, String text, - NonViralName name, XMLEvent parentEvent) { - text = text.trim(); - // remove brackets - if (text.matches("^\\(.*\\)\\.?$")) { - text = text.replaceAll("\\.", ""); - text = text.substring(1, text.length() - 1); - } - String[] split = text.split("[;,]"); - for (String str : split) { - str = str.trim(); - boolean addToAllNamesInGroup = true; - TypeInfo typeInfo = makeSpecimenTypeTypeInfo(str, parentEvent); - SpecimenTypeDesignationStatus typeStatus = typeInfo.status; - Collection collection = createCollection(typeInfo.collectionString); - - // TODO improve cache strategy handling - DerivedUnitBase typeSpecimen = facade.addDuplicate(collection, - null, null, null, null); - typeSpecimen.setCacheStrategy(new DerivedUnitFacadeCacheStrategy()); - name.addSpecimenTypeDesignation((Specimen) typeSpecimen, typeStatus, null, null, null, false, addToAllNamesInGroup); - } - } - - private Collection createCollection(String code) { - // TODO deduplicate - // TODO code <-> name - Collection result = Collection.NewInstance(); - result.setCode(code); - return result; - } - - private TypeInfo makeSpecimenTypeTypeInfo(String originalString, XMLEvent event) { - TypeInfo result = new TypeInfo(); - String[] split = originalString.split("\\s+"); - for (String str : split) { - if (str.matches(SpecimenTypeParser.typeTypePattern)) { - SpecimenTypeDesignationStatus status; - try { - status = SpecimenTypeParser.parseSpecimenTypeStatus(str); - } catch (UnknownCdmTypeException e) { - String message = "Specimen type status '%s' not recognized by parser"; - message = String.format(message, str); - fireWarningEvent(message, event, 4); - status = null; - } - result.status = status; - } else if (str.matches(SpecimenTypeParser.collectionPattern)) { - result.collectionString = str; - } else { - String message = "Type part '%s' could not be recognized"; - message = String.format(message, str); - fireWarningEvent(message, event, 2); - } - } - - return result; - } - - - private void handleGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent , DerivedUnitFacade facade) throws XMLStreamException { - checkNoAttributes(parentEvent); - boolean hasCollector = false; - boolean hasFieldNum = false; - - // elements - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - checkMandatoryElement(hasCollector,parentEvent.asStartElement(), COLLECTOR); - checkMandatoryElement(hasFieldNum,parentEvent.asStartElement(), FIELD_NUM); - return; - } else { - if (isEndingElement(next, ALTERNATIVE_COLLECTOR)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, ALTERNATIVE_FIELD_NUM)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, COLLECTION_TYPE_STATUS)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, COLLECTION_AND_TYPE)) { - // NOT YET IMPLEMENTED , does this make sense here? - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, - ALTERNATIVE_COLLECTION_TYPE_STATUS)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, SUB_COLLECTION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, COLLECTION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, DATES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, NOTES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - } else if (next.isStartElement()) { - if (isStartingElement(next, COLLECTOR)) { - hasCollector = true; - String collectorStr = getCData(state, reader, next); - AgentBase collector = createCollector(collectorStr); - facade.setCollector(collector); - } else if (isStartingElement(next, ALTERNATIVE_COLLECTOR)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, FIELD_NUM)) { - hasFieldNum = true; - String fieldNumStr = getCData(state, reader, next); - facade.setFieldNumber(fieldNumStr); - } else if (isStartingElement(next, ALTERNATIVE_FIELD_NUM)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, COLLECTION_TYPE_STATUS)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, COLLECTION_AND_TYPE)) { //does this make sense here? - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, ALTERNATIVE_COLLECTION_TYPE_STATUS)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, SUB_COLLECTION)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, COLLECTION)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, LOCALITY)) { - handleLocality(state, reader, next, facade); - } else if (isStartingElement(next, DATES)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, NOTES)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next); - } - } else { - handleUnexpectedElement(next); - } - } - // TODO handle missing end element - throw new IllegalStateException("Collection has no closing tag"); - - } - - private void handleLocality(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, DerivedUnitFacade facade)throws XMLStreamException { - String classValue = getClassOnlyAttribute(parentEvent); - boolean isLocality = false; - NamedAreaLevel areaLevel = null; - if ("locality".equalsIgnoreCase(classValue)) { - isLocality = true; - } else { - areaLevel = makeNamedAreaLevel(state, classValue, parentEvent); - } - - String text = ""; - // elements - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - if (StringUtils.isNotBlank(text)) { - text = normalize(text); - if (isLocality) { - facade.setLocality(text); - } else { - text = CdmUtils.removeTrailingDot(text); - NamedArea area = makeArea(state, text, areaLevel); - facade.addCollectingArea(area); - } - } - // TODO - return; - } else { - if (isEndingElement(next, ALTITUDE)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, COORDINATES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, ANNOTATION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - } else if (next.isStartElement()) { - if (isStartingElement(next, ALTITUDE)) { - handleNotYetImplementedElement(next); - // homotypicalGroup = handleNom(state, reader, next, taxon, - // homotypicalGroup); - } else if (isStartingElement(next, COORDINATES)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, ANNOTATION)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next); - } - } else if (next.isCharacters()) { - text += next.asCharacters().getData(); - } else { - handleUnexpectedElement(next); - } - } - throw new IllegalStateException(" has no closing tag"); - } - -// private NamedArea createArea(String text, NamedAreaLevel areaLevel, MarkupImportState state) { -// NamedArea area = NamedArea.NewInstance(text, text, null); -// area.setLevel(areaLevel); -// save(area, state); -// return area; -// } - - private AgentBase createCollector(String collectorStr) { - return createAuthor(collectorStr); - } - - /** - * Creates the name defined by a nom tag. Adds it to the given homotypical - * group (if not null). - * - * @param state - * @param reader - * @param parentEvent - * @param homotypicalGroup - * @return - * @throws XMLStreamException - */ - private NonViralName handleNom(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, - HomotypicalGroup homotypicalGroup) throws XMLStreamException { - boolean isSynonym = false; - boolean isNameType = state.isNameType(); - // attributes - String classValue = getClassOnlyAttribute(parentEvent); - NonViralName name; - if (!isNameType && ACCEPTED.equalsIgnoreCase(classValue)) { - isSynonym = false; - name = createName(state, homotypicalGroup, isSynonym); - } else if (!isNameType && SYNONYM.equalsIgnoreCase(classValue)) { - isSynonym = true; - name = createName(state, homotypicalGroup, isSynonym); - } else if (isNameType && NAME_TYPE.equalsIgnoreCase(classValue)) { - // TODO do we need to define the rank here? - name = createNameByCode(state, null); - } else { - fireUnexpectedAttributeValue(parentEvent, CLASS, classValue); - name = createNameByCode(state, null); - } - - Map nameMap = new HashMap(); - - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (next.isEndElement()) { - if (isMyEndingElement(next, parentEvent)) { - // fill the name with all data gathered - fillName(state, nameMap, name, next); - return name; - } else { - if (isEndingElement(next, FULL_NAME)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, HOMONYM)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, NOTES)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else if (isEndingElement(next, ANNOTATION)) { - // NOT YET IMPLEMENTED - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - } else if (next.isStartElement()) { - if (isStartingElement(next, FULL_NAME)) { - handleNotYetImplementedElement(next); - // homotypicalGroup = handleNom(state, reader, next, taxon, - // homotypicalGroup); - } else if (isStartingElement(next, NUM)) { - String num = getCData(state, reader, next); - num = num.replace(".", ""); - num = num.replace(")", ""); - if (StringUtils.isNotBlank(num)){ - if (state.getCurrentTaxonNum() != null && ! state.getCurrentTaxonNum().equals(num) ){ - String message = "Taxontitle num and homotypes/nom/num differ ( %s <-> %s ). I use the later one."; - message = String.format(message, state.getCurrentTaxonNum(), num); - fireWarningEvent(message, next, 4); - } - state.setCurrentTaxonNum(num); - } - } else if (isStartingElement(next, NAME)) { - handleName(state, reader, next, nameMap); - } else if (isStartingElement(next, CITATION)) { - handleCitation(state, reader, next, name); - } else if (isStartingElement(next, HOMONYM)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, NOTES)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, ANNOTATION)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next); - } - } else { - handleUnexpectedElement(next); - } - } - // TODO handle missing end element - throw new IllegalStateException("Nom has no closing tag"); - - } - - private void fillName(MarkupImportState state, Map nameMap, - NonViralName name, XMLEvent event) { - - // Ranks: family, subfamily, tribus, genus, subgenus, section, - // subsection, species, subspecies, variety, subvariety, forma - // infrank, paraut, author, infrparaut, infraut, status, notes - - String infrank = getAndRemoveMapKey(nameMap, INFRANK); - String authorStr = getAndRemoveMapKey(nameMap, AUTHOR); - String paraut = getAndRemoveMapKey(nameMap, PARAUT); - - String infrParAut = getAndRemoveMapKey(nameMap, INFRPARAUT); - String infrAut = getAndRemoveMapKey(nameMap, INFRAUT); - - String statusStr = getAndRemoveMapKey(nameMap, STATUS); - String notes = getAndRemoveMapKey(nameMap, NOTES); - - makeRankDecision(state, nameMap, name, event, infrank); - - // test consistency of rank and authors - testRankAuthorConsistency(name, event, authorStr, paraut, infrParAut,infrAut); - - // authors - makeNomenclaturalAuthors(name, event, authorStr, paraut, infrParAut,infrAut); - - // status - // TODO handle pro parte, pro syn. etc. - if (StringUtils.isNotBlank(statusStr)) { - String proPartePattern = "(pro parte|p.p.)"; - if (statusStr.matches(proPartePattern)) { - state.setProParte(true); - } - try { - // TODO handle trim earlier - statusStr = statusStr.trim(); - NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(statusStr); - name.addStatus(NomenclaturalStatus.NewInstance(nomStatusType)); - } catch (UnknownCdmTypeException e) { - String message = "Status '%s' could not be recognized"; - message = String.format(message, statusStr); - fireWarningEvent(message, event, 4); - } - } - - // notes - if (StringUtils.isNotBlank(notes)) { - handleNotYetImplementedAttributeValue(event, CLASS, NOTES); - } - - return; - } - - /** - * @param state - * @param nameMap - * @param name - * @param event - * @param infrankStr - */ - private void makeRankDecision(MarkupImportState state, Map nameMap, - NonViralName name, XMLEvent event, String infrankStr) { - // TODO ranks - for (String key : nameMap.keySet()) { - Rank rank = makeRank(state, key, false); - if (rank == null) { - handleNotYetImplementedAttributeValue(event, CLASS, key); - } else { - if (name.getRank() == null || rank.isLower(name.getRank())) { - name.setRank(rank); - } - String value = nameMap.get(key); - if (rank.isSupraGeneric() || rank.isGenus()) { - name.setGenusOrUninomial(toFirstCapital(value)); - } else if (rank.isInfraGeneric()) { - name.setInfraGenericEpithet(toFirstCapital(value)); - } else if (rank.isSpecies()) { - if (isFirstCapitalWord(value)){ //capital letters are allowed for species epithet in case of person names (e.g. Manilkara Welwitschii Engl. - name.setSpecificEpithet(value); - }else{ - name.setSpecificEpithet(value.toLowerCase()); - } - } else if (rank.isInfraSpecific()) { - name.setInfraSpecificEpithet(value.toLowerCase()); - } else { - String message = "Invalid rank '%s'. Can't decide which epithet to fill with '%s'"; - message = String.format(message, rank.getTitleCache(),value); - fireWarningEvent(message, event, 4); - } - } - - } - // handle given infrank marker - if (StringUtils.isNotBlank(infrankStr)) { - Rank infRank = makeRank(state, infrankStr, true); - - if (infRank == null) { - String message = "Infrank '%s' rank not recognized"; - message = String.format(message, infrankStr); - fireWarningEvent(message, event, 4); - } else { - if (name.getRank() == null) { - name.setRank(infRank); - } else if (infRank.isLower(name.getRank())) { - String message = "InfRank '%s' is lower than existing rank "; - message = String.format(message, infrankStr); - fireWarningEvent(message, event, 2); - name.setRank(infRank); - } else if (infRank.equals(name.getRank())) { - // nothing - } else { - String message = "InfRank '%s' is higher than existing rank "; - message = String.format(message, infrankStr); - fireWarningEvent(message, event, 2); - } - } - } - } - - private String toFirstCapital(String value) { - if (StringUtils.isBlank(value)){ - return value; - }else{ - String result = ""; - value = value.trim(); - result += value.trim().substring(0,1).toUpperCase(); - if (value.length()>1){ - result += value.substring(1).toLowerCase(); - } - return result; - } - } - - /** - * @param name - * @param event - * @param authorStr - * @param paraut - * @param infrParAut - * @param infrAut - */ - private void makeNomenclaturalAuthors(NonViralName name, XMLEvent event, - String authorStr, String paraut, String infrParAut, String infrAut) { - if (name.getRank() != null && name.getRank().isInfraSpecific()) { - if (StringUtils.isNotBlank(infrAut)) { - INomenclaturalAuthor[] authorAndEx = authorAndEx(infrAut, event); - name.setCombinationAuthorTeam(authorAndEx[0]); - name.setExCombinationAuthorTeam(authorAndEx[1]); - } - if (StringUtils.isNotBlank(infrParAut)) { - INomenclaturalAuthor[] authorAndEx = authorAndEx(infrParAut, event); - name.setBasionymAuthorTeam(authorAndEx[0]); - name.setExBasionymAuthorTeam(authorAndEx[1]); - } - } else { - if (name.getRank() == null){ - String message = "No rank defined. Check correct usage of authors!"; - fireWarningEvent(message, event, 4); - if (isNotBlank(infrParAut) || isNotBlank(infrAut)){ - authorStr = infrAut; - paraut = infrParAut; - } - } - if (StringUtils.isNotBlank(authorStr)) { - INomenclaturalAuthor[] authorAndEx = authorAndEx(authorStr, event); - name.setCombinationAuthorTeam(authorAndEx[0]); - name.setExCombinationAuthorTeam(authorAndEx[1]); - } - if (StringUtils.isNotBlank(paraut)) { - INomenclaturalAuthor[] authorAndEx = authorAndEx(paraut, event); - name.setBasionymAuthorTeam(authorAndEx[0]); - name.setExBasionymAuthorTeam(authorAndEx[1]); - } - } - } - - private TeamOrPersonBase[] authorAndEx(String authorAndEx, XMLEvent xmlEvent) { - authorAndEx = authorAndEx.trim(); - TeamOrPersonBase[] result = new TeamOrPersonBase[2]; - - String[] split = authorAndEx.split("\\sex\\s"); - if (split.length > 2) { - String message = "There is more then 1 ' ex ' in author string. Can't separate author and ex-author"; - fireWarningEvent(message, xmlEvent, 4); - result[0] = createAuthor(authorAndEx); - } else if (split.length == 2) { - result[0] = createAuthor(split[1]); - result[1] = createAuthor(split[0]); - } else { - result[0] = createAuthor(split[0]); - } - return result; - } - - /** - * Tests if the names rank is consistent with the given author strings. - * @param name - * @param event - * @param authorStr - * @param paraut - * @param infrParAut - * @param infrAut - */ - private void testRankAuthorConsistency(NonViralName name, XMLEvent event, - String authorStr, String paraut, String infrParAut, String infrAut) { - if (name.getRank() == null){ - return; - } - if (name.getRank().isInfraSpecific()) { - if (StringUtils.isBlank(infrParAut) - && StringUtils.isBlank(infrAut) //was isNotBlank before 29.5.2012 - && (StringUtils.isNotBlank(paraut) || StringUtils.isNotBlank(authorStr)) - && ! name.isAutonym()) { - String message = "Rank is infraspecicific but has only specific or higher author(s)"; - fireWarningEvent(message, event, 4); - } - } else { - // is not infraspecific - if (StringUtils.isNotBlank(infrParAut) || StringUtils.isNotBlank(infrAut)) { - String message = "Rank is not infraspecicific but name has infra author(s)"; - fireWarningEvent(message, event, 4); - } - } - } - - /** - * Returns the (empty) name with the correct homotypical group depending on - * the taxon status. Throws NPE if no currentTaxon is set in state. - * - * @param state - * @param homotypicalGroup - * @param isSynonym - * @return - */ - private NonViralName createName(MarkupImportState state, - HomotypicalGroup homotypicalGroup, boolean isSynonym) { - NonViralName name; - Taxon taxon = state.getCurrentTaxon(); - if (isSynonym) { - Rank defaultRank = Rank.SPECIES(); // can be any - name = createNameByCode(state, defaultRank); - if (homotypicalGroup != null) { - name.setHomotypicalGroup(homotypicalGroup); - } - SynonymRelationshipType synonymType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(); - if (taxon.getHomotypicGroup().equals(homotypicalGroup)) { - synonymType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(); - } - taxon.addSynonymName(name, synonymType); - } else { - name = CdmBase.deproxy(taxon.getName(), NonViralName.class); - } - return name; - } - - private void handleName(MarkupImportState state, XMLEventReader reader, - XMLEvent parentEvent, Map nameMap) - throws XMLStreamException { - String classValue = getClassOnlyAttribute(parentEvent); - - String text = ""; - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isMyEndingElement(next, parentEvent)) { - nameMap.put(classValue, text); - return; - } else if (next.isStartElement()) { - if (isStartingElement(next, ANNOTATION)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next.asStartElement()); - } - } else if (next.isCharacters()) { - text += next.asCharacters().getData(); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - throw new IllegalStateException("name has no closing tag"); - - } - - /** - * @param state - * @param classValue - * @param byAbbrev - * @return - */ - private Rank makeRank(MarkupImportState state, String value, - boolean byAbbrev) { - Rank rank = null; - if (StringUtils.isBlank(value)) { - return null; - } - try { - boolean useUnknown = true; - NomenclaturalCode nc = makeNomenclaturalCode(state); - if (byAbbrev) { - rank = Rank.getRankByAbbreviation(value, nc, useUnknown); - } else { - rank = Rank.getRankByEnglishName(value, nc, useUnknown); - } - if (rank.equals(Rank.UNKNOWN_RANK())) { - rank = null; - } - } catch (UnknownCdmTypeException e) { - // doNothing - } - return rank; - } - - // public void handleNameNotRank(MarkupImportState state, XMLEventReader - // reader, XMLEvent parentEvent, String classValue, NonViralName name) - // throws XMLStreamException { - // if (ACCEPTED.equalsIgnoreCase(classValue)){ - // }else if (SYNONYM.equalsIgnoreCase(classValue)){ - // }else{ - // //TODO Not yet implemented - // handleNotYetImplementedAttributeValue(parentEvent, CLASS, classValue); - // } - // } - - private void handleCitation(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, NonViralName name) throws XMLStreamException { - String classValue = getClassOnlyAttribute(parentEvent); - - state.setCitation(true); - boolean hasRefPart = false; - Map refMap = new HashMap(); - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isMyEndingElement(next, parentEvent)) { - checkMandatoryElement(hasRefPart, parentEvent.asStartElement(), - REF_PART); - Reference reference = createReference(state, refMap, next); - String microReference = refMap.get(DETAILS); - doCitation(state, name, classValue, reference, microReference, - parentEvent); - state.setCitation(false); - return; - } else if (isStartingElement(next, REF_PART)) { - handleRefPart(state, reader, next, refMap); - hasRefPart = true; - } else { - handleUnexpectedElement(next); - } - } - throw new IllegalStateException("Citation has no closing tag"); - - } - - private void handleRefPart(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, Map refMap) throws XMLStreamException { - String classValue = getClassOnlyAttribute(parentEvent); - - String text = ""; - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isMyEndingElement(next, parentEvent)) { - refMap.put(classValue, text); - return; - } else if (next.isStartElement()) { - if (isStartingElement(next, ANNOTATION)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, ITALICS)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, BOLD)) { - handleNotYetImplementedElement(next); - } else { - handleUnexpectedStartElement(next.asStartElement()); - } - } else if (next.isCharacters()) { - text += next.asCharacters().getData(); - } else { - handleUnexpectedEndElement(next.asEndElement()); - } - } - throw new IllegalStateException("RefPart has no closing tag"); - - } - - private Reference createReference(MarkupImportState state, Map refMap, XMLEvent parentEvent) { - // TODO - Reference reference; - - String type = getAndRemoveMapKey(refMap, PUBTYPE); - String authorStr = getAndRemoveMapKey(refMap, AUTHOR); - String titleStr = getAndRemoveMapKey(refMap, PUBTITLE); - String titleCache = getAndRemoveMapKey(refMap, PUBFULLNAME); - String volume = getAndRemoveMapKey(refMap, VOLUME); - String edition = getAndRemoveMapKey(refMap, EDITION); - String editors = getAndRemoveMapKey(refMap, EDITORS); - String year = getAndRemoveMapKey(refMap, YEAR); - String pubName = getAndRemoveMapKey(refMap, PUBNAME); - String pages = getAndRemoveMapKey(refMap, PAGES); - - if (state.isCitation()) { - if (volume != null || "journal".equalsIgnoreCase(type)) { - IArticle article = ReferenceFactory.newArticle(); - if (pubName != null) { - IJournal journal = ReferenceFactory.newJournal(); - journal.setTitle(pubName); - article.setInJournal(journal); - } - reference = (Reference) article; - - } else { - // TODO - if (pubName != null){ - reference = ReferenceFactory.newBookSection(); - }else{ - reference = ReferenceFactory.newBook(); - } - } - // TODO use existing author from name or before - TeamOrPersonBase author = createAuthor(authorStr); - reference.setAuthorTeam(author); - - reference.setTitle(titleStr); - if (StringUtils.isNotBlank(titleCache)) { - reference.setTitleCache(titleCache, true); - } - reference.setEdition(edition); - reference.setEditor(editors); - - if (pubName != null) { - Reference inReference; - if (reference.getType().equals(ReferenceType.Article)) { - inReference = ReferenceFactory.newJournal(); - } else { - inReference = ReferenceFactory.newGeneric(); - } - inReference.setTitle(pubName); - reference.setInReference(inReference); - } - - - } else { //no citation - if (volume != null || "journal".equalsIgnoreCase(type)) { - IArticle article = ReferenceFactory.newArticle(); - if (pubName != null) { - IJournal journal = ReferenceFactory.newJournal(); - journal.setTitle(pubName); - article.setInJournal(journal); - } - reference = (Reference) article; - - } else { - Reference bookOrPartOf = ReferenceFactory.newGeneric(); - reference = bookOrPartOf; - } - - // TODO type - TeamOrPersonBase author = createAuthor(authorStr); - reference.setAuthorTeam(author); - - reference.setTitle(titleStr); - if (StringUtils.isNotBlank(titleCache)) { - reference.setTitleCache(titleCache, true); - } - reference.setEdition(edition); - reference.setEditor(editors); - - if (pubName != null) { - Reference inReference; - if (reference.getType().equals(ReferenceType.Article)) { - inReference = ReferenceFactory.newJournal(); - } else { - inReference = ReferenceFactory.newGeneric(); - } - inReference.setTitle(pubName); - reference.setInReference(inReference); - } - } - reference.setVolume(volume); - reference.setDatePublished(TimePeriod.parseString(year)); - //TODO check if this is handled correctly in FM markup - reference.setPages(pages); - - // TODO - String[] unhandledList = new String[]{ALTERNATEPUBTITLE, ISSUE, NOTES, STATUS}; - for (String unhandled : unhandledList){ - String value = getAndRemoveMapKey(refMap, unhandled); - if (isNotBlank(value)){ - this.handleNotYetImplementedAttributeValue(parentEvent, CLASS, unhandled); - } - } - - for (String key : refMap.keySet()) { - if (!DETAILS.equalsIgnoreCase(key)) { - this.fireUnexpectedAttributeValue(parentEvent, CLASS, key); - } - } - - return reference; - } - - private TeamOrPersonBase createAuthor(String authorTitle) { - // TODO atomize and also use by name creation - TeamOrPersonBase result = Team.NewTitledInstance(authorTitle, - authorTitle); - return result; - } - - private String getAndRemoveMapKey(Map map, String key) { - String result = map.get(key); - map.remove(key); - if (result != null) { - result = normalize(result); - } - return StringUtils.stripToNull(result); - } - - private void doCitation(MarkupImportState state, NonViralName name, - String classValue, Reference reference, String microCitation, - XMLEvent parentEvent) { - if (PUBLICATION.equalsIgnoreCase(classValue)) { - name.setNomenclaturalReference(reference); - name.setNomenclaturalMicroReference(microCitation); - } else if (USAGE.equalsIgnoreCase(classValue)) { - Taxon taxon = state.getCurrentTaxon(); - TaxonDescription td = getTaxonDescription(taxon, state - .getConfig().getSourceReference(), false, true); - TextData citation = TextData.NewInstance(Feature.CITATION()); - // TODO name used in source - citation.addSource(null, null, reference, microCitation); - td.addElement(citation); - } else if (TYPE.equalsIgnoreCase(classValue)) { - handleNotYetImplementedAttributeValue(parentEvent, CLASS, - classValue); - } else { - // TODO Not yet implemented - handleNotYetImplementedAttributeValue(parentEvent, CLASS, - classValue); - } - } - - private void handleFeature(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { - String classValue = getClassOnlyAttribute(parentEvent); - Feature feature = makeFeature(classValue, state, parentEvent); - Taxon taxon = state.getCurrentTaxon(); - TaxonDescription taxonDescription = getTaxonDescription(taxon, state.getConfig().getSourceReference(), NO_IMAGE_GALLERY, CREATE_NEW); - // TextData figureHolderTextData = null; //for use with one TextData for - // all figure only - - boolean isDescription = feature.equals(Feature.DESCRIPTION()); - DescriptionElementBase lastDescriptionElement = null; - - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isMyEndingElement(next, parentEvent)) { - return; - } else if (isEndingElement(next, DISTRIBUTION_LIST) || isEndingElement(next, HABITAT_LIST)) { - // only handle list elements - } else if (isStartingElement(next, HEADING)) { - makeFeatureHeading(state, reader, classValue, feature, next); - } else if (isStartingElement(next, WRITER)) { - makeFeatureWriter(state, reader, feature, taxon, next); -// } else if (isStartingElement(next, DISTRIBUTION_LOCALITY)) { -// if (!feature.equals(Feature.DISTRIBUTION())) { -// String message = "Distribution locality only allowed for feature of type 'distribution'"; -// fireWarningEvent(message, next, 4); -// } -// handleDistributionLocality(state, reader, next); - } else if (isStartingElement(next, DISTRIBUTION_LIST) || isStartingElement(next, HABITAT_LIST)) { - // only handle single list elements - } else if (isStartingElement(next, HABITAT)) { - if (!(feature.equals(Feature.HABITAT()) - || feature.equals(Feature.HABITAT_ECOLOGY()) - || feature.equals(Feature.ECOLOGY()))) { - String message = "Habitat only allowed for feature of type 'habitat','habitat ecology' or 'ecology'"; - fireWarningEvent(message, next, 4); - } - handleHabitat(state, reader, next); - } else if (isStartingElement(next, CHAR)) { - TextData textData = handleChar(state, reader, next); - taxonDescription.addElement(textData); - } else if (isStartingElement(next, STRING)) { - lastDescriptionElement = makeFeatureString(state, reader,feature, taxonDescription, lastDescriptionElement,next); - } else if (isStartingElement(next, FIGURE_REF)) { - lastDescriptionElement = makeFeatureFigureRef(state, reader, taxonDescription, isDescription, lastDescriptionElement, next); - } else if (isStartingElement(next, REFERENCES)) { - // TODO details/microcitation ?? - - List> refs = handleReferences(state, reader, next); - if (!refs.isEmpty()) { - // TODO - Reference descriptionRef = state.getConfig().getSourceReference(); - TaxonDescription description = getTaxonDescription(taxon, descriptionRef, false, true); - TextData featurePlaceholder = docImport.getFeaturePlaceholder(state, description, feature, true); - for (Reference citation : refs) { - featurePlaceholder.addSource(null, null, citation, null); - } - } else { - String message = "No reference found in references"; - fireWarningEvent(message, next, 6); - } - } else if (isStartingElement(next, NUM)) { - //TODO - handleNotYetImplementedElement(next); - } else if (isEndingElement(next, NUM)) { - //TODO - popUnimplemented(next.asEndElement()); - } else { - handleUnexpectedElement(next); - } - } - throw new IllegalStateException(" has no closing tag"); - } - - /** - * @param state - * @param reader - * @param taxonDescription - * @param isDescription - * @param lastDescriptionElement - * @param next - * @return - * @throws XMLStreamException - */ - private DescriptionElementBase makeFeatureFigureRef(MarkupImportState state, XMLEventReader reader,TaxonDescription taxonDescription, - boolean isDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next)throws XMLStreamException { - FigureDataHolder figureHolder = handleFigureRef(state, reader, next); - Feature figureFeature = getFeature(state,MarkupTransformer.uuidFigures, "Figures", "Figures", "Fig.",null); - if (isDescription) { - TextData figureHolderTextData = null; - // if (figureHolderTextData == null){ - figureHolderTextData = TextData.NewInstance(figureFeature); - if (StringUtils.isNotBlank(figureHolder.num)) { - String annotationText = "" + figureHolder.num.trim() - + ""; - Annotation annotation = Annotation.NewInstance(annotationText, - AnnotationType.TECHNICAL(), Language.DEFAULT()); - figureHolderTextData.addAnnotation(annotation); - } - if (StringUtils.isNotBlank(figureHolder.figurePart)) { - String annotationText = ""+ figureHolder.figurePart.trim() + ""; - Annotation annotation = Annotation.NewInstance(annotationText,AnnotationType.EDITORIAL(), Language.DEFAULT()); - figureHolderTextData.addAnnotation(annotation); - } - // if (StringUtils.isNotBlank(figureText)){ - // figureHolderTextData.putText(Language.DEFAULT(), figureText); - // } - taxonDescription.addElement(figureHolderTextData); - // } - registerFigureDemand(state, figureHolderTextData, figureHolder.ref); - } else { - if (lastDescriptionElement == null) { - String message = "No description element created yet that can be referred by figure. Create new TextData instead"; - fireWarningEvent(message, next, 4); - lastDescriptionElement = TextData.NewInstance(figureFeature); - taxonDescription.addElement(lastDescriptionElement); - } - registerFigureDemand(state, lastDescriptionElement, - figureHolder.ref); - } - return lastDescriptionElement; - } - - /** - * @param state - * @param reader - * @param feature - * @param taxonDescription - * @param lastDescriptionElement - * @param distributionList - * @param next - * @return - * @throws XMLStreamException - */ - private DescriptionElementBase makeFeatureString(MarkupImportState state,XMLEventReader reader, Feature feature, - TaxonDescription taxonDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next) throws XMLStreamException { - //for specimen only - if (feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.MATERIALS_EXAMINED())){ - - List specimens = handleMaterialsExamined(state, reader, next); - for (DescriptionElementBase specimen : specimens){ - taxonDescription.addElement(specimen); - lastDescriptionElement = specimen; - } - return lastDescriptionElement; - } - - //others - Map subheadingMap = handleString(state, reader, next, feature); - for (String subheading : subheadingMap.keySet()) { - Feature subheadingFeature = feature; - if (StringUtils.isNotBlank(subheading) && subheadingMap.size() > 1) { - subheadingFeature = makeFeature(subheading, state, next); - } - if (feature.equals(Feature.COMMON_NAME())){ - List commonNames = makeVernacular(state, subheading, subheadingMap.get(subheading)); - for (DescriptionElementBase commonName : commonNames){ - taxonDescription.addElement(commonName); - lastDescriptionElement = commonName; - } - }else { - TextData textData = TextData.NewInstance(subheadingFeature); - textData.putText(Language.DEFAULT(), subheadingMap.get(subheading)); - taxonDescription.addElement(textData); - lastDescriptionElement = textData; - // TODO how to handle figures when these data are split in - // subheadings - } - } - return lastDescriptionElement; - } - - private List makeVernacular(MarkupImportState state, String subheading, String commonNameString) throws XMLStreamException { - List result = new ArrayList(); - String[] splits = commonNameString.split(","); - for (String split : splits){ - split = split.trim(); - if (! split.matches(".*\\(.*\\)\\.?")){ - fireWarningEvent("Common name string '"+split+"' does not match given pattern", state.getReader().peek(), 4); - } - - String name = split.replaceAll("\\(.*\\)", "").replace(".", "").trim(); - String languageStr = split.replaceFirst(".*\\(", "").replaceAll("\\)\\.?", "").trim(); - - Language language = null; - if (StringUtils.isNotBlank(languageStr)){ - try { - UUID langUuid = state.getTransformer().getLanguageUuid(languageStr); - TermVocabulary voc = null; - language = getLanguage(state, langUuid, languageStr, languageStr, null, voc); - if (language == null){ - logger.warn("Language " + languageStr + " not recognized by transformer"); - } - } catch (UndefinedTransformerMethodException e) { - throw new RuntimeException(e); - } - } - NamedArea area = null; - CommonTaxonName commonTaxonName = CommonTaxonName.NewInstance(name, language, area); - result.add(commonTaxonName); - } - - return result; - } - - private List handleMaterialsExamined(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { - List result = new ArrayList(); - while (reader.hasNext()) { - XMLEvent next = readNoWhitespace(reader); - if (isMyEndingElement(next, parentEvent)) { - if (result.isEmpty()){ - fireWarningEvent("Materials examined created empty Individual Associations list", parentEvent, 4); - } - return result; - } else if (isStartingElement(next, SUB_HEADING)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, BR)) { - handleNotYetImplementedElement(next); - } else if (isStartingElement(next, GATHERING)) { - DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.DerivedUnit); - handleGathering(state, reader, next, facade); - SpecimenOrObservationBase specimen; - if (facade.innerDerivedUnit() != null){ - specimen = facade.innerDerivedUnit(); - }else{ - specimen = facade.innerFieldObservation(); - } - IndividualsAssociation individualsAssociation = IndividualsAssociation.NewInstance(); - individualsAssociation.setAssociatedSpecimenOrObservation(specimen); - result.add(individualsAssociation); - } else { - handleUnexpectedElement(next); - } - } - throw new IllegalStateException(" has no closing tag"); - + + return result; } /** @@ -2632,7 +1377,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } else if (isStartingElement(next, REF_NUM)) { handleNotYetImplementedElement(next); } else if (isStartingElement(next, REFERENCE)) { - Reference ref = handleReference(state, reader, next); + Reference ref = nomenclatureImport.handleReference(state, reader, next); result.add(ref); } else { handleUnexpectedStartElement(next); @@ -2799,128 +1544,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } } throw new IllegalStateException(" has no closing tag"); - } - - /** - * @param state - * @param areaName - * @param level - * @return - */ - private NamedArea makeArea(MarkupImportState state, String areaName, NamedAreaLevel level) { - - - //TODO FM vocabulary - TermVocabulary voc = null; - NamedAreaType areaType = null; - - NamedArea area = null; - try { - area = state.getTransformer().getNamedAreaByKey(areaName); - } catch (UndefinedTransformerMethodException e) { - throw new RuntimeException(e); - } - if (area == null){ - boolean isNewInState = false; - UUID uuid = state.getAreaUuid(areaName); - if (uuid == null){ - isNewInState = true; - - - try { - uuid = state.getTransformer().getNamedAreaUuid(areaName); - } catch (UndefinedTransformerMethodException e) { - throw new RuntimeException(e); - } - } - - CdmImportBase.TermMatchMode matchMode = CdmImportBase.TermMatchMode.UUID_LABEL; - area = getNamedArea(state, uuid, areaName, areaName, areaName, areaType, level, voc, matchMode); - if (isNewInState){ - state.putAreaUuid(areaName, area.getUuid()); - - //TODO just for testing -> make generic and move to better place - String geoServiceLayer="vmap0_as_bnd_political_boundary_a"; - String layerFieldName ="nam"; - - if ("Bangka".equals(areaName)){ - String areaValue = "PULAU BANGKA#SUMATERA SELATAN"; - GeoServiceArea geoServiceArea = new GeoServiceArea(); - geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); - this.editGeoService.setMapping(area, geoServiceArea); -// save(area, state); - } - if ("Luzon".equals(areaName)){ - GeoServiceArea geoServiceArea = new GeoServiceArea(); - - List list = Arrays.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON", - "HERMANA MENOR ISLAND#CENTRAL LUZON", - "CENTRAL LUZON"); - for (String areaValue : list){ - geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); - } - - this.editGeoService.setMapping(area, geoServiceArea); -// save(area, state); - } - if ("Mindanao".equals(areaName)){ - GeoServiceArea geoServiceArea = new GeoServiceArea(); - - List list = Arrays.asList("NORTHERN MINDANAO", - "SOUTHERN MINDANAO", - "WESTERN MINDANAO"); - //TODO to be continued - for (String areaValue : list){ - geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); - } - - this.editGeoService.setMapping(area, geoServiceArea); -// save(area, state); - } - if ("Palawan".equals(areaName)){ - GeoServiceArea geoServiceArea = new GeoServiceArea(); - - List list = Arrays.asList("PALAWAN#SOUTHERN TAGALOG"); - for (String areaValue : list){ - geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); - } - - this.editGeoService.setMapping(area, geoServiceArea); -// save(area, state); - } - - - } - } - return area; - } - - - /** - * @param state - * @param levelString - * @param next - * @return - */ - private NamedAreaLevel makeNamedAreaLevel(MarkupImportState state, - String levelString, XMLEvent next) { - NamedAreaLevel level; - try { - level = state.getTransformer().getNamedAreaLevelByKey(levelString); - if (level == null) { - UUID levelUuid = state.getTransformer().getNamedAreaLevelUuid(levelString); - if (levelUuid == null) { - String message = "Unknown distribution locality class (named area level): %s. Create new level instead."; - message = String.format(message, levelString); - fireWarningEvent(message, next, 6); - } - level = getNamedAreaLevel(state, levelUuid, levelString, levelString, levelString, null); - } - } catch (UndefinedTransformerMethodException e) { - throw new RuntimeException(e); - } - return level; - } + } private String handleHeading(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException { checkNoAttributes(parentEvent); @@ -3162,8 +1786,7 @@ public class MarkupDocumentImportNoComponent extends MarkupImportBase { } - private TextData handleChar(MarkupImportState state, XMLEventReader reader, - XMLEvent parentEvent) throws XMLStreamException { + private TextData handleChar(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { String classValue = getClassOnlyAttribute(parentEvent); Feature feature = makeFeature(classValue, state, parentEvent); diff --git a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportBase.java b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportBase.java index 0d60483167..87711fafc6 100644 --- a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportBase.java +++ b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupImportBase.java @@ -9,9 +9,11 @@ package eu.etaxonomy.cdm.io.markup; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Stack; import java.util.UUID; @@ -33,9 +35,15 @@ import org.apache.log4j.Logger; import eu.etaxonomy.cdm.api.service.IClassificationService; import eu.etaxonomy.cdm.api.service.ITermService; import eu.etaxonomy.cdm.common.CdmUtils; +import eu.etaxonomy.cdm.ext.geo.GeoServiceArea; +import eu.etaxonomy.cdm.ext.geo.IEditGeoService; +import eu.etaxonomy.cdm.io.common.CdmImportBase; import eu.etaxonomy.cdm.io.common.CdmImportBase.TermMatchMode; import eu.etaxonomy.cdm.io.common.events.IIoEvent; import eu.etaxonomy.cdm.io.common.events.IoProblemEvent; +import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException; +import eu.etaxonomy.cdm.model.agent.Team; +import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase; import eu.etaxonomy.cdm.model.common.AnnotationType; import eu.etaxonomy.cdm.model.common.CdmBase; import eu.etaxonomy.cdm.model.common.DefinedTermBase; @@ -55,6 +63,7 @@ import eu.etaxonomy.cdm.model.reference.Reference; import eu.etaxonomy.cdm.model.taxon.Classification; import eu.etaxonomy.cdm.model.taxon.Taxon; import eu.etaxonomy.cdm.model.taxon.TaxonBase; +import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException; /** * @author a.mueller @@ -64,14 +73,34 @@ public abstract class MarkupImportBase { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(MarkupImportBase.class); + protected static final String ALTITUDE = "altitude"; + protected static final String ANNOTATION = "annotation"; + protected static final String BOLD = "bold"; + protected static final String BR = "br"; + protected static final String CITATION = "citation"; protected static final String CLASS = "class"; + protected static final String COORDINATES = "coordinates"; + protected static final String DATES = "dates"; + protected static final String GATHERING = "gathering"; + protected static final String FULL_NAME = "fullName"; + protected static final String ITALICS = "italics"; protected static final String NUM = "num"; + protected static final String NOTES = "notes"; + protected static final String PUBLICATION = "publication"; + protected static final String SPECIMEN_TYPE = "specimenType"; + protected static final String STATUS = "status"; + protected static final String SUB_HEADING = "subHeading"; + protected static final String TYPE = "type"; + protected static final String TYPE_STATUS = "typeStatus"; + protected MarkupDocumentImport docImport; - + private IEditGeoService editGeoService; + public MarkupImportBase(MarkupDocumentImport docImport) { super(); this.docImport = docImport; + this.editGeoService = docImport.getEditGeoService(); } private Stack unhandledElements = new Stack(); @@ -572,6 +601,28 @@ public abstract class MarkupImportBase { } + + /** + * Removes whitespaces at beginning and end and makes the first letter + * a capital letter and all other letters small letters. + * @param value + * @return + */ + protected String toFirstCapital(String value) { + if (StringUtils.isBlank(value)){ + return value; + }else{ + String result = ""; + value = value.trim(); + result += value.trim().substring(0,1).toUpperCase(); + if (value.length()>1){ + result += value.substring(1).toLowerCase(); + } + return result; + } + } + + /** * Checks if all words in the given string start with a capital letter but do not have any further capital letter. * @param word the string to be checekd. Usually should be a single word. @@ -708,7 +759,53 @@ public abstract class MarkupImportBase { } // *************************************** Concrete methods **********************************************/ + + + /** + * @param state + * @param classValue + * @param byAbbrev + * @return + */ + protected Rank makeRank(MarkupImportState state, String value, boolean byAbbrev) { + Rank rank = null; + if (StringUtils.isBlank(value)) { + return null; + } + try { + boolean useUnknown = true; + NomenclaturalCode nc = makeNomenclaturalCode(state); + if (byAbbrev) { + rank = Rank.getRankByAbbreviation(value, nc, useUnknown); + } else { + rank = Rank.getRankByEnglishName(value, nc, useUnknown); + } + if (rank.equals(Rank.UNKNOWN_RANK())) { + rank = null; + } + } catch (UnknownCdmTypeException e) { + // doNothing + } + return rank; + } + + + + protected TeamOrPersonBase createAuthor(String authorTitle) { + // TODO atomize and also use by name creation + TeamOrPersonBase result = Team.NewTitledInstance(authorTitle, authorTitle); + return result; + } + protected String getAndRemoveMapKey(Map map, String key) { + String result = map.get(key); + map.remove(key); + if (result != null) { + result = normalize(result); + } + return StringUtils.stripToNull(result); + } + /** * Creates a {@link NonViralName} object depending on the defined {@link NomenclaturalCode} @@ -739,6 +836,126 @@ public abstract class MarkupImportBase { return nc; } + + /** + * @param state + * @param levelString + * @param next + * @return + */ + protected NamedAreaLevel makeNamedAreaLevel(MarkupImportState state, + String levelString, XMLEvent next) { + NamedAreaLevel level; + try { + level = state.getTransformer().getNamedAreaLevelByKey(levelString); + if (level == null) { + UUID levelUuid = state.getTransformer().getNamedAreaLevelUuid(levelString); + if (levelUuid == null) { + String message = "Unknown distribution locality class (named area level): %s. Create new level instead."; + message = String.format(message, levelString); + fireWarningEvent(message, next, 6); + } + level = getNamedAreaLevel(state, levelUuid, levelString, levelString, levelString, null); + } + } catch (UndefinedTransformerMethodException e) { + throw new RuntimeException(e); + } + return level; + } + + + /** + * @param state + * @param areaName + * @param level + * @return + */ + protected NamedArea makeArea(MarkupImportState state, String areaName, NamedAreaLevel level) { + + //TODO FM vocabulary + TermVocabulary voc = null; + NamedAreaType areaType = null; + + NamedArea area = null; + try { + area = state.getTransformer().getNamedAreaByKey(areaName); + } catch (UndefinedTransformerMethodException e) { + throw new RuntimeException(e); + } + if (area == null){ + boolean isNewInState = false; + UUID uuid = state.getAreaUuid(areaName); + if (uuid == null){ + isNewInState = true; + + + try { + uuid = state.getTransformer().getNamedAreaUuid(areaName); + } catch (UndefinedTransformerMethodException e) { + throw new RuntimeException(e); + } + } + + CdmImportBase.TermMatchMode matchMode = CdmImportBase.TermMatchMode.UUID_LABEL; + area = getNamedArea(state, uuid, areaName, areaName, areaName, areaType, level, voc, matchMode); + if (isNewInState){ + state.putAreaUuid(areaName, area.getUuid()); + + //TODO just for testing -> make generic and move to better place + String geoServiceLayer="vmap0_as_bnd_political_boundary_a"; + String layerFieldName ="nam"; + + if ("Bangka".equals(areaName)){ + String areaValue = "PULAU BANGKA#SUMATERA SELATAN"; + GeoServiceArea geoServiceArea = new GeoServiceArea(); + geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); + this.editGeoService.setMapping(area, geoServiceArea); +// save(area, state); + } + if ("Luzon".equals(areaName)){ + GeoServiceArea geoServiceArea = new GeoServiceArea(); + + List list = Arrays.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON", + "HERMANA MENOR ISLAND#CENTRAL LUZON", + "CENTRAL LUZON"); + for (String areaValue : list){ + geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); + } + + this.editGeoService.setMapping(area, geoServiceArea); +// save(area, state); + } + if ("Mindanao".equals(areaName)){ + GeoServiceArea geoServiceArea = new GeoServiceArea(); + + List list = Arrays.asList("NORTHERN MINDANAO", + "SOUTHERN MINDANAO", + "WESTERN MINDANAO"); + //TODO to be continued + for (String areaValue : list){ + geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); + } + + this.editGeoService.setMapping(area, geoServiceArea); +// save(area, state); + } + if ("Palawan".equals(areaName)){ + GeoServiceArea geoServiceArea = new GeoServiceArea(); + + List list = Arrays.asList("PALAWAN#SOUTHERN TAGALOG"); + for (String areaValue : list){ + geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue); + } + + this.editGeoService.setMapping(area, geoServiceArea); +// save(area, state); + } + + } + } + return area; + } + /** diff --git a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupKeyImport.java b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupKeyImport.java index 53aa22bf33..e819d5def4 100644 --- a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupKeyImport.java +++ b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupKeyImport.java @@ -28,7 +28,6 @@ import eu.etaxonomy.cdm.model.common.Language; import eu.etaxonomy.cdm.model.description.KeyStatement; import eu.etaxonomy.cdm.model.description.PolytomousKey; import eu.etaxonomy.cdm.model.description.PolytomousKeyNode; -import eu.etaxonomy.cdm.model.name.BotanicalName; import eu.etaxonomy.cdm.model.name.NonViralName; import eu.etaxonomy.cdm.model.name.Rank; import eu.etaxonomy.cdm.model.taxon.Taxon; diff --git a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupNomenclatureImport.java b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupNomenclatureImport.java new file mode 100644 index 0000000000..a973084497 --- /dev/null +++ b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupNomenclatureImport.java @@ -0,0 +1,827 @@ +/** + * Copyright (C) 2009 EDIT + * European Distributed Institute of Taxonomy + * http://www.e-taxonomy.eu + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * See LICENSE.TXT at the top of this package for the full license terms. + */ + +package eu.etaxonomy.cdm.io.markup; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade; +import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType; +import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor; +import eu.etaxonomy.cdm.model.agent.Team; +import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase; +import eu.etaxonomy.cdm.model.common.CdmBase; +import eu.etaxonomy.cdm.model.common.TimePeriod; +import eu.etaxonomy.cdm.model.description.Feature; +import eu.etaxonomy.cdm.model.description.TaxonDescription; +import eu.etaxonomy.cdm.model.description.TextData; +import eu.etaxonomy.cdm.model.name.HomotypicalGroup; +import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus; +import eu.etaxonomy.cdm.model.name.NomenclaturalCode; +import eu.etaxonomy.cdm.model.name.NomenclaturalStatus; +import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType; +import eu.etaxonomy.cdm.model.name.NonViralName; +import eu.etaxonomy.cdm.model.name.Rank; +import eu.etaxonomy.cdm.model.name.TaxonNameBase; +import eu.etaxonomy.cdm.model.reference.IArticle; +import eu.etaxonomy.cdm.model.reference.IJournal; +import eu.etaxonomy.cdm.model.reference.Reference; +import eu.etaxonomy.cdm.model.reference.ReferenceFactory; +import eu.etaxonomy.cdm.model.reference.ReferenceType; +import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType; +import eu.etaxonomy.cdm.model.taxon.Taxon; +import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException; +import eu.etaxonomy.cdm.strategy.parser.NameTypeParser; +import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl; + +/** + * @author a.mueller + * @created 30.05.2012 + * + */ +public class MarkupNomenclatureImport extends MarkupImportBase { + @SuppressWarnings("unused") + private static final Logger logger = Logger.getLogger(MarkupNomenclatureImport.class); + + private static final String ACCEPTED = "accepted"; + private static final String ACCEPTED_NAME = "acceptedName"; + private static final String ALTERNATEPUBTITLE = "alternatepubtitle"; + private static final String AUTHOR = "author"; + private static final String DETAILS = "details"; + private static final String EDITION = "edition"; + private static final String EDITORS = "editors"; + private static final String HOMONYM = "homonym"; + private static final String HOMOTYPES = "homotypes"; + private static final String INFRANK = "infrank"; + private static final String INFRAUT = "infraut"; + private static final String INFRPARAUT = "infrparaut"; + private static final String ISSUE = "issue"; + private static final String NAME = "name"; + private static final String NAME_TYPE = "nameType"; + private static final String NOM = "nom"; + private static final String PAGES = "pages"; + private static final String PARAUT = "paraut"; + private static final String PUBFULLNAME = "pubfullname"; + private static final String PUBNAME = "pubname"; + private static final String PUBTITLE = "pubtitle"; + private static final String PUBTYPE = "pubtype"; + private static final String REF_PART = "refPart"; + private static final String SYNONYM = "synonym"; + private static final String USAGE = "usage"; + private static final String VOLUME = "volume"; + private static final String YEAR = "year"; + + + private NonViralNameParserImpl parser = new NonViralNameParserImpl(); + + private MarkupKeyImport keyImport; + private MarkupSpecimenImport specimenImport; + + + public MarkupNomenclatureImport(MarkupDocumentImport docImport, MarkupKeyImport keyImport, MarkupSpecimenImport specimenImport) { + super(docImport); + this.keyImport = keyImport; + this.specimenImport = specimenImport; + } + + + public void handleNomenclature(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) + throws XMLStreamException { + checkNoAttributes(parentEvent); + + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isStartingElement(next, HOMOTYPES)) { + handleHomotypes(state, reader, next.asStartElement()); + } else if (isMyEndingElement(next, parentEvent)) { + return; + } else { + fireSchemaConflictEventExpectedStartTag(HOMOTYPES, reader); + state.setUnsuccessfull(); + } + } + return; + } + + private void handleHomotypes(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) + throws XMLStreamException { + checkNoAttributes(parentEvent); + + HomotypicalGroup homotypicalGroup = null; + + boolean hasNom = false; + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + checkMandatoryElement(hasNom, parentEvent, NOM); + return; + } else { + if (isEndingElement(next, NAME_TYPE)) { + state.setNameType(false); + } else if (isEndingElement(next, NOTES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, NOM)) { + NonViralName name = handleNom(state, reader, next, homotypicalGroup); + homotypicalGroup = name.getHomotypicalGroup(); + hasNom = true; + } else if (isStartingElement(next, NAME_TYPE)) { + state.setNameType(true); + handleNameType(state, reader, next, homotypicalGroup); + } else if (isStartingElement(next, SPECIMEN_TYPE)) { + specimenImport.handleSpecimenType(state, reader, next, homotypicalGroup); + } else if (isStartingElement(next, NOTES)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException("Homotypes has no closing tag"); + + } + + private void handleNameType(MarkupImportState state, XMLEventReader reader, + XMLEvent parentEvent, HomotypicalGroup homotypicalGroup) + throws XMLStreamException { + Map attributes = getAttributes(parentEvent); + String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS); + checkNoAttributes(attributes, parentEvent); + + NameTypeDesignationStatus status; + try { + status = NameTypeParser.parseNameTypeStatus(typeStatus); + } catch (UnknownCdmTypeException e) { + String message = "Type status could not be recognized: %s"; + message = String.format(message, typeStatus); + fireWarningEvent(message, parentEvent, 4); + status = null; + } + + boolean hasNom = false; + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + checkMandatoryElement(hasNom, parentEvent.asStartElement(), + NOM); + state.setNameType(false); + return; + } else { + if (isEndingElement(next, ACCEPTED_NAME)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, NOM)) { + // TODO should we check if the type is always a species, is + // this a rule? + NonViralName speciesName = handleNom(state, reader, + next, null); + for (TaxonNameBase name : homotypicalGroup + .getTypifiedNames()) { + name.addNameTypeDesignation(speciesName, null, null, + null, status, false, false, false, false); + } + hasNom = true; + } else if (isStartingElement(next, ACCEPTED_NAME)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException("Homotypes has no closing tag"); + + } + + + /** + * Creates the name defined by a nom tag. Adds it to the given homotypical + * group (if not null). + * + * @param state + * @param reader + * @param parentEvent + * @param homotypicalGroup + * @return + * @throws XMLStreamException + */ + private NonViralName handleNom(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, + HomotypicalGroup homotypicalGroup) throws XMLStreamException { + boolean isSynonym = false; + boolean isNameType = state.isNameType(); + // attributes + String classValue = getClassOnlyAttribute(parentEvent); + NonViralName name; + if (!isNameType && ACCEPTED.equalsIgnoreCase(classValue)) { + isSynonym = false; + name = createName(state, homotypicalGroup, isSynonym); + } else if (!isNameType && SYNONYM.equalsIgnoreCase(classValue)) { + isSynonym = true; + name = createName(state, homotypicalGroup, isSynonym); + } else if (isNameType && NAME_TYPE.equalsIgnoreCase(classValue)) { + // TODO do we need to define the rank here? + name = createNameByCode(state, null); + } else { + fireUnexpectedAttributeValue(parentEvent, CLASS, classValue); + name = createNameByCode(state, null); + } + + Map nameMap = new HashMap(); + + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + // fill the name with all data gathered + fillName(state, nameMap, name, next); + return name; + } else { + if (isEndingElement(next, FULL_NAME)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, HOMONYM)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, NOTES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, ANNOTATION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, FULL_NAME)) { + handleNotYetImplementedElement(next); + // homotypicalGroup = handleNom(state, reader, next, taxon, + // homotypicalGroup); + } else if (isStartingElement(next, NUM)) { + String num = getCData(state, reader, next); + num = num.replace(".", ""); + num = num.replace(")", ""); + if (StringUtils.isNotBlank(num)){ + if (state.getCurrentTaxonNum() != null && ! state.getCurrentTaxonNum().equals(num) ){ + String message = "Taxontitle num and homotypes/nom/num differ ( %s <-> %s ). I use the later one."; + message = String.format(message, state.getCurrentTaxonNum(), num); + fireWarningEvent(message, next, 4); + } + state.setCurrentTaxonNum(num); + } + } else if (isStartingElement(next, NAME)) { + handleName(state, reader, next, nameMap); + } else if (isStartingElement(next, CITATION)) { + handleCitation(state, reader, next, name); + } else if (isStartingElement(next, HOMONYM)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, NOTES)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, ANNOTATION)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException("Nom has no closing tag"); + + } + + + private void handleName(MarkupImportState state, XMLEventReader reader, + XMLEvent parentEvent, Map nameMap) + throws XMLStreamException { + String classValue = getClassOnlyAttribute(parentEvent); + + String text = ""; + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isMyEndingElement(next, parentEvent)) { + nameMap.put(classValue, text); + return; + } else if (next.isStartElement()) { + if (isStartingElement(next, ANNOTATION)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next.asStartElement()); + } + } else if (next.isCharacters()) { + text += next.asCharacters().getData(); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + throw new IllegalStateException("name has no closing tag"); + + } + + + private void fillName(MarkupImportState state, Map nameMap, + NonViralName name, XMLEvent event) { + + // Ranks: family, subfamily, tribus, genus, subgenus, section, + // subsection, species, subspecies, variety, subvariety, forma + // infrank, paraut, author, infrparaut, infraut, status, notes + + String infrank = getAndRemoveMapKey(nameMap, INFRANK); + String authorStr = getAndRemoveMapKey(nameMap, AUTHOR); + String paraut = getAndRemoveMapKey(nameMap, PARAUT); + + String infrParAut = getAndRemoveMapKey(nameMap, INFRPARAUT); + String infrAut = getAndRemoveMapKey(nameMap, INFRAUT); + + String statusStr = getAndRemoveMapKey(nameMap, STATUS); + String notes = getAndRemoveMapKey(nameMap, NOTES); + + makeRankDecision(state, nameMap, name, event, infrank); + + // test consistency of rank and authors + testRankAuthorConsistency(name, event, authorStr, paraut, infrParAut,infrAut); + + // authors + makeNomenclaturalAuthors(name, event, authorStr, paraut, infrParAut,infrAut); + + // status + // TODO handle pro parte, pro syn. etc. + if (StringUtils.isNotBlank(statusStr)) { + String proPartePattern = "(pro parte|p.p.)"; + if (statusStr.matches(proPartePattern)) { + state.setProParte(true); + } + try { + // TODO handle trim earlier + statusStr = statusStr.trim(); + NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(statusStr); + name.addStatus(NomenclaturalStatus.NewInstance(nomStatusType)); + } catch (UnknownCdmTypeException e) { + String message = "Status '%s' could not be recognized"; + message = String.format(message, statusStr); + fireWarningEvent(message, event, 4); + } + } + + // notes + if (StringUtils.isNotBlank(notes)) { + handleNotYetImplementedAttributeValue(event, CLASS, NOTES); + } + + return; + } + + + /** + * @param state + * @param nameMap + * @param name + * @param event + * @param infrankStr + */ + private void makeRankDecision(MarkupImportState state, Map nameMap, + NonViralName name, XMLEvent event, String infrankStr) { + // TODO ranks + for (String key : nameMap.keySet()) { + Rank rank = makeRank(state, key, false); + if (rank == null) { + handleNotYetImplementedAttributeValue(event, CLASS, key); + } else { + if (name.getRank() == null || rank.isLower(name.getRank())) { + name.setRank(rank); + } + String value = nameMap.get(key); + if (rank.isSupraGeneric() || rank.isGenus()) { + name.setGenusOrUninomial(toFirstCapital(value)); + } else if (rank.isInfraGeneric()) { + name.setInfraGenericEpithet(toFirstCapital(value)); + } else if (rank.isSpecies()) { + if (isFirstCapitalWord(value)){ //capital letters are allowed for species epithet in case of person names (e.g. Manilkara Welwitschii Engl. + name.setSpecificEpithet(value); + }else{ + name.setSpecificEpithet(value.toLowerCase()); + } + } else if (rank.isInfraSpecific()) { + name.setInfraSpecificEpithet(value.toLowerCase()); + } else { + String message = "Invalid rank '%s'. Can't decide which epithet to fill with '%s'"; + message = String.format(message, rank.getTitleCache(),value); + fireWarningEvent(message, event, 4); + } + } + + } + // handle given infrank marker + if (StringUtils.isNotBlank(infrankStr)) { + Rank infRank = makeRank(state, infrankStr, true); + + if (infRank == null) { + String message = "Infrank '%s' rank not recognized"; + message = String.format(message, infrankStr); + fireWarningEvent(message, event, 4); + } else { + if (name.getRank() == null) { + name.setRank(infRank); + } else if (infRank.isLower(name.getRank())) { + String message = "InfRank '%s' is lower than existing rank "; + message = String.format(message, infrankStr); + fireWarningEvent(message, event, 2); + name.setRank(infRank); + } else if (infRank.equals(name.getRank())) { + // nothing + } else { + String message = "InfRank '%s' is higher than existing rank "; + message = String.format(message, infrankStr); + fireWarningEvent(message, event, 2); + } + } + } + } + + + /** + * @param name + * @param event + * @param authorStr + * @param paraut + * @param infrParAut + * @param infrAut + */ + private void makeNomenclaturalAuthors(NonViralName name, XMLEvent event, + String authorStr, String paraut, String infrParAut, String infrAut) { + if (name.getRank() != null && name.getRank().isInfraSpecific()) { + if (StringUtils.isNotBlank(infrAut)) { + INomenclaturalAuthor[] authorAndEx = authorAndEx(infrAut, event); + name.setCombinationAuthorTeam(authorAndEx[0]); + name.setExCombinationAuthorTeam(authorAndEx[1]); + } + if (StringUtils.isNotBlank(infrParAut)) { + INomenclaturalAuthor[] authorAndEx = authorAndEx(infrParAut, event); + name.setBasionymAuthorTeam(authorAndEx[0]); + name.setExBasionymAuthorTeam(authorAndEx[1]); + } + } else { + if (name.getRank() == null){ + String message = "No rank defined. Check correct usage of authors!"; + fireWarningEvent(message, event, 4); + if (isNotBlank(infrParAut) || isNotBlank(infrAut)){ + authorStr = infrAut; + paraut = infrParAut; + } + } + if (StringUtils.isNotBlank(authorStr)) { + INomenclaturalAuthor[] authorAndEx = authorAndEx(authorStr, event); + name.setCombinationAuthorTeam(authorAndEx[0]); + name.setExCombinationAuthorTeam(authorAndEx[1]); + } + if (StringUtils.isNotBlank(paraut)) { + INomenclaturalAuthor[] authorAndEx = authorAndEx(paraut, event); + name.setBasionymAuthorTeam(authorAndEx[0]); + name.setExBasionymAuthorTeam(authorAndEx[1]); + } + } + } + + + private TeamOrPersonBase[] authorAndEx(String authorAndEx, XMLEvent xmlEvent) { + authorAndEx = authorAndEx.trim(); + TeamOrPersonBase[] result = new TeamOrPersonBase[2]; + + String[] split = authorAndEx.split("\\sex\\s"); + if (split.length > 2) { + String message = "There is more then 1 ' ex ' in author string. Can't separate author and ex-author"; + fireWarningEvent(message, xmlEvent, 4); + result[0] = createAuthor(authorAndEx); + } else if (split.length == 2) { + result[0] = createAuthor(split[1]); + result[1] = createAuthor(split[0]); + } else { + result[0] = createAuthor(split[0]); + } + return result; + } + + + /** + * Returns the (empty) name with the correct homotypical group depending on + * the taxon status. Throws NPE if no currentTaxon is set in state. + * + * @param state + * @param homotypicalGroup + * @param isSynonym + * @return + */ + private NonViralName createName(MarkupImportState state, + HomotypicalGroup homotypicalGroup, boolean isSynonym) { + NonViralName name; + Taxon taxon = state.getCurrentTaxon(); + if (isSynonym) { + Rank defaultRank = Rank.SPECIES(); // can be any + name = createNameByCode(state, defaultRank); + if (homotypicalGroup != null) { + name.setHomotypicalGroup(homotypicalGroup); + } + SynonymRelationshipType synonymType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(); + if (taxon.getHomotypicGroup().equals(homotypicalGroup)) { + synonymType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(); + } + taxon.addSynonymName(name, synonymType); + } else { + name = CdmBase.deproxy(taxon.getName(), NonViralName.class); + } + return name; + } + + + private void handleCitation(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, NonViralName name) throws XMLStreamException { + String classValue = getClassOnlyAttribute(parentEvent); + + state.setCitation(true); + boolean hasRefPart = false; + Map refMap = new HashMap(); + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isMyEndingElement(next, parentEvent)) { + checkMandatoryElement(hasRefPart, parentEvent.asStartElement(),REF_PART); + Reference reference = createReference(state, refMap, next); + String microReference = refMap.get(DETAILS); + doCitation(state, name, classValue, reference, microReference, + parentEvent); + state.setCitation(false); + return; + } else if (isStartingElement(next, REF_PART)) { + handleRefPart(state, reader, next, refMap); + hasRefPart = true; + } else { + handleUnexpectedElement(next); + } + } + throw new IllegalStateException("Citation has no closing tag"); + + } + + private void handleRefPart(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, Map refMap) throws XMLStreamException { + String classValue = getClassOnlyAttribute(parentEvent); + + String text = ""; + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isMyEndingElement(next, parentEvent)) { + refMap.put(classValue, text); + return; + } else if (next.isStartElement()) { + if (isStartingElement(next, ANNOTATION)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, ITALICS)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, BOLD)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next.asStartElement()); + } + } else if (next.isCharacters()) { + text += next.asCharacters().getData(); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + throw new IllegalStateException("RefPart has no closing tag"); + + } + + + + private void doCitation(MarkupImportState state, NonViralName name, + String classValue, Reference reference, String microCitation, + XMLEvent parentEvent) { + if (PUBLICATION.equalsIgnoreCase(classValue)) { + name.setNomenclaturalReference(reference); + name.setNomenclaturalMicroReference(microCitation); + } else if (USAGE.equalsIgnoreCase(classValue)) { + Taxon taxon = state.getCurrentTaxon(); + TaxonDescription td = getTaxonDescription(taxon, state + .getConfig().getSourceReference(), false, true); + TextData citation = TextData.NewInstance(Feature.CITATION()); + // TODO name used in source + citation.addSource(null, null, reference, microCitation); + td.addElement(citation); + } else if (TYPE.equalsIgnoreCase(classValue)) { + handleNotYetImplementedAttributeValue(parentEvent, CLASS, + classValue); + } else { + // TODO Not yet implemented + handleNotYetImplementedAttributeValue(parentEvent, CLASS, + classValue); + } + } + + + + /** + * Tests if the names rank is consistent with the given author strings. + * @param name + * @param event + * @param authorStr + * @param paraut + * @param infrParAut + * @param infrAut + */ + private void testRankAuthorConsistency(NonViralName name, XMLEvent event, + String authorStr, String paraut, String infrParAut, String infrAut) { + if (name.getRank() == null){ + return; + } + if (name.getRank().isInfraSpecific()) { + if (StringUtils.isBlank(infrParAut) + && StringUtils.isBlank(infrAut) //was isNotBlank before 29.5.2012 + && (StringUtils.isNotBlank(paraut) || StringUtils.isNotBlank(authorStr)) + && ! name.isAutonym()) { + String message = "Rank is infraspecicific but has only specific or higher author(s)"; + fireWarningEvent(message, event, 4); + } + } else { + // is not infraspecific + if (StringUtils.isNotBlank(infrParAut) || StringUtils.isNotBlank(infrAut)) { + String message = "Rank is not infraspecicific but name has infra author(s)"; + fireWarningEvent(message, event, 4); + } + } + } + + + private Reference createReference(MarkupImportState state, Map refMap, XMLEvent parentEvent) { + // TODO + Reference reference; + + String type = getAndRemoveMapKey(refMap, PUBTYPE); + String authorStr = getAndRemoveMapKey(refMap, AUTHOR); + String titleStr = getAndRemoveMapKey(refMap, PUBTITLE); + String titleCache = getAndRemoveMapKey(refMap, PUBFULLNAME); + String volume = getAndRemoveMapKey(refMap, VOLUME); + String edition = getAndRemoveMapKey(refMap, EDITION); + String editors = getAndRemoveMapKey(refMap, EDITORS); + String year = getAndRemoveMapKey(refMap, YEAR); + String pubName = getAndRemoveMapKey(refMap, PUBNAME); + String pages = getAndRemoveMapKey(refMap, PAGES); + + if (state.isCitation()) { + if (volume != null || "journal".equalsIgnoreCase(type)) { + IArticle article = ReferenceFactory.newArticle(); + if (pubName != null) { + IJournal journal = ReferenceFactory.newJournal(); + journal.setTitle(pubName); + article.setInJournal(journal); + } + reference = (Reference) article; + + } else { + // TODO + if (pubName != null){ + reference = ReferenceFactory.newBookSection(); + }else{ + reference = ReferenceFactory.newBook(); + } + } + // TODO use existing author from name or before + TeamOrPersonBase author = createAuthor(authorStr); + reference.setAuthorTeam(author); + + reference.setTitle(titleStr); + if (StringUtils.isNotBlank(titleCache)) { + reference.setTitleCache(titleCache, true); + } + reference.setEdition(edition); + reference.setEditor(editors); + + if (pubName != null) { + Reference inReference; + if (reference.getType().equals(ReferenceType.Article)) { + inReference = ReferenceFactory.newJournal(); + } else { + inReference = ReferenceFactory.newGeneric(); + } + inReference.setTitle(pubName); + reference.setInReference(inReference); + } + + + } else { //no citation + if (volume != null || "journal".equalsIgnoreCase(type)) { + IArticle article = ReferenceFactory.newArticle(); + if (pubName != null) { + IJournal journal = ReferenceFactory.newJournal(); + journal.setTitle(pubName); + article.setInJournal(journal); + } + reference = (Reference) article; + + } else { + Reference bookOrPartOf = ReferenceFactory.newGeneric(); + reference = bookOrPartOf; + } + + // TODO type + TeamOrPersonBase author = createAuthor(authorStr); + reference.setAuthorTeam(author); + + reference.setTitle(titleStr); + if (StringUtils.isNotBlank(titleCache)) { + reference.setTitleCache(titleCache, true); + } + reference.setEdition(edition); + reference.setEditor(editors); + + if (pubName != null) { + Reference inReference; + if (reference.getType().equals(ReferenceType.Article)) { + inReference = ReferenceFactory.newJournal(); + } else { + inReference = ReferenceFactory.newGeneric(); + } + inReference.setTitle(pubName); + reference.setInReference(inReference); + } + } + reference.setVolume(volume); + reference.setDatePublished(TimePeriod.parseString(year)); + //TODO check if this is handled correctly in FM markup + reference.setPages(pages); + + // TODO + String[] unhandledList = new String[]{ALTERNATEPUBTITLE, ISSUE, NOTES, STATUS}; + for (String unhandled : unhandledList){ + String value = getAndRemoveMapKey(refMap, unhandled); + if (isNotBlank(value)){ + this.handleNotYetImplementedAttributeValue(parentEvent, CLASS, unhandled); + } + } + + for (String key : refMap.keySet()) { + if (!DETAILS.equalsIgnoreCase(key)) { + this.fireUnexpectedAttributeValue(parentEvent, CLASS, key); + } + } + + return reference; + } + + + public Reference handleReference(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException { + checkNoAttributes(parentEvent); + + boolean hasRefPart = false; + Map refMap = new HashMap(); + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isMyEndingElement(next, parentEvent)) { + checkMandatoryElement(hasRefPart, parentEvent.asStartElement(), REF_PART); + Reference reference = createReference(state, refMap, next); + return reference; + } else if (isStartingElement(next, REF_PART)) { + handleRefPart(state, reader, next, refMap); + hasRefPart = true; + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException(" has no closing tag"); + } + + +} diff --git a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupSpecimenImport.java b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupSpecimenImport.java index 2c7917415b..4f4855a48a 100644 --- a/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupSpecimenImport.java +++ b/cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/markup/MarkupSpecimenImport.java @@ -9,20 +9,454 @@ package eu.etaxonomy.cdm.io.markup; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.XMLEvent; + +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade; +import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType; +import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeCacheStrategy; +import eu.etaxonomy.cdm.common.CdmUtils; +import eu.etaxonomy.cdm.model.agent.AgentBase; +import eu.etaxonomy.cdm.model.common.CdmBase; +import eu.etaxonomy.cdm.model.description.DescriptionElementBase; +import eu.etaxonomy.cdm.model.description.IndividualsAssociation; +import eu.etaxonomy.cdm.model.location.NamedArea; +import eu.etaxonomy.cdm.model.location.NamedAreaLevel; +import eu.etaxonomy.cdm.model.name.HomotypicalGroup; +import eu.etaxonomy.cdm.model.name.NonViralName; +import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus; +import eu.etaxonomy.cdm.model.name.TaxonNameBase; +import eu.etaxonomy.cdm.model.occurrence.Collection; +import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase; +import eu.etaxonomy.cdm.model.occurrence.FieldObservation; +import eu.etaxonomy.cdm.model.occurrence.Specimen; +import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; +import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException; +import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser; +import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser.TypeInfo; + /** * @author a.mueller * @created 30.05.2012 * */ -public class MarkupSpecimenImport extends MarkupImportBase { +public class MarkupSpecimenImport extends MarkupImportBase { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(MarkupSpecimenImport.class); + + private static final String ALTERNATIVE_COLLECTION_TYPE_STATUS = "alternativeCollectionTypeStatus"; + private static final String ALTERNATIVE_COLLECTOR = "alternativeCollector"; + private static final String ALTERNATIVE_FIELD_NUM = "alternativeFieldNum"; + private static final String COLLECTOR = "collector"; + private static final String COLLECTION = "collection"; + private static final String COLLECTION_AND_TYPE = "collectionAndType"; + private static final String COLLECTION_TYPE_STATUS = "collectionTypeStatus"; + private static final String DESTROYED = "destroyed"; + private static final String FIELD_NUM = "fieldNum"; + private static final String FULL_TYPE = "fullType"; + private static final String LOCALITY = "locality"; + private static final String LOST = "lost"; + private static final String SUB_COLLECTION = "subCollection"; + private static final String NOT_FOUND = "notFound"; + private static final String NOT_SEEN = "notSeen"; + private static final String ORIGINAL_DETERMINATION = "originalDetermination"; + + private static final String UNKNOWN = "unknown"; + public MarkupSpecimenImport(MarkupDocumentImport docImport) { super(docImport); } + + + public void handleSpecimenType(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, + HomotypicalGroup homotypicalGroup) throws XMLStreamException { + + // attributes + Map attributes = getAttributes(parentEvent); + String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS); + String notSeen = getAndRemoveAttributeValue(attributes, NOT_SEEN); + String unknown = getAndRemoveAttributeValue(attributes, UNKNOWN); + String notFound = getAndRemoveAttributeValue(attributes, NOT_FOUND); + String destroyed = getAndRemoveAttributeValue(attributes, DESTROYED); + String lost = getAndRemoveAttributeValue(attributes, LOST); + checkNoAttributes(attributes, parentEvent); + if (StringUtils.isNotEmpty(typeStatus)) { + // TODO + // currently not needed + } else if (StringUtils.isNotEmpty(notSeen)) { + handleNotYetImplementedAttribute(attributes, NOT_SEEN); + } else if (StringUtils.isNotEmpty(unknown)) { + handleNotYetImplementedAttribute(attributes, UNKNOWN); + } else if (StringUtils.isNotEmpty(notFound)) { + handleNotYetImplementedAttribute(attributes, NOT_FOUND); + } else if (StringUtils.isNotEmpty(destroyed)) { + handleNotYetImplementedAttribute(attributes, DESTROYED); + } else if (StringUtils.isNotEmpty(lost)) { + handleNotYetImplementedAttribute(attributes, LOST); + } + + NonViralName firstName = null; + Set names = homotypicalGroup.getTypifiedNames(); + if (names.isEmpty()) { + String message = "There is no name in a homotypical group. Can't create the specimen type"; + fireWarningEvent(message, parentEvent, 8); + } else { + firstName = CdmBase.deproxy(names.iterator().next(),NonViralName.class); + } + + DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.Specimen); + String text = ""; + // elements + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + makeSpecimenType(state, facade, text, firstName, parentEvent); + return; + } else { + if (isEndingElement(next, FULL_TYPE)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, TYPE_STATUS)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, ORIGINAL_DETERMINATION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, SPECIMEN_TYPE)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, COLLECTION_AND_TYPE)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, CITATION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, NOTES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, ANNOTATION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, FULL_TYPE)) { + handleNotYetImplementedElement(next); + // homotypicalGroup = handleNom(state, reader, next, taxon, + // homotypicalGroup); + } else if (isStartingElement(next, TYPE_STATUS)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, GATHERING)) { + handleGathering(state, reader, next, facade); + } else if (isStartingElement(next, ORIGINAL_DETERMINATION)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, SPECIMEN_TYPE)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, COLLECTION_AND_TYPE)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, CITATION)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, NOTES)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, ANNOTATION)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else if (next.isCharacters()) { + text += next.asCharacters().getData(); + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException("Specimen type has no closing tag"); + } + + + + private void makeSpecimenType(MarkupImportState state, DerivedUnitFacade facade, String text, + NonViralName name, XMLEvent parentEvent) { + text = text.trim(); + // remove brackets + if (text.matches("^\\(.*\\)\\.?$")) { + text = text.replaceAll("\\.", ""); + text = text.substring(1, text.length() - 1); + } + String[] split = text.split("[;,]"); + for (String str : split) { + str = str.trim(); + boolean addToAllNamesInGroup = true; + TypeInfo typeInfo = makeSpecimenTypeTypeInfo(str, parentEvent); + SpecimenTypeDesignationStatus typeStatus = typeInfo.status; + Collection collection = createCollection(typeInfo.collectionString); + + // TODO improve cache strategy handling + DerivedUnitBase typeSpecimen = facade.addDuplicate(collection, + null, null, null, null); + typeSpecimen.setCacheStrategy(new DerivedUnitFacadeCacheStrategy()); + name.addSpecimenTypeDesignation((Specimen) typeSpecimen, typeStatus, null, null, null, false, addToAllNamesInGroup); + } + } + + + private Collection createCollection(String code) { + // TODO deduplicate + // TODO code <-> name + Collection result = Collection.NewInstance(); + result.setCode(code); + return result; + } + + + private TypeInfo makeSpecimenTypeTypeInfo(String originalString, XMLEvent event) { + TypeInfo result = new TypeInfo(); + String[] split = originalString.split("\\s+"); + for (String str : split) { + if (str.matches(SpecimenTypeParser.typeTypePattern)) { + SpecimenTypeDesignationStatus status; + try { + status = SpecimenTypeParser.parseSpecimenTypeStatus(str); + } catch (UnknownCdmTypeException e) { + String message = "Specimen type status '%s' not recognized by parser"; + message = String.format(message, str); + fireWarningEvent(message, event, 4); + status = null; + } + result.status = status; + } else if (str.matches(SpecimenTypeParser.collectionPattern)) { + result.collectionString = str; + } else { + String message = "Type part '%s' could not be recognized"; + message = String.format(message, str); + fireWarningEvent(message, event, 2); + } + } + + return result; + } + + + private void handleGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent , DerivedUnitFacade facade) throws XMLStreamException { + checkNoAttributes(parentEvent); + boolean hasCollector = false; + boolean hasFieldNum = false; + + // elements + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + checkMandatoryElement(hasCollector,parentEvent.asStartElement(), COLLECTOR); + checkMandatoryElement(hasFieldNum,parentEvent.asStartElement(), FIELD_NUM); + return; + } else { + if (isEndingElement(next, ALTERNATIVE_COLLECTOR)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, ALTERNATIVE_FIELD_NUM)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, COLLECTION_TYPE_STATUS)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, COLLECTION_AND_TYPE)) { + // NOT YET IMPLEMENTED , does this make sense here? + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, + ALTERNATIVE_COLLECTION_TYPE_STATUS)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, SUB_COLLECTION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, COLLECTION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, DATES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, NOTES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, COLLECTOR)) { + hasCollector = true; + String collectorStr = getCData(state, reader, next); + AgentBase collector = createCollector(collectorStr); + facade.setCollector(collector); + } else if (isStartingElement(next, ALTERNATIVE_COLLECTOR)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, FIELD_NUM)) { + hasFieldNum = true; + String fieldNumStr = getCData(state, reader, next); + facade.setFieldNumber(fieldNumStr); + } else if (isStartingElement(next, ALTERNATIVE_FIELD_NUM)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, COLLECTION_TYPE_STATUS)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, COLLECTION_AND_TYPE)) { //does this make sense here? + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, ALTERNATIVE_COLLECTION_TYPE_STATUS)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, SUB_COLLECTION)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, COLLECTION)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, LOCALITY)) { + handleLocality(state, reader, next, facade); + } else if (isStartingElement(next, DATES)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, NOTES)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else { + handleUnexpectedElement(next); + } + } + // TODO handle missing end element + throw new IllegalStateException("Collection has no closing tag"); + + } + + + private void handleLocality(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, DerivedUnitFacade facade)throws XMLStreamException { + String classValue = getClassOnlyAttribute(parentEvent); + boolean isLocality = false; + NamedAreaLevel areaLevel = null; + if ("locality".equalsIgnoreCase(classValue)) { + isLocality = true; + } else { + areaLevel = makeNamedAreaLevel(state, classValue, parentEvent); + } + + String text = ""; + // elements + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (next.isEndElement()) { + if (isMyEndingElement(next, parentEvent)) { + if (StringUtils.isNotBlank(text)) { + text = normalize(text); + if (isLocality) { + facade.setLocality(text); + } else { + text = CdmUtils.removeTrailingDot(text); + NamedArea area = makeArea(state, text, areaLevel); + facade.addCollectingArea(area); + } + } + // TODO + return; + } else { + if (isEndingElement(next, ALTITUDE)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, COORDINATES)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else if (isEndingElement(next, ANNOTATION)) { + // NOT YET IMPLEMENTED + popUnimplemented(next.asEndElement()); + } else { + handleUnexpectedEndElement(next.asEndElement()); + } + } + } else if (next.isStartElement()) { + if (isStartingElement(next, ALTITUDE)) { + handleNotYetImplementedElement(next); + // homotypicalGroup = handleNom(state, reader, next, taxon, + // homotypicalGroup); + } else if (isStartingElement(next, COORDINATES)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, ANNOTATION)) { + handleNotYetImplementedElement(next); + } else { + handleUnexpectedStartElement(next); + } + } else if (next.isCharacters()) { + text += next.asCharacters().getData(); + } else { + handleUnexpectedElement(next); + } + } + throw new IllegalStateException(" has no closing tag"); + } + + + + private AgentBase createCollector(String collectorStr) { + return createAuthor(collectorStr); + } + + + public List handleMaterialsExamined(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { + List result = new ArrayList(); + while (reader.hasNext()) { + XMLEvent next = readNoWhitespace(reader); + if (isMyEndingElement(next, parentEvent)) { + if (result.isEmpty()){ + fireWarningEvent("Materials examined created empty Individual Associations list", parentEvent, 4); + } + return result; + } else if (isStartingElement(next, SUB_HEADING)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, BR)) { + handleNotYetImplementedElement(next); + } else if (isStartingElement(next, GATHERING)) { + DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.DerivedUnit); + handleGathering(state, reader, next, facade); + SpecimenOrObservationBase specimen; + if (facade.innerDerivedUnit() != null){ + specimen = facade.innerDerivedUnit(); + }else{ + specimen = facade.innerFieldObservation(); + } + IndividualsAssociation individualsAssociation = IndividualsAssociation.NewInstance(); + individualsAssociation.setAssociatedSpecimenOrObservation(specimen); + result.add(individualsAssociation); + } else { + handleUnexpectedElement(next); + } + } + throw new IllegalStateException(" has no closing tag"); + + } + + + + public String handleInLineGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException { + DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.FieldObservation); + handleGathering(state, reader, parentEvent, facade); + FieldObservation fieldObservation = facade.innerFieldObservation(); + String result = "%s"; + result = String.format(result, fieldObservation.getUuid(), fieldObservation.getTitleCache()); + save(fieldObservation, state); + return result; + } + + + } -- 2.34.1