2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.io
.markup
;
12 import java
.net
.MalformedURLException
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Arrays
;
15 import java
.util
.Collection
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
22 import java
.util
.Stack
;
23 import java
.util
.UUID
;
24 import java
.util
.regex
.Matcher
;
25 import java
.util
.regex
.Pattern
;
27 import javax
.xml
.namespace
.QName
;
28 import javax
.xml
.stream
.Location
;
29 import javax
.xml
.stream
.XMLEventReader
;
30 import javax
.xml
.stream
.XMLStreamConstants
;
31 import javax
.xml
.stream
.XMLStreamException
;
32 import javax
.xml
.stream
.events
.Attribute
;
33 import javax
.xml
.stream
.events
.Characters
;
34 import javax
.xml
.stream
.events
.EndElement
;
35 import javax
.xml
.stream
.events
.StartElement
;
36 import javax
.xml
.stream
.events
.XMLEvent
;
38 import org
.apache
.commons
.lang
.StringUtils
;
39 import org
.apache
.commons
.lang
.WordUtils
;
40 import org
.apache
.log4j
.Logger
;
42 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
43 import eu
.etaxonomy
.cdm
.api
.service
.ITermService
;
44 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
45 import eu
.etaxonomy
.cdm
.ext
.geo
.GeoServiceArea
;
46 import eu
.etaxonomy
.cdm
.ext
.geo
.IEditGeoService
;
47 import eu
.etaxonomy
.cdm
.io
.common
.CdmImportBase
;
48 import eu
.etaxonomy
.cdm
.io
.common
.CdmImportBase
.TermMatchMode
;
49 import eu
.etaxonomy
.cdm
.io
.common
.events
.IIoEvent
;
50 import eu
.etaxonomy
.cdm
.io
.common
.events
.IoProblemEvent
;
51 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
52 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
53 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
54 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
55 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
56 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
57 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTerm
;
59 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
60 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
61 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
62 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
63 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
64 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
65 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
66 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
67 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
68 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
69 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKey
;
70 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
71 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
72 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
73 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
74 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
75 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
76 import eu
.etaxonomy
.cdm
.model
.media
.IdentifiableMediaEntity
;
77 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
78 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
79 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
80 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
81 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
82 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
84 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
85 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
86 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
87 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
93 public abstract class MarkupImportBase
{
94 private static final Logger logger
= Logger
.getLogger(MarkupImportBase
.class);
97 protected static final String ALTITUDE
= "altitude";
98 protected static final String ANNOTATION
= "annotation";
99 protected static final String BOLD
= "bold";
100 protected static final String BR
= "br";
101 protected static final String DOUBTFUL
= "doubtful";
102 protected static final String CITATION
= "citation";
103 protected static final String CLASS
= "class";
104 protected static final String COORDINATES
= "coordinates";
105 protected static final String DATES
= "dates";
106 protected static final String GATHERING
= "gathering";
107 protected static final String GATHERING_GROUP
= "gatheringGroup";
108 protected static final String GENUS_ABBREVIATION
= "genus abbreviation";
109 protected static final String FOOTNOTE
= "footnote";
110 protected static final String FOOTNOTE_REF
= "footnoteRef";
111 protected static final String FULL_NAME
= "fullName";
112 protected static final String ITALICS
= "italics";
113 protected static final String NUM
= "num";
114 protected static final String NOTES
= "notes";
115 protected static final String PUBLICATION
= "publication";
116 protected static final String SPECIMEN_TYPE
= "specimenType";
117 protected static final String STATUS
= "status";
118 protected static final String SUB_HEADING
= "subHeading";
119 protected static final String TYPE
= "type";
120 protected static final String TYPE_STATUS
= "typeStatus";
121 protected static final String UNKNOWN
= "unknown";
124 protected static final boolean CREATE_NEW
= true;
125 protected static final boolean NO_IMAGE_GALLERY
= false;
126 protected static final boolean IMAGE_GALLERY
= true;
128 protected static final String ADDENDA
= "addenda";
129 protected static final String BIBLIOGRAPHY
= "bibliography";
130 protected static final String BIOGRAPHIES
= "biographies";
131 protected static final String CHAR
= "char";
132 protected static final String DEDICATION
= "dedication";
133 protected static final String DEFAULT_MEDIA_URL
= "defaultMediaUrl";
134 protected static final String DISTRIBUTION_LIST
= "distributionList";
135 protected static final String DISTRIBUTION_LOCALITY
= "distributionLocality";
136 protected static final String FEATURE
= "feature";
137 protected static final String FIGURE
= "figure";
138 protected static final String FIGURE_LEGEND
= "figureLegend";
139 protected static final String FIGURE_PART
= "figurePart";
140 protected static final String FIGURE_REF
= "figureRef";
141 protected static final String FIGURE_TITLE
= "figureTitle";
142 protected static final String FOOTNOTE_STRING
= "footnoteString";
143 protected static final String FREQUENCY
= "frequency";
144 protected static final String HEADING
= "heading";
145 protected static final String HABITAT
= "habitat";
146 protected static final String HABITAT_LIST
= "habitatList";
147 protected static final String IS_FREETEXT
= "isFreetext";
148 protected static final String ID
= "id";
149 protected static final String KEY
= "key";
150 protected static final String LIFE_CYCLE_PERIODS
= "lifeCyclePeriods";
151 protected static final String META_DATA
= "metaData";
152 protected static final String MODS
= "mods";
154 protected static final String NOMENCLATURE
= "nomenclature";
155 protected static final String QUOTE
= "quote";
156 protected static final String RANK
= "rank";
157 protected static final String REF
= "ref";
158 protected static final String REF_NUM
= "refNum";
159 protected static final String REFERENCE
= "reference";
160 protected static final String REFERENCES
= "references";
161 protected static final String SUB_CHAR
= "subChar";
162 protected static final String TAXON
= "taxon";
163 protected static final String TAXONTITLE
= "taxontitle";
164 protected static final String TAXONTYPE
= "taxontype";
165 protected static final String TEXT_SECTION
= "textSection";
166 protected static final String TREATMENT
= "treatment";
167 protected static final String SERIALS_ABBREVIATIONS
= "serialsAbbreviations";
168 protected static final String STRING
= "string";
169 protected static final String URL
= "url";
170 protected static final String WRITER
= "writer";
172 protected static final String LOCALITY
= "locality";
177 protected static final String ACCEPTED
= "accepted";
178 protected static final String ACCEPTED_NAME
= "acceptedName";
179 protected static final String ALTERNATEPUBTITLE
= "alternatepubtitle";
180 protected static final String AUTHOR
= "author";
181 protected static final String DETAILS
= "details";
182 protected static final String EDITION
= "edition";
183 protected static final String EDITORS
= "editors";
184 protected static final String HOMONYM
= "homonym";
185 protected static final String HOMOTYPES
= "homotypes";
186 protected static final String NOMENCLATURAL_NOTES
= "nomenclaturalNotes";
187 protected static final String INFRANK
= "infrank";
188 protected static final String INFRAUT
= "infraut";
189 protected static final String INFRPARAUT
= "infrparaut";
190 protected static final String ISSUE
= "issue";
191 protected static final String NAME
= "name";
192 protected static final String NAME_TYPE
= "nameType";
193 protected static final String NOM
= "nom";
194 protected static final String PAGES
= "pages";
195 protected static final String PARAUT
= "paraut";
196 protected static final String PUBFULLNAME
= "pubfullname";
197 protected static final String PUBLOCATION
= "publocation";
198 protected static final String PUBLISHER
= "publisher";
199 protected static final String PUBNAME
= "pubname";
200 protected static final String PUBTITLE
= "pubtitle";
201 protected static final String PUBTYPE
= "pubtype";
202 protected static final String REF_PART
= "refPart";
203 protected static final String SYNONYM
= "synonym";
204 protected static final String USAGE
= "usage";
205 protected static final String VOLUME
= "volume";
206 protected static final String YEAR
= "year";
210 protected static final String COUPLET
= "couplet";
211 protected static final String IS_SPOTCHARACTERS
= "isSpotcharacters";
212 protected static final String ONLY_NUMBERED_TAXA_EXIST
= "onlyNumberedTaxaExist";
213 protected static final String EXISTS
= "exists";
214 protected static final String KEYNOTES
= "keynotes";
215 protected static final String KEY_TITLE
= "keyTitle";
216 protected static final String QUESTION
= "question";
217 protected static final String TEXT
= "text";
218 protected static final String TO_COUPLET
= "toCouplet";
219 protected static final String TO_KEY
= "toKey";
220 protected static final String TO_TAXON
= "toTaxon";
224 protected static final String VERNACULAR_NAMES
= "vernacularNames";
225 protected static final String VERNACULAR_NAME
= "vernacularName";
226 protected static final String TRANSLATION
= "translation";
227 protected static final String LOCAL_LANGUAGE
= "localLanguage";
231 protected MarkupDocumentImport docImport
;
233 private IEditGeoService editGeoService
;
235 public MarkupImportBase(MarkupDocumentImport docImport
) {
237 this.docImport
= docImport
;
238 this.editGeoService
= docImport
.getEditGeoService();
241 private Stack
<QName
> unhandledElements
= new Stack
<QName
>();
242 private Stack
<QName
> handledElements
= new Stack
<QName
>();
245 protected <T
extends CdmBase
> void save(Collection
<T
> collection
, MarkupImportState state
) {
246 if (state
.isCheck() || collection
.isEmpty()){
249 T example
= collection
.iterator().next();
250 if (example
.isInstanceOf(TaxonBase
.class)){
251 Collection
<TaxonBase
> typedCollection
= (Collection
<TaxonBase
>)collection
;
252 docImport
.getTaxonService().saveOrUpdate(typedCollection
);
253 }else if (example
.isInstanceOf(Classification
.class)){
254 Collection
<Classification
> typedCollection
= (Collection
<Classification
>)collection
;
255 docImport
.getClassificationService().saveOrUpdate(typedCollection
);
256 }else if (example
.isInstanceOf(PolytomousKey
.class)){
257 Collection
<PolytomousKey
> typedCollection
= (Collection
<PolytomousKey
>)collection
;
258 docImport
.getPolytomousKeyService().saveOrUpdate(typedCollection
);
259 }else if (example
.isInstanceOf(DefinedTermBase
.class)){
260 Collection
<DefinedTermBase
> typedCollection
= (Collection
<DefinedTermBase
>)collection
;
261 getTermService().saveOrUpdate(typedCollection
);
267 //TODO move to service layer for all IdentifiableEntities
268 protected void save(CdmBase cdmBase
, MarkupImportState state
) {
269 if (state
.isCheck()){
272 cdmBase
= CdmBase
.deproxy(cdmBase
, CdmBase
.class);
273 if (cdmBase
== null){
274 String message
= "Tried to save a null object.";
275 fireWarningEvent(message
, "--location ?? --", 6,1);
276 } else if (cdmBase
.isInstanceOf(TaxonBase
.class)){
277 docImport
.getTaxonService().saveOrUpdate((TaxonBase
<?
>)cdmBase
);
278 }else if (cdmBase
.isInstanceOf(Classification
.class)){
279 docImport
.getClassificationService().saveOrUpdate((Classification
)cdmBase
);
280 }else if (cdmBase
.isInstanceOf(PolytomousKey
.class)){
281 docImport
.getPolytomousKeyService().saveOrUpdate((PolytomousKey
)cdmBase
);
282 }else if (cdmBase
.isInstanceOf(DefinedTermBase
.class)){
283 docImport
.getTermService().saveOrUpdate((DefinedTermBase
<?
>)cdmBase
);
284 }else if (cdmBase
.isInstanceOf(Media
.class)){
285 docImport
.getMediaService().saveOrUpdate((Media
)cdmBase
);
286 }else if (cdmBase
.isInstanceOf(SpecimenOrObservationBase
.class)){
287 docImport
.getOccurrenceService().saveOrUpdate((SpecimenOrObservationBase
<?
>)cdmBase
);
288 }else if (cdmBase
.isInstanceOf(DescriptionElementBase
.class)){
289 docImport
.getDescriptionService().saveDescriptionElement((DescriptionElementBase
)cdmBase
);
290 }else if (cdmBase
.isInstanceOf(Reference
.class)){
291 docImport
.getReferenceService().saveOrUpdate((Reference
<?
>)cdmBase
);
293 String message
= "Unknown cdmBase type to save: " + cdmBase
.getClass();
294 fireWarningEvent(message
, "Unknown location", 8);
296 //logger.warn("Saved " + cdmBase);
300 protected ITermService
getTermService() {
301 return docImport
.getTermService();
304 protected IClassificationService
getClassificationService() {
305 return docImport
.getClassificationService();
308 //*********************** Attribute methods *************************************/
311 * Returns a map for all attributes of an start element
315 protected Map
<String
, Attribute
> getAttributes(XMLEvent event
) {
316 Map
<String
, Attribute
> result
= new HashMap
<String
, Attribute
>();
317 if (!event
.isStartElement()){
318 fireWarningEvent("Event is not an startElement. Can't check attributes", makeLocationStr(event
.getLocation()), 1, 1);
321 StartElement element
= event
.asStartElement();
322 Iterator
<Attribute
> attributes
= element
.getAttributes();
323 while (attributes
.hasNext()){
324 Attribute attribute
= attributes
.next();
326 result
.put(attribute
.getName().getLocalPart(), attribute
);
332 * Throws an unexpected attributes event if the event has any attributes.
335 protected void checkNoAttributes(Map
<String
, Attribute
> attributes
, XMLEvent event
) {
336 String
[] exceptions
= new String
[]{};
337 handleUnexpectedAttributes(event
.getLocation(), attributes
, 1, exceptions
);
343 * Throws an unexpected attributes event if the event has any attributes.
346 protected void checkNoAttributes(XMLEvent event
) {
347 String
[] exceptions
= new String
[]{};
348 checkNoAttributes(event
, 1, exceptions
);
352 * Throws an unexpected attributes event if the event has any attributes except those mentioned in "exceptions".
356 protected void checkNoAttributes(XMLEvent event
, int stackDepth
, String
... exceptions
) {
357 if (! event
.isStartElement()){
358 fireWarningEvent("Event is not an startElement. Can't check attributes", makeLocationStr(event
.getLocation()), 1, 1);
361 StartElement startElement
= event
.asStartElement();
362 Map
<String
, Attribute
> attributes
= getAttributes(startElement
);
363 handleUnexpectedAttributes(startElement
.getLocation(), attributes
, stackDepth
+1, exceptions
);
368 * Checks if the given attribute exists and has the given value.
369 * If yes, true is returned and the attribute is removed from the attributes map.
370 * Otherwise false is returned.
374 * @return <code>true</code> if attribute has given value, <code>false</code> otherwise
376 protected boolean checkAndRemoveAttributeValue( Map
<String
, Attribute
> attributes
, String attrName
, String value
) {
377 Attribute attr
= attributes
.get(attrName
);
378 if (attr
== null ||value
== null ){
381 if (value
.equals(attr
.getValue())){
382 attributes
.remove(attrName
);
392 * Returns the value of a given attribute name and removes the attribute from the attributes map.
397 protected String
getAndRemoveAttributeValue(Map
<String
, Attribute
> attributes
, String attrName
) {
398 return getAndRemoveAttributeValue(null, attributes
, attrName
, false, 1);
402 * Returns the value of a boolean attribute with the given name and removes the attribute from the attributes map.
403 * Returns <code>defaultValue</code> if the attribute does not exist. ALso returns <code>defaultValue</code> and throws a warning if the
404 * attribute has no boolean value (true, false).
406 * @param attributes the
407 * @param attrName the name of the attribute
408 * @param defaultValue the default value to return if attribute does not exist or can not be defined
411 protected Boolean
getAndRemoveBooleanAttributeValue(XMLEvent event
, Map
<String
, Attribute
> attributes
, String attrName
, Boolean defaultValue
) {
412 String value
= getAndRemoveAttributeValue(null, attributes
, attrName
, false, 1);
413 Boolean result
= defaultValue
;
415 if (value
.equalsIgnoreCase("true")){
417 }else if (value
.equalsIgnoreCase("false")){
420 String message
= "Boolean attribute has no boolean value ('true', 'false') but '%s'";
421 fireWarningEvent(String
.format(message
, value
), makeLocationStr(event
.getLocation()), 6, 1);
429 * Returns the value of a given attribute name and returns the attribute from the attributes map.
430 * Fires a mandatory field is missing event if the attribute does not exist.
436 protected String
getAndRemoveRequiredAttributeValue(XMLEvent xmlEvent
, Map
<String
, Attribute
> attributes
, String attrName
) {
437 return getAndRemoveAttributeValue(xmlEvent
, attributes
, attrName
, true, 1);
441 * Returns the value of a given attribute name and returns the attribute from the attributes map.
442 * If required is <code>true</code> and the attribute does not exist a mandatory field is missing event is fired.
449 private String
getAndRemoveAttributeValue(XMLEvent xmlEvent
, Map
<String
, Attribute
> attributes
, String attrName
, boolean isRequired
, int stackDepth
) {
450 Attribute attr
= attributes
.get(attrName
);
453 fireMandatoryElementIsMissing(xmlEvent
, attrName
, 8, stackDepth
+1);
457 attributes
.remove(attrName
);
458 return attr
.getValue();
463 * Fires an not yet implemented event if the given attribute exists in attributes.
467 protected void handleNotYetImplementedAttribute(Map
<String
, Attribute
> attributes
, String attrName
) {
468 Attribute attr
= attributes
.get(attrName
);
470 attributes
.remove(attrName
);
471 QName qName
= attr
.getName();
472 fireNotYetImplementedAttribute(attr
.getLocation(), qName
, 1);
477 * Fires an unhandled attributes event, if attributes exist in attributes map not covered by the exceptions.
478 * No event is fired if the unhandled elements stack is not empty.
483 protected void handleUnexpectedAttributes(Location location
,Map
<String
, Attribute
> attributes
, String
... exceptions
) {
484 handleUnexpectedAttributes(location
, attributes
, 1, exceptions
);
488 * see {@link #handleUnexpectedAttributes(Location, Map, String...)}
492 * @param stackDepth the stack trace depth
495 private void handleUnexpectedAttributes(Location location
,Map
<String
, Attribute
> attributes
, int stackDepth
, String
... exceptions
) {
496 if (attributes
.size() > 0){
497 if (this.unhandledElements
.size() == 0 ){
498 boolean hasUnhandledAttributes
= false;
499 for (String key
: attributes
.keySet()){
500 boolean isException
= false;
501 for (String exception
: exceptions
){
502 if(key
.equals(exception
)){
507 hasUnhandledAttributes
= true;
510 if (hasUnhandledAttributes
){
511 fireUnexpectedAttributes(location
, attributes
, stackDepth
+1);
518 private void fireUnexpectedAttributes(Location location
, Map
<String
, Attribute
> attributes
, int stackDepth
) {
519 String attributesString
= "";
520 for (String key
: attributes
.keySet()){
521 Attribute attribute
= attributes
.get(key
);
522 attributesString
= CdmUtils
.concat(",", attributesString
, attribute
.getName().getLocalPart() + ":" + attribute
.getValue());
524 String message
= "Unexpected attributes: %s";
525 IoProblemEvent event
= makeProblemEvent(location
, String
.format(message
, attributesString
), 1 , stackDepth
+1 );
530 protected void fireUnexpectedAttributeValue(XMLEvent parentEvent
, String attrName
, String attrValue
) {
531 String message
= "Unexpected attribute value %s='%s'";
532 message
= String
.format(message
, attrName
, attrValue
);
533 IoProblemEvent event
= makeProblemEvent(parentEvent
.getLocation(), message
, 1 , 1 );
537 protected void handleNotYetImplementedAttributeValue(XMLEvent xmlEvent
, String attrName
, String attrValue
) {
538 String message
= "Attribute %s not yet implemented for value '%s'";
539 message
= String
.format(message
, attrName
, attrValue
);
540 IIoEvent event
= makeProblemEvent(xmlEvent
.getLocation(), message
, 1, 1 );
544 protected void fireNotYetImplementedAttribute(Location location
, QName qName
, int stackDepth
) {
545 String message
= "Attribute not yet implemented: %s";
546 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, qName
.getLocalPart()), 1, stackDepth
+1 );
551 protected void fireUnexpectedEvent(XMLEvent xmlEvent
, int stackDepth
) {
552 Location location
= xmlEvent
.getLocation();
553 String message
= "Unexpected event: %s";
554 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, xmlEvent
.toString()), 2, stackDepth
+1);
558 protected void fireUnexpectedStartElement(Location location
, StartElement startElement
, int stackDepth
) {
559 QName qName
= startElement
.getName();
560 String message
= "Unexpected start element: %s";
561 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, qName
.getLocalPart()), 2, stackDepth
+1);
566 protected void fireUnexpectedEndElement(Location location
, EndElement endElement
, int stackDepth
) {
567 QName qName
= endElement
.getName();
568 String message
= "Unexpected end element: %s";
569 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, qName
.getLocalPart()), 16, stackDepth
+1);
573 protected void fireNotYetImplementedElement(Location location
, QName qName
, int stackDepth
) {
574 String message
= "Element not yet implemented: %s";
575 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, qName
.getLocalPart()), 1, stackDepth
+1 );
579 protected void fireNotYetImplementedCharacters(Location location
, Characters chars
, int stackDepth
) {
580 String message
= "Characters not yet handled: %s";
581 IIoEvent event
= makeProblemEvent(location
, String
.format(message
, chars
.getData()), 1, stackDepth
+1 );
586 * Creates a problem event.
587 * Be aware of the right depths of the stack trace !
593 private IoProblemEvent
makeProblemEvent(Location location
, String message
, int severity
, int stackDepth
) {
595 StackTraceElement
[] stackTrace
= new Exception().getStackTrace();
596 int lineNumber
= stackTrace
[stackDepth
].getLineNumber();
597 String methodName
= stackTrace
[stackDepth
].getMethodName();
598 String locationStr
= makeLocationStr(location
);
599 String className
= stackTrace
[stackDepth
].getClassName();
600 Class
<?
> declaringClass
;
602 declaringClass
= Class
.forName(className
);
603 } catch (ClassNotFoundException e
) {
604 declaringClass
= this.getClass();
606 IoProblemEvent event
= IoProblemEvent
.NewInstance(declaringClass
, message
,
607 locationStr
, lineNumber
, severity
, methodName
);
612 * Creates a string from a location
616 protected String
makeLocationStr(Location location
) {
617 String locationStr
= location
== null ?
" - no location - " : "l." + location
.getLineNumber() + "/c."+ location
.getColumnNumber();
623 * Fires an unexpected element event if the unhandled elements stack is empty.
624 * Otherwise adds the element to the stack.
627 protected void handleUnexpectedStartElement(XMLEvent event
) {
628 handleUnexpectedStartElement(event
, 1);
632 * Fires an unexpected element event if the unhandled elements stack is empty.
633 * Otherwise adds the element to the stack.
636 protected void handleUnexpectedStartElement(XMLEvent event
, int stackDepth
) {
637 QName qName
= event
.asStartElement().getName();
638 if (! unhandledElements
.empty()){
639 unhandledElements
.push(qName
);
641 fireUnexpectedStartElement(event
.getLocation(), event
.asStartElement(), stackDepth
+ 1);
646 protected void handleUnexpectedEndElement(EndElement event
) {
647 handleUnexpectedEndElement(event
, 1);
651 * Fires an unexpected element event if the event is not the last on the stack.
652 * Otherwise removes last stack element.
655 protected void handleUnexpectedEndElement(EndElement event
, int stackDepth
) {
656 QName qName
= event
.asEndElement().getName();
657 if (!unhandledElements
.isEmpty() && unhandledElements
.peek().equals(qName
)){
658 unhandledElements
.pop();
660 fireUnexpectedEndElement(event
.getLocation(), event
.asEndElement(), stackDepth
+ 1);
668 protected void popUnimplemented(EndElement endElement
) {
669 QName qName
= endElement
.asEndElement().getName();
670 if (unhandledElements
.peek().equals(qName
)){
671 unhandledElements
.pop();
673 String message
= "End element is not last on stack: %s";
674 message
= String
.format(message
, qName
.getLocalPart());
675 IIoEvent event
= makeProblemEvent(endElement
.getLocation(), message
, 16, 1);
683 * Fires an unexpected element event if the unhandled element stack is empty.
686 protected void handleUnexpectedElement(XMLEvent event
) {
687 if (event
.isStartElement()){
688 handleUnexpectedStartElement(event
, 2);
689 }else if (event
.isEndElement()){
690 handleUnexpectedEndElement(event
.asEndElement(), 2);
691 }else if (event
.getEventType() == XMLStreamConstants
.COMMENT
){
693 }else if (! unhandledElements
.empty()){
696 fireUnexpectedEvent(event
, 1);
701 * Fires an not yet implemented event and adds the element name to the unhandled elements stack.
704 protected void handleNotYetImplementedCharacters(XMLEvent event
) {
705 Characters chars
= event
.asCharacters();
706 fireNotYetImplementedCharacters(event
.getLocation(), chars
, 1);
710 * Fires an not yet implemented event and adds the element name to the unhandled elements stack.
713 protected void handleNotYetImplementedElement(XMLEvent event
) {
714 QName qName
= event
.asStartElement().getName();
715 boolean isTopLevel
= unhandledElements
.isEmpty();
716 unhandledElements
.push(qName
);
718 fireNotYetImplementedElement(event
.getLocation(), qName
, 1);
723 * Fires an not yet implemented event and adds the element name to the unhandled elements stack.
726 protected void handleIgnoreElement(XMLEvent event
) {
727 QName qName
= event
.asStartElement().getName();
728 unhandledElements
.push(qName
);
731 protected void handleAmbigousManually(MarkupImportState state
,
732 XMLEventReader reader
, StartElement startElement
) {
733 QName qName
= startElement
.getName();
734 unhandledElements
.push(qName
);
736 "Handle manually: " + qName
.getLocalPart() + " is ambigous and should therefore be handled manually",
737 makeLocationStr(startElement
.getLocation()), 2, 2);
741 * Checks if a mandatory text is not empty or null.
742 * Returns true if text is given.
743 * Fires an mandatory element is missing event otherwise and returns <code>null</code>.
748 protected boolean checkMandatoryText(String text
, XMLEvent parentEvent
) {
749 if (! StringUtils
.isNotBlank(text
)){
750 fireMandatoryElementIsMissing(parentEvent
, "CData", 4, 1);
757 * Fires an mandatory element is missing event if exists is <code>false</code>.
758 * @param hasMandatory
762 protected void checkMandatoryElement(boolean exists
, StartElement parentEvent
, String attrName
) {
764 fireMandatoryElementIsMissing(parentEvent
, attrName
, 5, 1);
770 * Fires an element is missing event.
775 * @throws IllegalStateException if xmlEvent is not a StartElement and not an Attribute
777 private void fireMandatoryElementIsMissing(XMLEvent xmlEvent
, String missingEventName
, int severity
, int stackDepth
) throws IllegalStateException
{
778 Location location
= xmlEvent
.getLocation();
781 if (xmlEvent
.isAttribute()){
782 Attribute attribute
= ((Attribute
)xmlEvent
);
783 typeName
= "attribute";
784 qName
= attribute
.getName();
785 }else if (xmlEvent
.isStartElement()){
786 typeName
= "element";
787 qName
= xmlEvent
.asStartElement().getName();
789 throw new IllegalStateException("mandatory element only allowed for attributes and start tags in " + makeLocationStr(location
));
791 String message
= "Mandatory %s '%s' is missing in %s";
792 message
= String
.format(message
, typeName
, missingEventName
, qName
.getLocalPart());
793 IIoEvent event
= makeProblemEvent(location
, message
, severity
, stackDepth
+1);
801 * Returns true if the "next" event is the ending tag for the "parent" event.
802 * @param next end element to test, must not be null
803 * @param parentEvent start element to test
804 * @return true if the "next" event is the ending tag for the "parent" event.
805 * @throws XMLStreamException
807 protected boolean isMyEndingElement(XMLEvent next
, XMLEvent parentEvent
) throws XMLStreamException
{
808 if (! parentEvent
.isStartElement()){
809 String message
= "Parent event should be start tag";
810 fireWarningEvent(message
, makeLocationStr(next
.getLocation()), 6);
813 return isEndingElement(next
, parentEvent
.asStartElement().getName().getLocalPart());
817 * Trims the text and removes turns all whitespaces into single empty space.
821 protected String
normalize(String text
) {
822 text
= StringUtils
.trimToEmpty(text
);
823 text
= text
.replaceAll("\\s+", " ");
830 * Removes whitespaces at beginning and end and makes the first letter
831 * a capital letter and all other letters small letters.
835 protected String
toFirstCapital(String value
) {
836 if (StringUtils
.isBlank(value
)){
840 value
= value
.trim();
841 result
+= value
.trim().substring(0,1).toUpperCase();
842 if (value
.length()>1){
843 result
+= value
.substring(1).toLowerCase();
850 * Currently not used.
852 * @param allowedNumberOfCharacters
853 * @param onlyFirstCapital
856 protected boolean isAbbreviation(String str
, int allowedNumberOfCharacters
, boolean onlyFirstCapital
){
861 if (! str
.endsWith(".")){
864 str
= str
.substring(0, str
.length() -1);
865 if (str
.length() > allowedNumberOfCharacters
){
868 final String re
= "^\\p{javaUpperCase}\\p{javaLowerCase}*$";
869 if (str
.matches(re
)){
877 * Checks if <code>abbrev</code> is the short form for the genus name (strGenusName).
878 * Usually this is the case if <code>abbrev</code> is the first letter (optional with ".")
879 * of strGenusName. But in older floras it may also be the first 2 or 3 letters (optional with dot).
880 * However, we allow only a maximum of 2 letters to be anambigous. In cases with 3 letters better
881 * change the original markup data.
883 * @param strGenusName
886 protected boolean isGenusAbbrev(String abbrev
, String strGenusName
) {
887 if (! abbrev
.matches("[A-Z][a-z]?\\.?")) {
889 }else if (abbrev
.length() == 0 || strGenusName
== null || strGenusName
.length() == 0){
892 abbrev
= abbrev
.replace(".", "");
893 return strGenusName
.startsWith(abbrev
);
894 // boolean result = true;
895 // for (int i = 0 ; i < abbrev.length(); i++){
896 // result &= ( abbrev.charAt(i) == strGenusName.charAt(i));
904 * Checks if all words in the given string start with a capital letter but do not have any further capital letter.
905 * @param word the string to be checekd. Usually should be a single word.
906 * @return true if the above is the case, false otherwise
908 protected boolean isFirstCapitalWord(String word
) {
909 if (WordUtils
.capitalizeFully(word
).equals(word
)){
911 }else if (WordUtils
.capitalizeFully(word
,new char[]{'-'}).equals(word
)){
912 //for words like Le-Testui (which is a species epithet)
921 * Read next event. Ignore whitespace events.
924 * @throws XMLStreamException
926 protected XMLEvent
readNoWhitespace(XMLEventReader reader
) throws XMLStreamException
{
927 XMLEvent event
= reader
.nextEvent();
928 while (!unhandledElements
.isEmpty()){
929 if (event
.isStartElement()){
930 handleNotYetImplementedElement(event
);
931 }else if (event
.isEndElement()){
932 popUnimplemented(event
.asEndElement());
934 event
= reader
.nextEvent();
936 while (event
.isCharacters() && event
.asCharacters().isWhiteSpace()){
937 event
= reader
.nextEvent();
943 * Returns the REQUIRED "class" attribute for a given event and checks that it is the only attribute.
947 protected String
getClassOnlyAttribute(XMLEvent parentEvent
) {
948 return getClassOnlyAttribute(parentEvent
, true);
953 * Returns the "class" attribute for a given event and checks that it is the only attribute.
957 protected String
getClassOnlyAttribute(XMLEvent parentEvent
, boolean required
) {
958 return getOnlyAttribute(parentEvent
, CLASS
, required
);
962 * Returns the value for the only attribute for a given event and checks that it is the only attribute.
966 protected String
getOnlyAttribute(XMLEvent parentEvent
, String attrName
, boolean required
) {
967 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
968 String classValue
=getAndRemoveAttributeValue(parentEvent
, attributes
, attrName
, required
, 1);
969 checkNoAttributes(attributes
, parentEvent
);
974 protected void fireWarningEvent(String message
, String locationStr
, Integer severity
, Integer depth
) {
975 docImport
.fireWarningEvent(message
, locationStr
, severity
, depth
);
978 protected void fireWarningEvent(String message
, XMLEvent event
, Integer severity
) {
979 docImport
.fireWarningEvent(message
, makeLocationStr(event
.getLocation()), severity
, 1);
982 protected void fireSchemaConflictEventExpectedStartTag(String elName
, XMLEventReader reader
) throws XMLStreamException
{
983 docImport
.fireSchemaConflictEventExpectedStartTag(elName
, reader
);
987 protected void fireWarningEvent(String message
, String locationStr
, int severity
) {
988 docImport
.fireWarningEvent(message
, locationStr
, severity
, 1);
991 protected void fire(IIoEvent event
) {
992 docImport
.fire(event
);
995 protected boolean isNotBlank(String str
){
996 return StringUtils
.isNotBlank(str
);
999 protected boolean isBlank(String str
){
1000 return StringUtils
.isBlank(str
);
1003 protected TaxonDescription
getTaxonDescription(Taxon taxon
, Reference
<?
> ref
, boolean isImageGallery
, boolean createNewIfNotExists
) {
1004 return docImport
.getTaxonDescription(taxon
, isImageGallery
, createNewIfNotExists
);
1009 * Returns the default language defined in the state. If no default language is defined in the state,
1010 * the CDM default language is returned.
1014 protected Language
getDefaultLanguage(MarkupImportState state
) {
1015 Language result
= state
.getDefaultLanguage();
1016 if (result
== null){
1017 result
= Language
.DEFAULT();
1023 //*********************** FROM XML IMPORT BASE ****************************************
1024 protected boolean isEndingElement(XMLEvent event
, String elName
) throws XMLStreamException
{
1025 return docImport
.isEndingElement(event
, elName
);
1028 protected boolean isStartingElement(XMLEvent event
, String elName
) throws XMLStreamException
{
1029 return docImport
.isStartingElement(event
, elName
);
1033 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon
, Taxon childTaxon
) {
1034 docImport
.fillMissingEpithetsForTaxa(parentTaxon
, childTaxon
);
1037 protected Feature
getFeature(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<Feature
> voc
){
1038 return docImport
.getFeature(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1041 protected ExtensionType
getExtensionType(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
1042 return docImport
.getExtensionType(state
, uuid
, label
, text
, labelAbbrev
);
1045 protected DefinedTerm
getIdentifierType(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<DefinedTerm
> voc
){
1046 return docImport
.getIdentifierType(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1049 protected AnnotationType
getAnnotationType(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<AnnotationType
> voc
){
1050 return docImport
.getAnnotationType(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1053 protected MarkerType
getMarkerType(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<MarkerType
> voc
){
1054 return docImport
.getMarkerType(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1057 protected NamedAreaLevel
getNamedAreaLevel(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<NamedAreaLevel
> voc
){
1058 return docImport
.getNamedAreaLevel(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1061 protected NamedArea
getNamedArea(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
, TermMatchMode matchMode
){
1062 return docImport
.getNamedArea(state
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, voc
, matchMode
);
1065 protected Language
getLanguage(MarkupImportState state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<?
> voc
){
1066 return docImport
.getLanguage(state
, uuid
, label
, text
, labelAbbrev
, voc
);
1069 // *************************************** Concrete methods **********************************************/
1078 protected Rank
makeRank(MarkupImportState state
, String value
, boolean byAbbrev
) {
1080 if (StringUtils
.isBlank(value
)) {
1084 boolean useUnknown
= true;
1085 NomenclaturalCode nc
= makeNomenclaturalCode(state
);
1086 if (value
.equals(GENUS_ABBREVIATION
)){
1087 rank
= Rank
.GENUS();
1088 }else if (byAbbrev
) {
1089 rank
= Rank
.getRankByIdInVoc(value
, nc
, useUnknown
);
1091 rank
= Rank
.getRankByEnglishName(value
, nc
, useUnknown
);
1093 if (rank
.equals(Rank
.UNKNOWN_RANK())) {
1096 if (rank
== null && "sous-genre".equalsIgnoreCase(value
)){
1097 rank
= Rank
.SUBGENUS();
1099 } catch (UnknownCdmTypeException e
) {
1107 protected TeamOrPersonBase
<?
> createAuthor(String authorTitle
) {
1108 // TODO atomize and also use by name creation
1109 TeamOrPersonBase
<?
> result
= Team
.NewTitledInstance(authorTitle
, authorTitle
);
1113 protected String
getAndRemoveMapKey(Map
<String
, String
> map
, String key
) {
1114 String result
= map
.get(key
);
1116 if (result
!= null) {
1117 result
= normalize(result
);
1119 return StringUtils
.stripToNull(result
);
1124 * Creates a {@link NonViralName} object depending on the defined {@link NomenclaturalCode}
1125 * and the given parameters.
1130 protected NonViralName
<?
> createNameByCode(MarkupImportState state
, Rank rank
) {
1131 NonViralName
<?
> name
;
1132 NomenclaturalCode nc
= makeNomenclaturalCode(state
);
1133 name
= (NonViralName
<?
>) nc
.getNewTaxonNameInstance(rank
);
1137 protected void handleFullName(MarkupImportState state
, XMLEventReader reader
,
1138 NonViralName
<?
> name
, XMLEvent next
) throws XMLStreamException
{
1140 Map
<String
, Attribute
> attrs
= getAttributes(next
);
1141 String rankStr
= getAndRemoveRequiredAttributeValue(next
,
1143 Rank rank
= makeRank(state
, rankStr
, false);
1146 String message
= "Rank was computed as null. This must not be.";
1147 fireWarningEvent(message
, next
, 6);
1148 name
.setRank(Rank
.UNKNOWN_RANK());
1150 if (!attrs
.isEmpty()) {
1151 handleUnexpectedAttributes(next
.getLocation(), attrs
);
1153 // next = readNoWhitespace(reader);
1154 fullNameStr
= getCData(state
, reader
, next
, false);
1155 NonViralNameParserImpl
.NewInstance().parseFullName(name
, fullNameStr
, rank
, false);
1156 // name.setTitleCache(fullNameStr, true);
1161 * Returns the {@link NomenclaturalCode} for this import. Default is {@link NomenclaturalCode#ICBN} if
1162 * no code is defined.
1166 protected NomenclaturalCode
makeNomenclaturalCode(MarkupImportState state
) {
1167 NomenclaturalCode nc
= state
.getConfig().getNomenclaturalCode();
1169 nc
= NomenclaturalCode
.ICNAFP
; // default;
1177 * @param levelString
1181 protected NamedAreaLevel
makeNamedAreaLevel(MarkupImportState state
, String levelString
, XMLEvent next
) {
1182 NamedAreaLevel level
;
1184 level
= state
.getTransformer().getNamedAreaLevelByKey(levelString
);
1185 if (level
== null) {
1186 UUID levelUuid
= state
.getTransformer().getNamedAreaLevelUuid(levelString
);
1187 if (levelUuid
== null) {
1188 String message
= "Unknown distribution locality class (named area level): %s. Create new level instead.";
1189 message
= String
.format(message
, levelString
);
1190 fireWarningEvent(message
, next
, 6);
1192 level
= getNamedAreaLevel(state
, levelUuid
, levelString
, levelString
, levelString
, null);
1194 } catch (UndefinedTransformerMethodException e
) {
1195 throw new RuntimeException(e
);
1207 protected NamedArea
makeArea(MarkupImportState state
, String areaName
, NamedAreaLevel level
) {
1209 //TODO FM vocabulary
1210 TermVocabulary
<NamedArea
> voc
= null;
1211 NamedAreaType areaType
= null;
1213 NamedArea area
= null;
1215 area
= state
.getTransformer().getNamedAreaByKey(areaName
);
1216 } catch (UndefinedTransformerMethodException e
) {
1217 throw new RuntimeException(e
);
1220 boolean isNewInState
= false;
1221 UUID uuid
= state
.getAreaUuid(areaName
);
1223 isNewInState
= true;
1227 uuid
= state
.getTransformer().getNamedAreaUuid(areaName
);
1228 } catch (UndefinedTransformerMethodException e
) {
1229 throw new RuntimeException(e
);
1233 CdmImportBase
.TermMatchMode matchMode
= CdmImportBase
.TermMatchMode
.UUID_LABEL
;
1234 area
= getNamedArea(state
, uuid
, areaName
, areaName
, areaName
, areaType
, level
, voc
, matchMode
);
1236 state
.putAreaUuid(areaName
, area
.getUuid());
1238 //TODO just for testing -> make generic and move to better place
1239 String geoServiceLayer
="vmap0_as_bnd_political_boundary_a";
1240 String layerFieldName
="nam";
1242 if ("Bangka".equals(areaName
)){
1243 String areaValue
= "PULAU BANGKA#SUMATERA SELATAN";
1244 GeoServiceArea geoServiceArea
= new GeoServiceArea();
1245 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
1246 this.editGeoService
.setMapping(area
, geoServiceArea
);
1247 // save(area, state);
1249 if ("Luzon".equals(areaName
)){
1250 GeoServiceArea geoServiceArea
= new GeoServiceArea();
1252 List
<String
> list
= Arrays
.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON",
1253 "HERMANA MENOR ISLAND#CENTRAL LUZON",
1255 for (String areaValue
: list
){
1256 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
1259 this.editGeoService
.setMapping(area
, geoServiceArea
);
1260 // save(area, state);
1262 if ("Mindanao".equals(areaName
)){
1263 GeoServiceArea geoServiceArea
= new GeoServiceArea();
1265 List
<String
> list
= Arrays
.asList("NORTHERN MINDANAO",
1266 "SOUTHERN MINDANAO",
1267 "WESTERN MINDANAO");
1268 //TODO to be continued
1269 for (String areaValue
: list
){
1270 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
1273 this.editGeoService
.setMapping(area
, geoServiceArea
);
1274 // save(area, state);
1276 if ("Palawan".equals(areaName
)){
1277 GeoServiceArea geoServiceArea
= new GeoServiceArea();
1279 List
<String
> list
= Arrays
.asList("PALAWAN#SOUTHERN TAGALOG");
1280 for (String areaValue
: list
){
1281 geoServiceArea
.add(geoServiceLayer
, layerFieldName
, areaValue
);
1284 this.editGeoService
.setMapping(area
, geoServiceArea
);
1285 // save(area, state);
1296 * Reads character data. Any element other than character data or the ending
1297 * tag will fire an unexpected element event.
1299 * @see #getCData(MarkupImportState, XMLEventReader, XMLEvent, boolean)
1304 * @throws XMLStreamException
1306 protected String
getCData(MarkupImportState state
, XMLEventReader reader
, XMLEvent next
) throws XMLStreamException
{
1307 return getCData(state
, reader
, next
, true);
1311 * Reads character data. Any element other than character data or the ending
1312 * tag will fire an unexpected element event.
1317 * @param inlineMarkup map for inline markup, this is used for e.g. the locality markup within a subheading
1318 * The map will be filled by the markup element name as key. The value may be a String, a CdmBase or any other object.
1319 * If null any markup text will be neglected but a warning will be fired if they exist.
1320 * @param removeInlineMarkupText if true the markedup text will be removed from the returned String
1321 * @param checkAttributes
1323 * @throws XMLStreamException
1325 protected String
getCData(MarkupImportState state
, XMLEventReader reader
, XMLEvent parent
, /*Map<String, Object> inlineMarkup, *boolean removeInlineMarkupText,*/ boolean checkAttributes
) throws XMLStreamException
{
1326 if (checkAttributes
){
1327 checkNoAttributes(parent
);
1331 while (reader
.hasNext()) {
1332 XMLEvent next
= readNoWhitespace(reader
);
1333 if (isMyEndingElement(next
, parent
)) {
1335 } else if (next
.isCharacters()) {
1336 text
+= next
.asCharacters().getData();
1337 } else if (isStartingElement(next
, FOOTNOTE_REF
)){
1338 handleNotYetImplementedElement(next
);
1339 // } else if (isStartingElement(next, LOCALITY)){
1340 // handleCDataLocality(state, reader, parent);
1342 handleUnexpectedElement(next
);
1345 throw new IllegalStateException("Event has no closing tag");
1349 // private void handleCDataLocality(MarkupImportState state, XMLEventReader reader, XMLEvent parent) {
1350 // checkAndRemoveAttributeValue(attributes, attrName, value)
1357 * For it returns a pure CData annotation string. This behaviour may change in future. More complex annotations
1358 * should be handled differently.
1361 * @param parentEvent
1363 * @throws XMLStreamException
1365 protected String
handleSimpleAnnotation(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1366 String annotation
= getCData(state
, reader
, parentEvent
);
1371 * True if text is single "." oder "," or ";" or ":"
1375 protected boolean isPunctuation(String text
) {
1376 return text
== null ?
false : text
.trim().matches("^[\\.,;:]$");
1381 * Text indicating that type information is following but no information about the type of the type
1385 protected boolean charIsSimpleType(String text
) {
1386 return text
.matches("(?i)Type:");
1389 protected String
getXmlTag(XMLEvent event
) {
1391 if (event
.isStartElement()) {
1392 result
= "<" + event
.asStartElement().getName().getLocalPart()
1394 } else if (event
.isEndElement()) {
1395 result
= "</" + event
.asEndElement().getName().getLocalPart() + ">";
1397 String message
= "Only start or end elements are allowed as Html tags";
1398 throw new IllegalStateException(message
);
1403 protected WriterDataHolder
handleWriter(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
) throws XMLStreamException
{
1405 checkNoAttributes(parentEvent
);
1406 WriterDataHolder dataHolder
= new WriterDataHolder();
1407 List
<FootnoteDataHolder
> footnotes
= new ArrayList
<FootnoteDataHolder
>();
1409 // TODO handle attributes
1410 while (reader
.hasNext()) {
1411 XMLEvent next
= readNoWhitespace(reader
);
1412 if (isMyEndingElement(next
, parentEvent
)) {
1413 text
= CdmUtils
.removeBrackets(text
);
1414 if (checkMandatoryText(text
, parentEvent
)) {
1415 text
= normalize(text
);
1416 dataHolder
.writer
= text
;
1417 dataHolder
.footnotes
= footnotes
;
1420 UUID uuidWriterExtension
= MarkupTransformer
.uuidWriterExtension
;
1421 ExtensionType writerExtensionType
=
1422 this.getExtensionType(state
, uuidWriterExtension
,"Writer", "writer", "writer");
1423 Extension extension
= Extension
.NewInstance();
1424 extension
.setType(writerExtensionType
);
1425 extension
.setValue(text
);
1426 dataHolder
.extension
= extension
;
1429 UUID uuidWriterAnnotation
= MarkupTransformer
.uuidWriterAnnotation
;
1430 AnnotationType writerAnnotationType
= this.getAnnotationType(state
, uuidWriterAnnotation
, "Writer", "writer", "writer", null);
1431 Annotation annotation
= Annotation
.NewInstance(text
, writerAnnotationType
, getDefaultLanguage(state
));
1432 dataHolder
.annotation
= annotation
;
1438 } else if (isStartingElement(next
, FOOTNOTE_REF
)) {
1439 FootnoteDataHolder footNote
= handleFootnoteRef(state
, reader
, next
);
1440 if (footNote
.isRef()) {
1441 footnotes
.add(footNote
);
1443 logger
.warn("Non ref footnotes not yet impelemnted");
1445 } else if (next
.isCharacters()) {
1446 text
+= next
.asCharacters().getData();
1449 handleUnexpectedElement(next
);
1450 state
.setUnsuccessfull();
1453 throw new IllegalStateException("<writer> has no end tag");
1457 protected void registerFootnotes(MarkupImportState state
, AnnotatableEntity entity
, List
<FootnoteDataHolder
> footnotes
) {
1458 for (FootnoteDataHolder footNote
: footnotes
) {
1459 registerFootnoteDemand(state
, entity
, footNote
);
1464 private void registerFootnoteDemand(MarkupImportState state
, AnnotatableEntity entity
, FootnoteDataHolder footnote
) {
1465 FootnoteDataHolder existingFootnote
= state
.getFootnote(footnote
.ref
);
1466 if (existingFootnote
!= null) {
1467 attachFootnote(state
, entity
, existingFootnote
);
1469 Set
<AnnotatableEntity
> demands
= state
.getFootnoteDemands(footnote
.ref
);
1470 if (demands
== null) {
1471 demands
= new HashSet
<AnnotatableEntity
>();
1472 state
.putFootnoteDemands(footnote
.ref
, demands
);
1474 demands
.add(entity
);
1479 protected void attachFootnote(MarkupImportState state
, AnnotatableEntity entity
, FootnoteDataHolder footnote
) {
1480 AnnotationType annotationType
= this.getAnnotationType(state
, MarkupTransformer
.uuidFootnote
, "Footnote", "An e-flora footnote", "fn", null);
1481 Annotation annotation
= Annotation
.NewInstance(footnote
.string
, annotationType
, getDefaultLanguage(state
));
1482 // TODO transient objects
1483 entity
.addAnnotation(annotation
);
1484 save(entity
, state
);
1488 protected void attachFigure(MarkupImportState state
, XMLEvent next
, AnnotatableEntity entity
, Media figure
) {
1489 // IdentifiableEntity<?> toSave;
1490 if (entity
.isInstanceOf(TextData
.class)) {
1491 TextData deb
= CdmBase
.deproxy(entity
, TextData
.class);
1492 deb
.addMedia(figure
);
1493 // toSave = ((TaxonDescription)deb.getInDescription()).getTaxon();
1494 } else if (entity
.isInstanceOf(SpecimenOrObservationBase
.class)) {
1495 String message
= "figures for specimen should be handled as Textdata";
1496 fireWarningEvent(message
, next
, 4);
1498 } else if (entity
.isInstanceOf(IdentifiableMediaEntity
.class)) {
1499 IdentifiableMediaEntity
<?
> ime
= CdmBase
.deproxy(entity
, IdentifiableMediaEntity
.class);
1500 ime
.addMedia(figure
);
1503 String message
= "Unsupported entity to attach media: %s";
1504 message
= String
.format(message
, entity
.getClass().getName());
1507 save(entity
, state
);
1511 protected void registerGivenFootnote(MarkupImportState state
, FootnoteDataHolder footnote
) {
1512 state
.registerFootnote(footnote
);
1513 Set
<AnnotatableEntity
> demands
= state
.getFootnoteDemands(footnote
.id
);
1514 if (demands
!= null) {
1515 for (AnnotatableEntity entity
: demands
) {
1516 attachFootnote(state
, entity
, footnote
);
1522 protected FootnoteDataHolder
handleFootnote(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
,
1523 MarkupSpecimenImport specimenImport
, MarkupNomenclatureImport nomenclatureImport
) throws XMLStreamException
{
1524 FootnoteDataHolder result
= new FootnoteDataHolder();
1525 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1526 result
.id
= getAndRemoveAttributeValue(attributes
, ID
);
1527 // result.ref = getAndRemoveAttributeValue(attributes, REF);
1528 checkNoAttributes(attributes
, parentEvent
);
1530 while (reader
.hasNext()) {
1531 XMLEvent next
= readNoWhitespace(reader
);
1532 if (isStartingElement(next
, FOOTNOTE_STRING
)) {
1533 String string
= handleFootnoteString(state
, reader
, next
, specimenImport
, nomenclatureImport
);
1534 result
.string
= string
;
1535 } else if (isMyEndingElement(next
, parentEvent
)) {
1538 fireUnexpectedEvent(next
, 0);
1545 protected Media
handleFigure(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
,
1546 MarkupSpecimenImport specimenImport
, MarkupNomenclatureImport nomenclatureImport
) throws XMLStreamException
{
1547 // FigureDataHolder result = new FigureDataHolder();
1549 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1550 String id
= getAndRemoveAttributeValue(attributes
, ID
);
1551 String type
= getAndRemoveAttributeValue(attributes
, TYPE
);
1552 String urlAttr
= getAndRemoveAttributeValue(attributes
, URL
);
1553 checkNoAttributes(attributes
, parentEvent
);
1555 String urlString
= null;
1556 String legendString
= null;
1557 String titleString
= null;
1558 String numString
= null;
1560 if (isNotBlank(urlAttr
)){
1561 urlString
= CdmUtils
.Nz(state
.getBaseMediaUrl()) + urlAttr
;
1563 while (reader
.hasNext()) {
1564 XMLEvent next
= readNoWhitespace(reader
);
1565 if (isMyEndingElement(next
, parentEvent
)) {
1566 if (isNotBlank(text
)){
1567 fireWarningEvent("Text not yet handled for figures: " + text
, next
, 4);
1569 Media media
= makeFigure(state
, id
, type
, urlString
, legendString
, titleString
, numString
, next
);
1571 } else if (isStartingElement(next
, FIGURE_LEGEND
)) {
1572 // TODO same as figure string ?
1573 legendString
= handleFootnoteString(state
, reader
, next
, specimenImport
, nomenclatureImport
);
1574 } else if (isStartingElement(next
, FIGURE_TITLE
)) {
1575 titleString
= getCData(state
, reader
, next
);
1576 } else if (isStartingElement(next
, URL
)) {
1577 String localUrl
= getCData(state
, reader
, next
);
1578 String url
= CdmUtils
.Nz(state
.getBaseMediaUrl()) + localUrl
;
1579 if (isBlank(urlString
)){
1582 if (! url
.equals(urlString
)){
1583 String message
= "URL attribute and URL element differ. Attribute: %s, Element: %s";
1584 fireWarningEvent(String
.format(message
, urlString
, url
), next
, 2);
1586 } else if (isStartingElement(next
, NUM
)) {
1587 numString
= getCData(state
, reader
, next
);
1588 } else if (next
.isCharacters()) {
1589 text
+= CdmUtils
.concat("", text
, next
.asCharacters().getData());
1591 fireUnexpectedEvent(next
, 0);
1594 throw new IllegalStateException("<figure> has no end tag");
1603 * @param legendString
1604 * @param titleString
1608 private Media
makeFigure(MarkupImportState state
, String id
, String type
, String urlString
,
1609 String legendString
, String titleString
, String numString
, XMLEvent next
) {
1611 // boolean isFigure = false; //no difference between figure and media since v3.3
1613 //TODO maybe everything is a figure as it is all taken from a book
1614 if ("lineart".equals(type
)) {
1616 // media = Figure.NewInstance(url.toURI(), null, null, null);
1617 } else if (type
== null || "photo".equals(type
)
1618 || "signature".equals(type
)
1619 || "others".equals(type
)) {
1622 String message
= "Unknown figure type '%s'";
1623 message
= String
.format(message
, type
);
1624 fireWarningEvent(message
, next
, 2);
1626 media
= docImport
.getImageMedia(urlString
, docImport
.getReadMediaData());
1630 if (StringUtils
.isNotBlank(titleString
)) {
1631 media
.putTitle(getDefaultLanguage(state
), titleString
);
1634 if (StringUtils
.isNotBlank(legendString
)) {
1635 media
.putDescription(getDefaultLanguage(state
), legendString
);
1637 if (StringUtils
.isNotBlank(numString
)) {
1638 // TODO use concrete source (e.g. DAPHNIPHYLLACEAE in FM
1640 Reference
<?
> citation
= state
.getConfig().getSourceReference();
1641 media
.addSource(OriginalSourceType
.Import
, numString
, "num", citation
, null);
1642 // TODO name used in source if available
1644 // TODO which citation
1645 if (StringUtils
.isNotBlank(id
)) {
1646 media
.addSource(OriginalSourceType
.Import
, id
, null, state
.getConfig().getSourceReference(), null);
1648 String message
= "Figure id should never be empty or null";
1649 fireWarningEvent(message
, next
, 6);
1654 registerGivenFigure(state
, next
, id
, media
);
1657 String message
= "No media found: ";
1658 fireWarningEvent(message
, next
, 4);
1660 } catch (MalformedURLException e
) {
1661 String message
= "Media uri has incorrect syntax: %s";
1662 message
= String
.format(message
, urlString
);
1663 fireWarningEvent(message
, next
, 4);
1664 // } catch (URISyntaxException e) {
1665 // String message = "Media uri has incorrect syntax: %s";
1666 // message = String.format(message, urlString);
1667 // fireWarningEvent(message, next, 4);
1674 private void registerGivenFigure(MarkupImportState state
, XMLEvent next
, String id
, Media figure
) {
1675 state
.registerFigure(id
, figure
);
1676 Set
<AnnotatableEntity
> demands
= state
.getFigureDemands(id
);
1677 if (demands
!= null) {
1678 for (AnnotatableEntity entity
: demands
) {
1679 attachFigure(state
, next
, entity
, figure
);
1682 save(figure
, state
);
1686 private FootnoteDataHolder
handleFootnoteRef(MarkupImportState state
,
1687 XMLEventReader reader
, XMLEvent parentEvent
)
1688 throws XMLStreamException
{
1689 FootnoteDataHolder result
= new FootnoteDataHolder();
1690 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1691 result
.ref
= getAndRemoveAttributeValue(attributes
, REF
);
1692 checkNoAttributes(attributes
, parentEvent
);
1694 // text is not handled, needed only for debugging purposes
1696 while (reader
.hasNext()) {
1697 XMLEvent next
= readNoWhitespace(reader
);
1698 // if (isStartingElement(next, FOOTNOTE_STRING)){
1699 // String string = handleFootnoteString(state, reader, next);
1700 // result.string = string;
1702 if (isMyEndingElement(next
, parentEvent
)) {
1703 if (StringUtils
.isNotBlank(text
)){
1704 fireWarningEvent("text is not empty but not handled during import", parentEvent
, 4);
1707 } else if (next
.isCharacters() && unhandledElements
.isEmpty()) {
1708 text
+= next
.asCharacters().getData();
1709 } else if (isStartingElement(next
, NUM
)) {
1710 //ignore numbering of footnotes as they are numbered differently in the CDM
1711 handleIgnoreElement(next
);
1713 handleUnexpectedElement(next
);
1721 private String
handleFootnoteString(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
, MarkupSpecimenImport specimenImport
, MarkupNomenclatureImport nomenclatureImport
) throws XMLStreamException
{
1722 boolean isTextMode
= true;
1724 while (reader
.hasNext()) {
1725 XMLEvent next
= readNoWhitespace(reader
);
1726 if (isMyEndingElement(next
, parentEvent
)) {
1728 } else if (next
.isEndElement()) {
1729 if (isEndingElement(next
, FULL_NAME
)) {
1730 popUnimplemented(next
.asEndElement());
1731 } else if (isEndingElement(next
, BR
)) {
1733 } else if (isHtml(next
)) {
1734 text
+= getXmlTag(next
);
1736 handleUnexpectedEndElement(next
.asEndElement());
1738 } else if (next
.isStartElement()) {
1739 if (isStartingElement(next
, FULL_NAME
)) {
1740 handleNotYetImplementedElement(next
);
1741 } else if (isStartingElement(next
, GATHERING
)) {
1742 text
+= specimenImport
.handleInLineGathering(state
, reader
, next
);
1743 } else if (isStartingElement(next
, REFERENCES
)) {
1744 text
+= " " + handleInLineReferences(state
, reader
, next
, nomenclatureImport
)+ " ";
1745 } else if (isStartingElement(next
, BR
)) {
1748 } else if (isStartingElement(next
, NOMENCLATURE
)) {
1749 handleNotYetImplementedElement(next
);
1750 } else if (isHtml(next
)) {
1751 text
+= getXmlTag(next
);
1753 handleUnexpectedStartElement(next
.asStartElement());
1755 } else if (next
.isCharacters()) {
1757 String message
= "footnoteString is not in text mode";
1758 fireWarningEvent(message
, next
, 6);
1760 text
+= next
.asCharacters().getData().trim();
1761 // getCData(state, reader, next); does not work as we have inner tags like <references>
1764 handleUnexpectedEndElement(next
.asEndElement());
1767 throw new IllegalStateException("<footnoteString> has no closing tag");
1771 private static final List
<String
> htmlList
= Arrays
.asList("sub", "sup",
1772 "ol", "ul", "li", "i", "b", "table", "br","tr","td");
1774 protected boolean isHtml(XMLEvent event
) {
1775 if (event
.isStartElement()) {
1776 String tag
= event
.asStartElement().getName().getLocalPart();
1777 return htmlList
.contains(tag
);
1778 } else if (event
.isEndElement()) {
1779 String tag
= event
.asEndElement().getName().getLocalPart();
1780 return htmlList
.contains(tag
);
1788 private String
handleInLineReferences(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
, MarkupNomenclatureImport nomenclatureImport
) throws XMLStreamException
{
1789 checkNoAttributes(parentEvent
);
1791 boolean hasReference
= false;
1793 while (reader
.hasNext()) {
1794 XMLEvent next
= readNoWhitespace(reader
);
1795 if (isMyEndingElement(next
, parentEvent
)) {
1796 checkMandatoryElement(hasReference
, parentEvent
.asStartElement(), REFERENCE
);
1798 } else if (isStartingElement(next
, REFERENCE
)) {
1799 text
+= handleInLineReference(state
, reader
, next
, nomenclatureImport
);
1800 hasReference
= true;
1802 handleUnexpectedElement(next
);
1805 throw new IllegalStateException("<References> has no closing tag");
1808 private String
handleInLineReference(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
, MarkupNomenclatureImport nomenclatureImport
)throws XMLStreamException
{
1809 Reference
<?
> reference
= nomenclatureImport
.handleReference(state
, reader
, parentEvent
);
1810 String result
= "<cdm:ref uuid='%s'>%s</ref>";
1811 result
= String
.format(result
, reference
.getUuid(), reference
.getTitleCache());
1812 save(reference
, state
);
1821 * @param parentEvent
1822 * @param feature only needed for distributionLocalities
1824 * @throws XMLStreamException
1826 protected Map
<String
, String
> handleString(MarkupImportState state
, XMLEventReader reader
, XMLEvent parentEvent
, Feature feature
)throws XMLStreamException
{
1828 String classValue
= getClassOnlyAttribute(parentEvent
, false);
1829 if (StringUtils
.isNotBlank(classValue
)) {
1830 String message
= "class attribute for <string> not yet implemented";
1831 fireWarningEvent(message
, parentEvent
, 2);
1835 Map
<String
, String
> subHeadingMap
= new HashMap
<String
, String
>();
1836 String currentSubheading
= null;
1838 boolean isTextMode
= true;
1840 while (reader
.hasNext()) {
1841 XMLEvent next
= readNoWhitespace(reader
);
1842 if (isMyEndingElement(next
, parentEvent
)) {
1843 putCurrentSubheading(subHeadingMap
, currentSubheading
, text
);
1844 return subHeadingMap
;
1845 } else if (isStartingElement(next
, BR
)) {
1848 } else if (isEndingElement(next
, BR
)) {
1850 } else if (isHtml(next
)) {
1851 text
+= getXmlTag(next
);
1852 } else if (isStartingElement(next
, SUB_HEADING
)) {
1853 text
= putCurrentSubheading(subHeadingMap
,currentSubheading
, text
);
1855 currentSubheading
= getCData(state
, reader
, next
).trim();
1856 } else if (isStartingElement(next
, DISTRIBUTION_LOCALITY
)) {
1857 if (feature
!= null && !feature
.equals(Feature
.DISTRIBUTION())) {
1858 String message
= "Distribution locality only allowed for feature of type 'distribution'";
1859 fireWarningEvent(message
, next
, 4);
1861 text
+= handleDistributionLocality(state
, reader
, next
);
1862 } else if (next
.isCharacters()) {
1864 String message
= "String is not in text mode";
1865 fireWarningEvent(message
, next
, 6);
1867 text
+= next
.asCharacters().getData();
1869 } else if (isStartingElement(next
, HEADING
)) {
1871 handleNotYetImplementedElement(next
);
1872 } else if (isStartingElement(next
, VERNACULAR_NAMES
)) {
1874 handleNotYetImplementedElement(next
);
1875 } else if (isStartingElement(next
, QUOTE
)) {
1877 handleNotYetImplementedElement(next
);
1878 } else if (isStartingElement(next
, DEDICATION
)) {
1880 handleNotYetImplementedElement(next
);
1881 } else if (isStartingElement(next
, TAXONTYPE
)) {
1883 handleNotYetImplementedElement(next
);
1884 } else if (isStartingElement(next
, FULL_NAME
)) {
1886 handleNotYetImplementedElement(next
);
1887 }else if (isStartingElement(next
, REFERENCES
)) {
1889 handleNotYetImplementedElement(next
);
1890 } else if (isStartingElement(next
, GATHERING
)) {
1892 handleNotYetImplementedElement(next
);
1893 } else if (isStartingElement(next
, ANNOTATION
)) {
1894 //TODO //TODO test handleSimpleAnnotation
1895 handleNotYetImplementedElement(next
);
1896 } else if (isStartingElement(next
, HABITAT
)) {
1898 handleNotYetImplementedElement(next
);
1899 } else if (isStartingElement(next
, FIGURE_REF
)) {
1901 handleNotYetImplementedElement(next
);
1902 } else if (isStartingElement(next
, FIGURE
)) {
1904 handleNotYetImplementedElement(next
);
1905 } else if (isStartingElement(next
, FOOTNOTE_REF
)) {
1907 handleNotYetImplementedElement(next
);
1908 } else if (isStartingElement(next
, FOOTNOTE
)) {
1910 handleNotYetImplementedElement(next
);
1911 } else if (isStartingElement(next
, WRITER
)) {
1913 handleNotYetImplementedElement(next
);
1914 } else if (isStartingElement(next
, DATES
)) {
1916 handleNotYetImplementedElement(next
);
1918 handleUnexpectedElement(next
);
1921 throw new IllegalStateException("<String> has no closing tag");
1926 * @param subHeadingMap
1927 * @param currentSubheading
1931 private String
putCurrentSubheading(Map
<String
, String
> subHeadingMap
, String currentSubheading
, String text
) {
1932 if (StringUtils
.isNotBlank(text
)) {
1933 text
= removeStartingMinus(text
);
1934 subHeadingMap
.put(currentSubheading
, text
.trim());
1939 private String
removeStartingMinus(String string
) {
1940 string
= replaceStart(string
, "-");
1941 string
= replaceStart(string
, "\u002d");
1942 string
= replaceStart(string
, "\u2013");
1943 string
= replaceStart(string
, "\u2014");
1944 string
= replaceStart(string
, "--");
1951 * @param replacementString
1953 private String
replaceStart(String value
, String replacementString
) {
1954 if (value
.startsWith(replacementString
) ){
1955 value
= value
.substring(replacementString
.length()).trim();
1957 while (value
.startsWith("-") || value
.startsWith("\u2014") ){
1958 value
= value
.substring("-".length()).trim();
1964 private String
handleDistributionLocality(MarkupImportState state
,XMLEventReader reader
, XMLEvent parentEvent
)throws XMLStreamException
{
1965 Map
<String
, Attribute
> attributes
= getAttributes(parentEvent
);
1966 String classValue
= getAndRemoveRequiredAttributeValue(parentEvent
, attributes
, CLASS
);
1967 String statusValue
=getAndRemoveAttributeValue(attributes
, STATUS
);
1968 String frequencyValue
=getAndRemoveAttributeValue(attributes
, FREQUENCY
);
1971 Taxon taxon
= state
.getCurrentTaxon();
1972 // TODO which ref to take?
1973 Reference
<?
> ref
= state
.getConfig().getSourceReference();
1976 while (reader
.hasNext()) {
1977 XMLEvent next
= readNoWhitespace(reader
);
1978 if (isMyEndingElement(next
, parentEvent
)) {
1979 if (StringUtils
.isNotBlank(text
)) {
1980 String label
= CdmUtils
.removeTrailingDot(normalize(text
));
1981 TaxonDescription description
= getTaxonDescription(taxon
, ref
, false, true);
1982 NamedAreaLevel level
= makeNamedAreaLevel(state
,classValue
, next
);
1985 PresenceAbsenceTerm status
= null;
1986 if (isNotBlank(statusValue
)){
1988 status
= state
.getTransformer().getPresenceTermByKey(statusValue
);
1989 if (status
== null){
1991 String message
= "The presence/absence status '%s' could not be transformed to an CDM status";
1992 fireWarningEvent(String
.format(message
, statusValue
), next
, 4);
1994 } catch (UndefinedTransformerMethodException e
) {
1995 throw new RuntimeException(e
);
1998 status
= PresenceAbsenceTerm
.PRESENT();
2001 if (isNotBlank(frequencyValue
)){
2002 String message
= "The frequency attribute is currently not yet available in CDM";
2003 fireWarningEvent(message
, parentEvent
, 6);
2006 NamedArea higherArea
= null;
2007 List
<NamedArea
> areas
= new ArrayList
<NamedArea
>();
2009 String patSingleArea
= "([^,\\(]{3,})";
2010 String patSeparator
= "(,|\\sand\\s)";
2011 String hierarchiePattern
= String
.format("%s\\((%s(%s%s)*)\\)",patSingleArea
, patSingleArea
, patSeparator
, patSingleArea
);
2012 Pattern patHierarchie
= Pattern
.compile(hierarchiePattern
, Pattern
.CASE_INSENSITIVE
);
2013 Matcher matcher
= patHierarchie
.matcher(label
);
2014 if (matcher
.matches()){
2015 String higherAreaStr
= matcher
.group(1).trim();
2016 higherArea
= makeArea(state
, higherAreaStr
, level
);
2017 String
[] innerAreas
= matcher
.group(2).split(patSeparator
);
2018 for (String innerArea
: innerAreas
){
2019 if (isNotBlank(innerArea
)){
2020 NamedArea singleArea
= makeArea(state
, innerArea
.trim(), level
);
2021 areas
.add(singleArea
);
2022 NamedArea partOf
= singleArea
.getPartOf();
2023 // if (partOf == null){
2024 // singleArea.setPartOf(higherArea);
2029 NamedArea singleArea
= makeArea(state
, label
, level
);
2030 areas
.add(singleArea
);
2033 for (NamedArea area
: areas
){
2034 //create distribution
2035 Distribution distribution
= Distribution
.NewInstance(area
,status
);
2036 description
.addElement(distribution
);
2039 String message
= "Empty distribution locality";
2040 fireWarningEvent(message
, next
, 4);
2043 } else if (isStartingElement(next
, COORDINATES
)) {
2045 handleNotYetImplementedElement(next
);
2046 } else if (isEndingElement(next
, COORDINATES
)) {
2048 popUnimplemented(next
.asEndElement());
2049 } else if (next
.isCharacters()) {
2050 text
+= next
.asCharacters().getData();
2052 handleUnexpectedElement(next
);
2055 throw new IllegalStateException("<DistributionLocality> has no closing tag");
2059 //********************************************** OLD *************************************
2061 // protected boolean testAdditionalElements(Element parentElement, List<String> excludeList){
2062 // boolean result = true;
2063 // List<Element> list = parentElement.getChildren();
2064 // for (Element element : list){
2065 // if (! excludeList.contains(element.getName())){
2066 // logger.warn("Unknown element (" + element.getName() + ") in parent element (" + parentElement.getName() + ")");
2074 // protected <T extends IdentifiableEntity> T makeReferenceType(Element element, Class<? extends T> clazz, MapWrapper<? extends T> objectMap, ResultWrapper<Boolean> success){
2076 // String linkType = element.getAttributeValue("linkType");
2077 // String ref = element.getAttributeValue("ref");
2078 // if(ref == null && linkType == null){
2079 // result = getInstance(clazz);
2080 // if (result != null){
2081 // String title = element.getTextNormalize();
2082 // result.setTitleCache(title, true);
2084 // }else if (linkType == null || linkType.equals("local")){
2086 // result = objectMap.get(ref);
2087 // if (result == null){
2088 // logger.warn("Object (ref = " + ref + ")could not be found in WrapperMap");
2090 // }else if(linkType.equals("external")){
2091 // logger.warn("External link types not yet implemented");
2092 // }else if(linkType.equals("other")){
2093 // logger.warn("Other link types not yet implemented");
2095 // logger.warn("Unknown link type or missing ref");
2097 // if (result == null){
2098 // success.setValue(false);
2104 // protected Reference makeAccordingTo(Element elAccordingTo, MapWrapper<Reference> referenceMap, ResultWrapper<Boolean> success){
2105 // Reference result = null;
2106 // if (elAccordingTo != null){
2107 // String childName = "AccordingToDetailed";
2108 // boolean obligatory = false;
2109 // Element elAccordingToDetailed = XmlHelp.getSingleChildElement(success, elAccordingTo, childName, elAccordingTo.getNamespace(), obligatory);
2111 // childName = "Simple";
2112 // obligatory = true;
2113 // Element elSimple = XmlHelp.getSingleChildElement(success, elAccordingTo, childName, elAccordingTo.getNamespace(), obligatory);
2115 // if (elAccordingToDetailed != null){
2116 // result = makeAccordingToDetailed(elAccordingToDetailed, referenceMap, success);
2118 // result = ReferenceFactory.newGeneric();
2119 // String title = elSimple.getTextNormalize();
2120 // result.setTitleCache(title, true);
2127 // private Reference makeAccordingToDetailed(Element elAccordingToDetailed, MapWrapper<Reference> referenceMap, ResultWrapper<Boolean> success){
2128 // Reference result = null;
2129 // Namespace tcsNamespace = elAccordingToDetailed.getNamespace();
2130 // if (elAccordingToDetailed != null){
2132 // String childName = "AuthorTeam";
2133 // boolean obligatory = false;
2134 // Element elAuthorTeam = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
2135 // makeAccordingToAuthorTeam(elAuthorTeam, success);
2138 // childName = "PublishedIn";
2139 // obligatory = false;
2140 // Element elPublishedIn = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
2141 // result = makeReferenceType(elPublishedIn, Reference.class, referenceMap, success);
2144 // childName = "MicroReference";
2145 // obligatory = false;
2146 // Element elMicroReference = XmlHelp.getSingleChildElement(success, elAccordingToDetailed, childName, tcsNamespace, obligatory);
2147 // String microReference = elMicroReference.getTextNormalize();
2148 // if (CdmUtils.Nz(microReference).equals("")){
2150 // logger.warn("MicroReference not yet implemented for AccordingToDetailed");
2156 // private Team makeAccordingToAuthorTeam(Element elAuthorTeam, ResultWrapper<Boolean> succes){
2157 // Team result = null;
2158 // if (elAuthorTeam != null){
2160 // logger.warn("AuthorTeam not yet implemented for AccordingToDetailed");