Added Hierarchy to imported vocabularies and abbrevated labels as well as id in source.
[cdmlib-apps.git] / app-import / src / main / java / eu / etaxonomy / cdm / io / redlist / bfnXml / BfnXmlImportTaxonName.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.io.redlist.bfnXml;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.LinkedHashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.UUID;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.jdom.Element;
22 import org.jdom.Namespace;
23 import org.springframework.stereotype.Component;
24 import org.springframework.transaction.TransactionStatus;
25
26 import eu.etaxonomy.cdm.api.service.IClassificationService;
27 import eu.etaxonomy.cdm.api.service.ITaxonService;
28 import eu.etaxonomy.cdm.common.ResultWrapper;
29 import eu.etaxonomy.cdm.common.XmlHelp;
30 import eu.etaxonomy.cdm.io.common.ICdmIO;
31 import eu.etaxonomy.cdm.model.common.CdmBase;
32 import eu.etaxonomy.cdm.model.common.Language;
33 import eu.etaxonomy.cdm.model.description.CategoricalData;
34 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
35 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
36 import eu.etaxonomy.cdm.model.description.Feature;
37 import eu.etaxonomy.cdm.model.description.State;
38 import eu.etaxonomy.cdm.model.description.TaxonDescription;
39 import eu.etaxonomy.cdm.model.description.TextData;
40 import eu.etaxonomy.cdm.model.location.NamedArea;
41 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
42 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
43 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
44 import eu.etaxonomy.cdm.model.name.NonViralName;
45 import eu.etaxonomy.cdm.model.name.Rank;
46 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
47 import eu.etaxonomy.cdm.model.taxon.Classification;
48 import eu.etaxonomy.cdm.model.taxon.Synonym;
49 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
50 import eu.etaxonomy.cdm.model.taxon.Taxon;
51 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
52 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
53 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
54 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
55 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
56 import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
57 /**
58 *
59 * @author a.oppermann
60 * @date 04.07.2013
61 *
62 */
63 //@Component("bfnXmlTaxonNameIO")
64 @Component
65 public class BfnXmlImportTaxonName extends BfnXmlImportBase implements ICdmIO<BfnXmlImportState> {
66
67
68 private static final Logger logger = Logger.getLogger(BfnXmlImportTaxonName.class);
69
70 private static String strNomenclaturalCode = null;// "Zoological";//"Botanical";
71 private static int parsingProblemCounter = 0;
72 private Map<Integer, Taxon> firstList;
73 private Map<Integer, Taxon> secondList;
74
75
76 public BfnXmlImportTaxonName(){
77 super();
78 }
79
80 @Override
81 public boolean doCheck(BfnXmlImportState state){
82 boolean result = true;
83 return result;
84 }
85
86 @Override
87 @SuppressWarnings({"rawtypes" })
88 public void doInvoke(BfnXmlImportState state){
89 ITaxonService taxonService = getTaxonService();
90
91 BfnXmlImportConfigurator config = state.getConfig();
92 strNomenclaturalCode = config.getNomenclaturalSig();
93 Element elDataSet = getDataSetElement(config);
94 //TODO set Namespace
95 Namespace bfnNamespace = config.getBfnXmlNamespace();
96
97 List<?> contentXML = elDataSet.getContent();
98 Element currentElement = null;
99 for(Object object:contentXML){
100
101 if(object instanceof Element){
102 currentElement = (Element)object;
103 //import taxon lists
104 if(currentElement.getName().equalsIgnoreCase("ROTELISTEDATEN")){
105 TransactionStatus tx = startTransaction();
106 Map<UUID, TaxonBase> savedTaxonMap = extractTaxonNames(state, taxonService, config, currentElement, bfnNamespace);
107 createOrUdateClassification(config, taxonService, savedTaxonMap, currentElement, state);
108 commitTransaction(tx);
109 }//import concept relations of taxon lists
110 if(config.isHasSecondList()){
111 if(currentElement.getName().equalsIgnoreCase("KONZEPTBEZIEHUNGEN")){
112 TransactionStatus tx = startTransaction();
113 extractTaxonConceptRelationShips(bfnNamespace,currentElement);
114 commitTransaction(tx);
115 }
116 }
117 }
118 }
119 return;
120 }
121
122 /**
123 * This method will parse the XML concept relationships and tries to map them into cdm relationship types.
124 *
125 * @param bfnNamespace
126 * @param currentElement
127 */
128 private void extractTaxonConceptRelationShips(Namespace bfnNamespace, Element currentElement) {
129 String childName;
130 String bfnElementName = "KONZEPTBEZIEHUNG";
131 ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
132 List<Element> elConceptList = currentElement.getChildren(bfnElementName, bfnNamespace);
133 List<TaxonBase> updatedTaxonList = new ArrayList<TaxonBase>();
134 for(Element element:elConceptList){
135
136 childName = "TAXONYM1";
137 Element elTaxon1 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
138 String taxNr1 = elTaxon1.getAttributeValue("taxNr");
139 int int1 = Integer.parseInt(taxNr1);
140 Taxon taxon1 = firstList.get(int1);
141 TaxonBase<?> taxonBase1 = getTaxonService().load(taxon1.getUuid());
142 taxon1 = (Taxon)taxonBase1;
143
144 childName = "TAXONYM2";
145 Element elTaxon2 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
146 String taxNr2 = elTaxon2.getAttributeValue("taxNr");
147 int int2 = Integer.parseInt(taxNr2);
148 Taxon taxon2 = secondList.get(int2);
149 TaxonBase<?> taxonBase2 = getTaxonService().load(taxon2.getUuid());
150 taxon2 = (Taxon) taxonBase2;
151
152 childName = "STATUS";
153 Element elConceptStatus = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
154 String conceptStatusValue = elConceptStatus.getValue();
155 conceptStatusValue = conceptStatusValue.replaceAll("\u00A0", "").trim();
156 TaxonRelationshipType taxonRelationType = null;
157 /**
158 * This if case only exists because it was decided not to have a included_in relationship type.
159 */
160 if(conceptStatusValue.equalsIgnoreCase("<")){
161 taxon2.addTaxonRelation(taxon1, TaxonRelationshipType.INCLUDES(), null, null);
162 }else{
163 try {
164 taxonRelationType = BfnXmlTransformer.concept2TaxonRelation(conceptStatusValue);
165 } catch (UnknownCdmTypeException e) {
166 e.printStackTrace();
167 }
168 taxon1.addTaxonRelation(taxon2, taxonRelationType , null, null);
169 }
170 if(taxonRelationType != null && taxonRelationType.equals(TaxonRelationshipType.ALL_RELATIONSHIPS())){
171 List<TaxonRelationship> relationsFromThisTaxon = (List<TaxonRelationship>) taxon1.getRelationsFromThisTaxon();
172 TaxonRelationship taxonRelationship = relationsFromThisTaxon.get(0);
173 taxonRelationship.setDoubtful(true);
174 }
175 updatedTaxonList.add(taxon2);
176 updatedTaxonList.add(taxon1);
177 }
178 getTaxonService().saveOrUpdate(updatedTaxonList);
179 logger.info("taxon relationships imported...");
180 }
181
182 /**
183 * This method stores the current imported maps in global variables to make
184 * them later available for matching the taxon relationships between these
185 * imported lists.
186 *
187 * @param config
188 * @param taxonMap
189 */
190 private void prepareListforConceptImport(BfnXmlImportConfigurator config,Map<Integer, Taxon> taxonMap) {
191 if(config.isFillSecondList()){
192 secondList = taxonMap;
193 }else{
194 firstList = taxonMap;
195 }
196 }
197
198 /**
199 *
200 * @param state
201 * @param taxonService
202 * @param config
203 * @param elDataSet
204 * @param bfnNamespace
205 * @return
206 */
207 private Map<UUID, TaxonBase> extractTaxonNames(BfnXmlImportState state,
208 ITaxonService taxonService, BfnXmlImportConfigurator config,
209 Element elDataSet, Namespace bfnNamespace) {
210 logger.info("start make TaxonNames...");
211 Map<Integer, Taxon> taxonMap = new LinkedHashMap<Integer, Taxon>();
212 ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
213 String childName;
214 boolean obligatory;
215 String idNamespace = "TaxonName";
216
217 childName = "TAXONYME";
218 obligatory = false;
219 Element elTaxonNames = XmlHelp.getSingleChildElement(success, elDataSet, childName, bfnNamespace, obligatory);
220
221 String bfnElementName = "TAXONYM";
222 List<Element> elTaxonList = elTaxonNames.getChildren(bfnElementName, bfnNamespace);
223
224 //for each taxonName
225 for (Element elTaxon : elTaxonList){
226 //create Taxon
227 String taxonId = elTaxon.getAttributeValue("taxNr");
228 childName = "WISSNAME";
229 Element elWissName = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
230 String childElementName = "NANTEIL";
231 Taxon taxon = createOrUpdateTaxon(success, idNamespace, config, bfnNamespace, elWissName, childElementName, state);
232
233 //for each synonym
234 childName = "SYNONYME";
235 Element elSynonyms = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
236 if(elSynonyms != null){
237 childElementName = "SYNONYM";
238 createOrUpdateSynonym(taxon, success, obligatory, bfnNamespace, childElementName,elSynonyms, taxonId, state);
239 }
240 //for vernacular name
241 childName = "DEUTSCHENAMEN";
242 Element elVernacularName = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
243 if(elVernacularName != null){
244 childElementName = "DNAME";
245 createOrUpdateVernacularName(taxon, bfnNamespace, childElementName, elVernacularName, state);
246 }
247 //for each information concerning the taxon element
248 //TODO Information block
249 if(config.isDoInformationImport()){
250 childName = "INFORMATIONEN";
251 Element elInformations = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
252 if(elInformations != null){
253 childElementName = "BEZUGSRAUM";
254 createOrUpdateInformation(taxon, bfnNamespace, childElementName,elInformations, state);
255 }
256 }
257 taxonMap.put(Integer.parseInt(taxonId), taxon);
258 }
259
260 //Quick'n'dirty to set concept relationships between two imported list
261 prepareListforConceptImport(config, taxonMap);
262
263 Map<UUID, TaxonBase> savedTaxonMap = taxonService.saveOrUpdate((Collection)taxonMap.values());
264 //FIXME: after first list don't import metadata yet
265 //TODO: import information for second taxon list.
266 config.setDoInformationImport(false);
267 logger.info("end makeTaxonNames ...");
268 if (!success.getValue()){
269 state.setUnsuccessfull();
270 }
271 return savedTaxonMap;
272 }
273
274
275
276
277 /**
278 * This will put the prior imported list into a classification
279 *
280 * @param config
281 * @param taxonService
282 * @param config
283 * @param savedTaxonMap
284 * @param currentElement
285 * @param state
286 * @return
287 */
288 @SuppressWarnings("rawtypes")
289 private boolean createOrUdateClassification(BfnXmlImportConfigurator config, ITaxonService taxonService, Map<UUID, TaxonBase> savedTaxonMap, Element currentElement, BfnXmlImportState state) {
290 boolean isNewClassification = true;
291 String classificationName = state.getFirstClassificationName();
292 if(config.isFillSecondList()){
293 classificationName = state.getSecondClassificationName();
294 }
295 // if(classificationName == null){
296 // classificationName = config.getClassificationName();
297 // }
298 //TODO make classification name dynamically depending on its value in the XML.
299 Classification classification = Classification.NewInstance(classificationName+" "+currentElement.getAttributeValue("inhalt"), state.getCompleteSourceRef());
300 classification.addImportSource(Integer.toString(classification.getId()), classification.getTitleCache(), state.getCompleteSourceRef(), state.getCurrentMicroRef().toString());
301 // List<Classification> classificationList = getClassificationService().list(Classification.class, null, null, null, VOC_CLASSIFICATION_INIT_STRATEGY);
302 // for(Classification c : classificationList){
303 // if(c.getTitleCache().equalsIgnoreCase(classification.getTitleCache())){
304 // classification = c;
305 // isNewClassification = false;
306 // }
307 // }
308
309 // ArrayList<TaxonBase> taxonBaseList = (ArrayList<TaxonBase>) taxonService.list(TaxonBase.class, null, null, null, VOC_CLASSIFICATION_INIT_STRATEGY);
310 for(TaxonBase tb:savedTaxonMap.values()){
311 if(tb instanceof Taxon){
312 TaxonBase tbase = CdmBase.deproxy(tb, TaxonBase.class);
313 Taxon taxon = (Taxon)tbase;
314 taxon = CdmBase.deproxy(taxon, Taxon.class);
315 classification.addChildTaxon(taxon, null, null);
316 }
317 }
318 IClassificationService classificationService = getClassificationService();
319 classificationService.saveOrUpdate(classification);
320 //set boolean for reference and internal mapping of concept relations
321 if(config.isHasSecondList()){
322 config.setFillSecondList(true);
323 }
324 return isNewClassification;
325 }
326
327
328
329 /**
330 * Matches the XML attributes against CDM entities.<BR>
331 * Imports Scientific Name, Rank, etc. and creates a taxon.<br>
332 * <b>Existing taxon names won't be matched yet</b>
333 *
334 * @param success
335 * @param idNamespace
336 * @param config
337 * @param bfnNamespace
338 * @param elTaxonName
339 * @param childElementName
340 * @param state
341 * @return
342 */
343
344 @SuppressWarnings({ "unchecked", "rawtypes" })
345 private Taxon createOrUpdateTaxon(
346 ResultWrapper<Boolean> success, String idNamespace,
347 BfnXmlImportConfigurator config, Namespace bfnNamespace,
348 Element elTaxonName, String childElementName, BfnXmlImportState state) {
349
350 List<Element> elWissNameList = elTaxonName.getChildren(childElementName, bfnNamespace);
351 Rank rank = null;
352 String strAuthor = null;
353 String strSupplement = null;
354 Taxon taxon = null;
355 String uniqueID = null;
356 String uriNameSpace = null;
357 // Long uniqueID = null;
358 for(Element elWissName:elWissNameList){
359
360 if(elWissName.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("Eindeutiger Code")){
361 uriNameSpace = elWissName.getAttributeValue("bereich");
362 String textNormalize = elWissName.getTextNormalize();
363 if(StringUtils.isBlank(textNormalize)){
364 uniqueID = "";
365 }else{
366 uniqueID = textNormalize;
367 }
368 }
369 if(elWissName.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("Autoren")){
370 strAuthor = elWissName.getTextNormalize();
371 }
372 if(elWissName.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("Rang")){
373 String strRank = elWissName.getTextNormalize();
374 rank = makeRank(strRank);
375 }
376 if(elWissName.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("Zusätze")){
377 strSupplement = elWissName.getTextNormalize();
378 }
379 if(elWissName.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("wissName")){
380 try{
381 TaxonNameBase<?, ?> nameBase = parseNonviralNames(rank,strAuthor,strSupplement,elWissName);
382 if(nameBase.isProtectedTitleCache() == true){
383 logger.warn("Taxon " + nameBase.getTitleCache());
384 }
385
386 //TODO extract to method?
387 if(strSupplement != null){
388 nameBase.setAppendedPhrase(strSupplement);
389 }
390 if(strSupplement != null && strSupplement.equalsIgnoreCase("nom. illeg.")){
391 nameBase.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ILLEGITIMATE()));
392 }
393 /**
394 * BFN does not want any name matching yet
395 */
396 // TaxonBase<?> taxonBase = null;
397 // //TODO find best matching Taxa
398 // Pager<TaxonNameBase> names = getNameService().findByTitle(null, nameBase.getTitleCache(), null, null, null, null, null, null);
399 // //TODO correct handling for pager
400 // List<TaxonNameBase> nameList = names.getRecords();
401 // if (nameList.isEmpty()){
402 // taxonBase = Taxon.NewInstance(nameBase, config.getSourceReference());
403 // }else{
404 // taxonBase = Taxon.NewInstance(nameList.get(0), config.getSourceReference());
405 // if (nameList.size()>1){
406 // logger.warn("More than 1 matching taxon name found for " + nameBase.getTitleCache());
407 // }
408 // }
409 state.setCurrentMicroRef(state.getFirstListSecRef());
410 if(config.isFillSecondList()){
411 state.setCurrentMicroRef(state.getSecondListSecRef());
412 }
413 taxon = Taxon.NewInstance(nameBase, state.getCurrentMicroRef());
414 //set create and set path of nameSpace
415 Element parentElement = elWissName.getParentElement();
416 Element grandParentElement = parentElement.getParentElement();
417 taxon.addImportSource(uniqueID, grandParentElement.getName()+":"+parentElement.getName()+":"+elWissName.getName()+":"+uriNameSpace, state.getCompleteSourceRef(), state.getCurrentMicroRef().getTitle());
418 } catch (UnknownCdmTypeException e) {
419 success.setValue(false);
420 }
421 }
422 }
423 return taxon;
424 }
425
426 /**
427 * Matches the XML attributes against CDM entities.<BR>
428 * Imports Scientific Name, Rank etc. and create a synonym.<br>
429 * <b>Existing synonym names won't be matched yet</b>
430 *
431 * @param taxon
432 * @param success
433 * @param obligatory
434 * @param bfnNamespace
435 * @param childElementName
436 * @param elSynonyms
437 * @param taxonId
438 * @param config
439 * @param state
440 */
441
442 @SuppressWarnings({ "unchecked" })
443 private void createOrUpdateSynonym(Taxon taxon, ResultWrapper<Boolean> success, boolean obligatory, Namespace bfnNamespace,
444 String childElementName, Element elSynonyms, String taxonId, BfnXmlImportState state) {
445
446 String childName;
447 List<Element> elSynonymList = elSynonyms.getChildren(childElementName, bfnNamespace);
448
449 for(Element elSyn:elSynonymList){
450 Rank rank = null;
451 String strAuthor = null;
452 String strSupplement = null;
453 childName = "WISSNAME";
454 Element elSynScientificName = XmlHelp.getSingleChildElement(success, elSyn, childName, bfnNamespace, obligatory);
455
456 childElementName = "NANTEIL";
457 List<Element> elSynDetails = elSynScientificName.getChildren(childElementName, bfnNamespace);
458
459 for(Element elSynDetail:elSynDetails){
460 if(elSynDetail.getAttributeValue("bereich").equalsIgnoreCase("Rang")){
461 String strRank = elSynDetail.getTextNormalize();
462 rank = makeRank(strRank);
463 }
464 if(elSynDetail.getAttributeValue("bereich").equalsIgnoreCase("Autoren")){
465 strAuthor = elSynDetail.getTextNormalize();
466 }
467 if(elSynDetail.getAttributeValue("bereich", bfnNamespace).equalsIgnoreCase("Zusätze")){
468 strSupplement = elSynDetail.getTextNormalize();
469 }
470 if(elSynDetail.getAttributeValue("bereich").equalsIgnoreCase("wissName")){
471 try{
472 TaxonNameBase<?, ?> nameBase = parseNonviralNames(rank,strAuthor,strSupplement,elSynDetail);
473
474 //TODO find best matching Taxa
475 Synonym synonym = Synonym.NewInstance(nameBase, state.getCurrentMicroRef());
476 taxon.addSynonym(synonym, SynonymRelationshipType.SYNONYM_OF());
477
478 } catch (UnknownCdmTypeException e) {
479 logger.warn("Name with id " + taxonId + " has unknown nomenclatural code.");
480 success.setValue(false);
481 }
482
483 }
484
485 }
486 }
487 }
488
489
490 /**
491 *
492 * @param taxon
493 * @param bfnNamespace
494 * @param childElementName
495 * @param elVernacularName
496 * @param state
497 */
498 private void createOrUpdateVernacularName(Taxon taxon,
499 Namespace bfnNamespace, String childElementName,
500 Element elVernacularName, BfnXmlImportState state) {
501
502 List<Element> elVernacularNameList = elVernacularName.getChildren(childElementName, bfnNamespace);
503
504 TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
505
506 for(Element elVernacular : elVernacularNameList){
507 Element child = elVernacular.getChild("TRIVIALNAME");
508 if(child != null){
509 makeCommonName(taxonDescription, child, state);
510 }
511 }
512
513 }
514
515 /**
516 *
517 * @param taxon
518 * @param bfnNamespace
519 * @param childElementName
520 * @param elInformations
521 * @param state
522 * @throws UnknownCdmTypeException
523 */
524
525 @SuppressWarnings("unchecked")
526 private void createOrUpdateInformation(Taxon taxon,
527 Namespace bfnNamespace, String childElementName,
528 Element elInformations,
529 BfnXmlImportState state){
530
531 List<Element> elInformationList = elInformations.getChildren(childElementName, bfnNamespace);
532
533 for(Element elInfo:elInformationList){
534 //check if geographical scope is Bund and import only these information for now
535 //TODO create several taxon descriptions for different geographical scope
536 if(elInfo.getName().equalsIgnoreCase("BEZUGSRAUM") && elInfo.getAttributeValue("name").equalsIgnoreCase("Bund")){
537 childElementName = "IWERT";
538 TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
539 UUID germanStateUUID;
540 try {
541 germanStateUUID = BfnXmlTransformer.getGermanStateUUID("Deutschland");
542 NamedArea area = (NamedArea)getTermService().load(germanStateUUID);
543 //FIXME GEOSCOPE_ID CANNOT BE NULL Exception
544 // taxonDescription.addGeoScope(area);
545 } catch (UnknownCdmTypeException e) {
546 // TODO Auto-generated catch block
547 e.printStackTrace();
548 }
549 List<Element> elInfoDetailList = elInfo.getChildren(childElementName, bfnNamespace);
550
551 for(Element elInfoDetail : elInfoDetailList){
552 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("RL Kat.")){
553 makeFeatures(taxonDescription, elInfoDetail, state, false);
554 }
555 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Kat. +/-")){
556 makeFeatures(taxonDescription, elInfoDetail, state, false);
557 }
558 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("aktuelle Bestandsstituation")){
559 makeFeatures(taxonDescription, elInfoDetail, state, false);
560 }
561 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("langfristiger Bestandstrend")){
562 makeFeatures(taxonDescription, elInfoDetail, state, false);
563 }
564 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("kurzfristiger Bestandstrend")){
565 makeFeatures(taxonDescription, elInfoDetail, state, false);
566 }
567 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Risikofaktoren")){
568 makeFeatures(taxonDescription, elInfoDetail, state, false);
569 }
570 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Verantwortlichkeit")){
571 makeFeatures(taxonDescription, elInfoDetail, state, false);
572 }
573 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("alte RL- Kat.")){
574 makeFeatures(taxonDescription, elInfoDetail, state, false);
575 }
576 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Neobiota")){
577 makeFeatures(taxonDescription, elInfoDetail, state, false);
578 }
579 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Eindeutiger Code")){
580 makeFeatures(taxonDescription, elInfoDetail, state, false);
581 }
582 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Kommentar zur Taxonomie")){
583 makeFeatures(taxonDescription, elInfoDetail, state, true);
584 }
585 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Kommentar zur Gefährdung")){
586 makeFeatures(taxonDescription, elInfoDetail, state, true);
587 }
588 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Sonderfälle")){
589 makeFeatures(taxonDescription, elInfoDetail, state, false);
590 }
591 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Letzter Nachweis")){
592 makeFeatures(taxonDescription, elInfoDetail, state, true);
593 }
594 if(elInfoDetail.getAttributeValue("standardname").equalsIgnoreCase("Weitere Kommentare")){
595 makeFeatures(taxonDescription, elInfoDetail, state, true);
596 }
597 }
598 }
599 }
600 }
601
602
603
604 private void makeCommonName(TaxonDescription taxonDescription,
605 Element child, BfnXmlImportState state) {
606 String commonNameValue = child.getValue();
607 NamedArea area = getTermService().getAreaByTdwgAbbreviation("GER");
608 CommonTaxonName commonName = CommonTaxonName.NewInstance(commonNameValue, Language.GERMAN(), area);
609 taxonDescription.addElement(commonName);
610 }
611
612
613 /**
614 *
615 * @param taxonDescription
616 * @param elInfoDetail
617 * @param state
618 * @param isTextData
619 */
620 private void makeFeatures(
621 TaxonDescription taxonDescription,
622 Element elInfoDetail,
623 BfnXmlImportState state,
624 boolean isTextData) {
625
626 String transformedRlKatValue = null;
627 UUID featureUUID = null;
628 UUID stateTermUUID = null;
629 String strRlKatValue = elInfoDetail.getChild("WERT").getValue();
630 String strRlKat = elInfoDetail.getAttributeValue("standardname");
631 boolean randomStateUUID = false;
632 try {
633 featureUUID = BfnXmlTransformer.getRedlistFeatureUUID(strRlKat);
634 transformedRlKatValue = BfnXmlTransformer.redListString2RedListCode(strRlKatValue);
635 } catch (UnknownCdmTypeException e) {
636 transformedRlKatValue = strRlKatValue;
637 }
638 Feature redListFeature = getFeature(state, featureUUID);
639 State rlState = null;
640 //if is text data a state is not needed
641 if(!isTextData){
642 try {
643 stateTermUUID = BfnXmlTransformer.getRedlistStateTermUUID(transformedRlKatValue, strRlKat);
644 } catch (UnknownCdmTypeException e) {
645 stateTermUUID = UUID.randomUUID();
646 randomStateUUID = true;
647 }
648 if(randomStateUUID || stateTermUUID == BfnXmlTransformer.stateTermEmpty){
649 if(stateTermUUID == BfnXmlTransformer.stateTermEmpty) {
650 transformedRlKatValue = "keine Angabe";
651 }
652 rlState = getStateTerm(state, stateTermUUID, transformedRlKatValue, transformedRlKatValue, transformedRlKatValue, null);
653 }else{
654 rlState = getStateTerm(state, stateTermUUID);
655 }
656 }
657 if(isTextData){
658 TextData textData = TextData.NewInstance(redListFeature);
659 textData.putText(Language.GERMAN(), strRlKatValue);
660 DescriptionElementBase descriptionElement = textData;
661 taxonDescription.addElement(descriptionElement);
662 }else{
663 CategoricalData catData = CategoricalData.NewInstance(rlState, redListFeature);
664 DescriptionElementBase descriptionElement = catData;
665 taxonDescription.addElement(descriptionElement);
666 }
667 }
668
669 /**
670 * Returns the rank represented by the rank element.<br>
671 * Returns <code>null</code> if the element is null.<br>
672 * Returns <code>null</code> if the code and the text are both either empty or do not exists.<br>
673 * Returns the rank represented by the code attribute, if the code attribute is not empty and could be resolved.<br>
674 * If the code could not be resolved it returns the rank represented most likely by the elements text.<br>
675 * Returns UNKNOWN_RANK if code attribute and element text could not be resolved.
676 * @param strRank bfn rank element
677 * @return
678 */
679 protected static Rank makeRank(String strRank){
680 Rank result;
681 if (strRank == null){
682 return null;
683 }
684 Rank codeRank = null;
685 try {
686 codeRank = BfnXmlTransformer.rankCode2Rank(strRank);
687 } catch (UnknownCdmTypeException e1) {
688 codeRank = Rank.UNKNOWN_RANK();
689 }
690 //codeRank exists
691 if ( (codeRank != null) && !codeRank.equals(Rank.UNKNOWN_RANK())){
692 result = codeRank;
693 }
694 //codeRank does not exist
695 else{
696 result = codeRank;
697 logger.warn("string rank used, because code rank does not exist or was not recognized: " + codeRank.getTitleCache()+" "+strRank);
698 }
699 return result;
700 }
701
702 /**
703 * @param rank
704 * @param strAuthor
705 * @param strSupplement
706 * @param elWissName
707 * @return
708 * @throws UnknownCdmTypeException
709 */
710 private TaxonNameBase<?, ?> parseNonviralNames(Rank rank, String strAuthor, String strSupplement, Element elWissName)
711 throws UnknownCdmTypeException {
712 TaxonNameBase<?,?> taxonNameBase = null;
713
714 NomenclaturalCode nomCode = BfnXmlTransformer.nomCodeString2NomCode(strNomenclaturalCode);
715 String strScientificName = elWissName.getTextNormalize();
716 /**
717 *
718 * trim strScienctificName because sometimes
719 * getTextNormalize() does not removes all the
720 * whitespaces
721 *
722 **/
723 strScientificName = StringUtils.trim(strScientificName);
724 strScientificName = StringUtils.remove(strScientificName, "\u00a0");
725 strScientificName = StringUtils.remove(strScientificName, "\uc281");
726
727 if(strSupplement != null && !strSupplement.isEmpty()){
728 strScientificName = StringUtils.remove(strScientificName, strSupplement);
729 }
730 NonViralName<?> nonViralName = null;
731 NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
732 nonViralName = parser.parseFullName(strScientificName, nomCode, rank);
733 if(nonViralName.hasProblem()){
734 for(ParserProblem p:nonViralName.getParsingProblems()){
735 logger.warn(++parsingProblemCounter + " " +nonViralName.getTitleCache() +" "+p.toString());
736 }
737 }
738 //check for parsed rank
739 Rank parsedRank = nonViralName.getRank();
740 if(parsedRank != rank){
741 nonViralName.setRank(rank);
742 }
743 //check for parsed author
744 String parsedAuthor = nonViralName.getAuthorshipCache();
745 strAuthor = StringUtils.trim(strAuthor);
746 parsedAuthor = StringUtils.trim(parsedAuthor);
747 if(parsedAuthor.equalsIgnoreCase(strAuthor)){
748 logger.info("Taxon " + nonViralName.getTitleCache() +":"
749 +"\t Author field: " + strAuthor +" and parsed AuthorshipCache: "+nonViralName.getAuthorshipCache());
750 }
751 taxonNameBase = nonViralName;
752 return taxonNameBase;
753 }
754
755 @Override
756 protected boolean isIgnore(BfnXmlImportState state){
757 return ! state.getConfig().isDoTaxonNames();
758 }
759 }