1
|
// $Id$
|
2
|
/**
|
3
|
* Copyright (C) 2007 EDIT
|
4
|
* European Distributed Institute of Taxonomy
|
5
|
* http://www.e-taxonomy.eu
|
6
|
*
|
7
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
8
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
9
|
*/
|
10
|
|
11
|
package eu.etaxonomy.cdm.print;
|
12
|
|
13
|
import java.util.ArrayList;
|
14
|
import java.util.List;
|
15
|
import java.util.Locale;
|
16
|
import java.util.UUID;
|
17
|
|
18
|
import org.apache.log4j.Logger;
|
19
|
import org.jdom.Document;
|
20
|
import org.jdom.Element;
|
21
|
import org.jdom.JDOMException;
|
22
|
import org.jdom.xpath.XPath;
|
23
|
|
24
|
import eu.etaxonomy.cdm.common.IProgressMonitor;
|
25
|
import eu.etaxonomy.cdm.print.out.IPublishOutputModule;
|
26
|
|
27
|
/**
|
28
|
* Retrieves all necessary data from an {@link IXMLEntityFactory}.
|
29
|
*
|
30
|
* @author n.hoffmann
|
31
|
* @created Apr 8, 2010
|
32
|
* @version 1.0
|
33
|
*/
|
34
|
public class XMLHarvester {
|
35
|
private static final Logger logger = Logger.getLogger(XMLHarvester.class);
|
36
|
|
37
|
private IXMLEntityFactory factory;
|
38
|
|
39
|
private PublishConfigurator configurator;
|
40
|
|
41
|
private List<SimplifiedFeatureNode> simplifiedFeatureTree;
|
42
|
|
43
|
private IProgressMonitor progressMonitor;
|
44
|
|
45
|
/**
|
46
|
*
|
47
|
* @param configurator
|
48
|
*/
|
49
|
public XMLHarvester(PublishConfigurator configurator){
|
50
|
this.configurator = configurator;
|
51
|
this.factory = configurator.getFactory();
|
52
|
this.progressMonitor = configurator.getProgressMonitor();
|
53
|
|
54
|
Element featureTreeElement = factory.getFeatureTree(configurator.getFeatureTreeUuid());
|
55
|
createSimplifiedFeatureTree(featureTreeElement);
|
56
|
}
|
57
|
|
58
|
private void createSimplifiedFeatureTree(Element featureTreeElement) {
|
59
|
Element root = featureTreeElement.getChild("root");
|
60
|
|
61
|
Element realRoot = factory.getFeatureNode(XMLHelper.getUuid(root));
|
62
|
|
63
|
progressMonitor.subTask("Generating simplified Feature Tree.");
|
64
|
simplifiedFeatureTree = featureTreeRecursive(realRoot);
|
65
|
|
66
|
logger.info("Simplified FeeatureTree created");
|
67
|
}
|
68
|
|
69
|
private List<SimplifiedFeatureNode> featureTreeRecursive(Element featureNode){
|
70
|
List<SimplifiedFeatureNode> result = new ArrayList<SimplifiedFeatureNode>();
|
71
|
|
72
|
if(featureNode != null){
|
73
|
Element children = featureNode.getChild("children");
|
74
|
|
75
|
List<Element> childFeatureNodes = children.getChildren();
|
76
|
|
77
|
for(Element childNode : childFeatureNodes){
|
78
|
UUID uuid = XMLHelper.getUuid(childNode);
|
79
|
Element featureNodeElement = factory.getFeatureNode(uuid);
|
80
|
Element featureElement = factory.getFeatureForFeatureNode(uuid);
|
81
|
featureElement.setName(featureElement.getName().toLowerCase(Locale.ENGLISH));
|
82
|
SimplifiedFeatureNode simplifiedFeatureNode = new SimplifiedFeatureNode(featureElement, featureTreeRecursive(featureNodeElement));
|
83
|
|
84
|
result.add(simplifiedFeatureNode);
|
85
|
}
|
86
|
}
|
87
|
return result;
|
88
|
}
|
89
|
|
90
|
private class SimplifiedFeatureNode{
|
91
|
private Element featureElement;
|
92
|
private List<SimplifiedFeatureNode> children;
|
93
|
|
94
|
public SimplifiedFeatureNode(Element featureElement, List<SimplifiedFeatureNode> children){
|
95
|
this.featureElement = featureElement;
|
96
|
this.children = children;
|
97
|
}
|
98
|
|
99
|
/**
|
100
|
* @return the uuid
|
101
|
*/
|
102
|
public Element getFeatureElement() {
|
103
|
return featureElement;
|
104
|
}
|
105
|
|
106
|
/**
|
107
|
* @return the children
|
108
|
*/
|
109
|
public List<SimplifiedFeatureNode> getChildren() {
|
110
|
return children;
|
111
|
}
|
112
|
}
|
113
|
|
114
|
/**
|
115
|
* Commences harvesting the given {@link List} of taxonNodeElements
|
116
|
*
|
117
|
* @param taxonNodeElements
|
118
|
* @return a {@link Document} containing the necessary XML needed by the {@link IPublishOutputModule IPublishOutputModules}
|
119
|
*/
|
120
|
public Document harvest(List<Element> taxonNodeElements){
|
121
|
|
122
|
Element root = new Element(IXMLElements.ROOT);
|
123
|
|
124
|
for(Element taxonNodeElement : taxonNodeElements){
|
125
|
|
126
|
taxonNodeElement.detach();
|
127
|
|
128
|
populateTreeNodeContainer(taxonNodeElement);
|
129
|
|
130
|
root.addContent(taxonNodeElement);
|
131
|
}
|
132
|
|
133
|
|
134
|
Document result = new Document();
|
135
|
|
136
|
result.addContent(root);
|
137
|
|
138
|
cleanDateFields(result);
|
139
|
|
140
|
return result;
|
141
|
}
|
142
|
|
143
|
/**
|
144
|
* FIXME
|
145
|
* This is a hack to circumvent problems with the serialized version of
|
146
|
* datePublished objects. Remove this once this was fixed in the library
|
147
|
* @param element the context
|
148
|
*/
|
149
|
@Deprecated
|
150
|
private void cleanDateFields(Object context) {
|
151
|
String path = "//datePublished/start";
|
152
|
|
153
|
try {
|
154
|
List<Element> nodes = XPath.selectNodes(context, path);
|
155
|
|
156
|
for(Element node : nodes){
|
157
|
String textWithRubbish = node.getText() ;
|
158
|
String cleanedText = textWithRubbish.substring(0, 4);
|
159
|
node.setText(cleanedText);
|
160
|
|
161
|
Element parent = (Element) node.getParent().getParent();
|
162
|
if(parent.getName().equals("citation")){
|
163
|
Element parent2 = (Element) parent.getParent();
|
164
|
parent2.setAttribute("sort", cleanedText);
|
165
|
}
|
166
|
}
|
167
|
} catch (JDOMException e) {
|
168
|
logger.error("Error tryong to clean dat published field");
|
169
|
}
|
170
|
}
|
171
|
|
172
|
/**
|
173
|
* Get all additional content that is not included in taxon node initialization
|
174
|
*
|
175
|
* @param container
|
176
|
*/
|
177
|
private void populateTreeNodeContainer(Element taxonNodeElement){
|
178
|
|
179
|
// get the taxon from the generic service to have the uuid for further processing
|
180
|
Element taxonElement = factory.getTaxonForTaxonNode(taxonNodeElement);
|
181
|
|
182
|
progressMonitor.subTask("Gathering data for taxon: " + XMLHelper.getTitleCache(taxonElement));
|
183
|
|
184
|
// get initialized accepted taxon
|
185
|
// TODO right now we are getting that from the portal service but should consider to use the generic service
|
186
|
// as the portal service is more likely to change
|
187
|
Element fullTaxonElement = factory.getAcceptedTaxonElement(taxonElement);
|
188
|
|
189
|
populateTypeDesignations(fullTaxonElement);
|
190
|
|
191
|
// get descriptions
|
192
|
if(configurator.isDoDescriptions()){
|
193
|
populateDescriptions(fullTaxonElement);
|
194
|
}
|
195
|
|
196
|
// get synonym
|
197
|
if(configurator.isDoSynonymy()){
|
198
|
populateSynonyms(fullTaxonElement);
|
199
|
}
|
200
|
|
201
|
// get media
|
202
|
if(configurator.isDoImages()){
|
203
|
populateImages(fullTaxonElement);
|
204
|
}
|
205
|
|
206
|
// add taxon element to the node element
|
207
|
XMLHelper.addContent(fullTaxonElement, taxonNodeElement);
|
208
|
|
209
|
// get taxonomically included taxa
|
210
|
if(configurator.isDoPublishEntireBranches()){
|
211
|
populateChildren(taxonNodeElement);
|
212
|
}
|
213
|
|
214
|
}
|
215
|
|
216
|
private void populateTypeDesignations(Element fullTaxonElement) {
|
217
|
|
218
|
Element nameElement = fullTaxonElement.getChild("name");
|
219
|
|
220
|
List<Element> typeDesignations = factory.getTypeDesignations(nameElement);
|
221
|
|
222
|
nameElement.removeChild("typeDesignations");
|
223
|
|
224
|
for(Element typeDesignation: typeDesignations){
|
225
|
XMLHelper.addContent(typeDesignation, "typeDesignations", nameElement);
|
226
|
}
|
227
|
}
|
228
|
|
229
|
/**
|
230
|
* Populates all child nodes of the given taxonNodeElement
|
231
|
*
|
232
|
* @param container
|
233
|
*/
|
234
|
private void populateChildren(Element taxonNodeElement){
|
235
|
|
236
|
logger.info("populating branch");
|
237
|
|
238
|
List<Element> childNodeElements = factory.getChildNodes(taxonNodeElement);
|
239
|
|
240
|
for(Element childNodeElement : childNodeElements){
|
241
|
logger.info("Creating content for child node");
|
242
|
|
243
|
populateTreeNodeContainer(childNodeElement);
|
244
|
XMLHelper.addContent(childNodeElement, "childNodes", taxonNodeElement);
|
245
|
}
|
246
|
}
|
247
|
|
248
|
/**
|
249
|
* Retrieves descriptions for the given taxonElement
|
250
|
*
|
251
|
* @param taxonElement
|
252
|
*/
|
253
|
private void populateDescriptions(Element taxonElement){
|
254
|
taxonElement.removeChild("descriptions");
|
255
|
|
256
|
Element rawDescriptions = factory.getDescriptions(taxonElement);
|
257
|
|
258
|
Element descriptions = new Element("descriptions");
|
259
|
|
260
|
Element features = new Element("features");
|
261
|
|
262
|
for(SimplifiedFeatureNode simplifiedFeatureNode : simplifiedFeatureTree){
|
263
|
|
264
|
try {
|
265
|
processFeatureNode(simplifiedFeatureNode, rawDescriptions, features);
|
266
|
} catch (JDOMException e) {
|
267
|
logger.error(e);
|
268
|
}
|
269
|
}
|
270
|
XMLHelper.addContent(features, descriptions);
|
271
|
XMLHelper.addContent(descriptions, taxonElement);
|
272
|
}
|
273
|
|
274
|
private void processFeatureNode(SimplifiedFeatureNode featureNode, Object context, Element parentElement) throws JDOMException{
|
275
|
// gets the feature elements with the current feature uuid
|
276
|
UUID featureUuid = XMLHelper.getUuid(featureNode.getFeatureElement());
|
277
|
String featurePattern = "//feature[contains(uuid,'" + featureUuid + "')]";
|
278
|
|
279
|
Element feature = (Element) XPath.selectSingleNode(context, featurePattern);
|
280
|
|
281
|
if(feature != null){
|
282
|
// get the parents of all feature elements with the current uuid
|
283
|
List<Element> descriptionElementElements = XPath.selectNodes(context, featurePattern + "/..");
|
284
|
// add matching description elements as children to this feature element
|
285
|
for(Element descriptionElementElement : descriptionElementElements){
|
286
|
descriptionElementElement.removeChild("feature");
|
287
|
descriptionElementElement.setName("descriptionelement");
|
288
|
XMLHelper.addContent(descriptionElementElement, "descriptionelements", feature);
|
289
|
}
|
290
|
XMLHelper.addContent(feature, parentElement);
|
291
|
}else if(featureNode.getChildren().size() > 0){
|
292
|
Element featureElement = featureNode.getFeatureElement();
|
293
|
Element featureElementClone = (Element) featureElement.clone();
|
294
|
feature = (Element) featureElementClone.detach();
|
295
|
XMLHelper.addContent(feature, parentElement);
|
296
|
}
|
297
|
|
298
|
// recurse into children
|
299
|
for(SimplifiedFeatureNode childFeatureNode : featureNode.getChildren()){
|
300
|
processFeatureNode(childFeatureNode, context, feature);
|
301
|
}
|
302
|
}
|
303
|
|
304
|
/**
|
305
|
* Retrieves the synonymy for the given taxonElement
|
306
|
*
|
307
|
* @param taxonElement
|
308
|
*/
|
309
|
private void populateSynonyms(Element taxonElement){
|
310
|
List<Element> synonymy = factory.getSynonymy(taxonElement);
|
311
|
|
312
|
for(Element synonymyNode : synonymy){
|
313
|
XMLHelper.addContent(synonymyNode, "synonymy", taxonElement);
|
314
|
}
|
315
|
}
|
316
|
|
317
|
|
318
|
|
319
|
/**
|
320
|
* TODO not implemented yet
|
321
|
* @param taxonElement
|
322
|
*/
|
323
|
private void populateImages(Element taxonElement){
|
324
|
logger.warn("not implemented yet");
|
325
|
}
|
326
|
}
|