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.progressMonitor = configurator.getProgressMonitor();
|
52
|
this.factory = configurator.getFactory();
|
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
|
progressMonitor.worked(1);
|
66
|
|
67
|
logger.info("Simplified FeeatureTree created");
|
68
|
}
|
69
|
|
70
|
private List<SimplifiedFeatureNode> featureTreeRecursive(Element featureNode){
|
71
|
List<SimplifiedFeatureNode> result = new ArrayList<SimplifiedFeatureNode>();
|
72
|
|
73
|
if(featureNode != null){
|
74
|
Element children = featureNode.getChild("children");
|
75
|
|
76
|
List<Element> childFeatureNodes = children.getChildren();
|
77
|
|
78
|
for(Element childNode : childFeatureNodes){
|
79
|
UUID uuid = XMLHelper.getUuid(childNode);
|
80
|
Element featureNodeElement = factory.getFeatureNode(uuid);
|
81
|
Element featureElement = factory.getFeatureForFeatureNode(uuid);
|
82
|
featureElement.setName(featureElement.getName().toLowerCase(Locale.ENGLISH));
|
83
|
SimplifiedFeatureNode simplifiedFeatureNode = new SimplifiedFeatureNode(featureElement, featureTreeRecursive(featureNodeElement));
|
84
|
|
85
|
result.add(simplifiedFeatureNode);
|
86
|
}
|
87
|
}
|
88
|
return result;
|
89
|
}
|
90
|
|
91
|
private class SimplifiedFeatureNode{
|
92
|
private Element featureElement;
|
93
|
private List<SimplifiedFeatureNode> children;
|
94
|
|
95
|
public SimplifiedFeatureNode(Element featureElement, List<SimplifiedFeatureNode> children){
|
96
|
this.featureElement = featureElement;
|
97
|
this.children = children;
|
98
|
}
|
99
|
|
100
|
/**
|
101
|
* @return the uuid
|
102
|
*/
|
103
|
public Element getFeatureElement() {
|
104
|
return featureElement;
|
105
|
}
|
106
|
|
107
|
/**
|
108
|
* @return the children
|
109
|
*/
|
110
|
public List<SimplifiedFeatureNode> getChildren() {
|
111
|
return children;
|
112
|
}
|
113
|
}
|
114
|
|
115
|
/**
|
116
|
* Commences harvesting the given {@link List} of taxonNodeElements
|
117
|
*
|
118
|
* @param taxonNodeElements
|
119
|
* @return a {@link Document} containing the necessary XML needed by the {@link IPublishOutputModule IPublishOutputModules}
|
120
|
*/
|
121
|
public Document harvest(List<Element> taxonNodeElements){
|
122
|
|
123
|
Element root = new Element(IXMLElements.ROOT);
|
124
|
|
125
|
for(Element taxonNodeElement : taxonNodeElements){
|
126
|
|
127
|
taxonNodeElement.detach();
|
128
|
|
129
|
populateTreeNodeContainer(taxonNodeElement);
|
130
|
|
131
|
root.addContent(taxonNodeElement);
|
132
|
}
|
133
|
|
134
|
|
135
|
Document result = new Document();
|
136
|
|
137
|
result.addContent(root);
|
138
|
|
139
|
// cleanDateFields(result);
|
140
|
|
141
|
return result;
|
142
|
}
|
143
|
|
144
|
/**
|
145
|
* FIXME
|
146
|
* This is a hack to circumvent problems with the serialized version of
|
147
|
* datePublished objects. Remove this once this was fixed in the library
|
148
|
* @param element the context
|
149
|
*/
|
150
|
@Deprecated
|
151
|
private void cleanDateFields(Object context) {
|
152
|
String path = "//datePublished/start";
|
153
|
|
154
|
try {
|
155
|
List<Element> nodes = XPath.selectNodes(context, path);
|
156
|
|
157
|
for(Element node : nodes){
|
158
|
String textWithRubbish = node.getText() ;
|
159
|
String cleanedText = textWithRubbish.substring(0, 4);
|
160
|
node.setText(cleanedText);
|
161
|
|
162
|
Element parent = (Element) node.getParent().getParent();
|
163
|
if(parent.getName().equals("citation")){
|
164
|
Element parent2 = (Element) parent.getParent();
|
165
|
parent2.setAttribute("sort", cleanedText);
|
166
|
}
|
167
|
}
|
168
|
} catch (Exception e) {
|
169
|
logger.error("Error trying to clean dat published field", e);
|
170
|
}
|
171
|
}
|
172
|
|
173
|
/**
|
174
|
* Get all additional content that is not included in taxon node initialization
|
175
|
*
|
176
|
* @param container
|
177
|
*/
|
178
|
private void populateTreeNodeContainer(Element taxonNodeElement){
|
179
|
|
180
|
// get the taxon from the generic service to have the uuid for further processing
|
181
|
Element taxonElement = factory.getTaxonForTaxonNode(taxonNodeElement);
|
182
|
|
183
|
progressMonitor.subTask("Gathering data for taxon: " + XMLHelper.getTitleCache(taxonElement));
|
184
|
|
185
|
// get initialized accepted taxon
|
186
|
// TODO right now we are getting that from the portal service but should consider to use the generic service
|
187
|
// as the portal service is more likely to change
|
188
|
Element fullTaxonElement = factory.getAcceptedTaxonElement(taxonElement);
|
189
|
|
190
|
populateTypeDesignations(fullTaxonElement);
|
191
|
|
192
|
// get descriptions
|
193
|
if(configurator.isDoDescriptions()){
|
194
|
populateDescriptions(fullTaxonElement);
|
195
|
}
|
196
|
|
197
|
// get synonym
|
198
|
if(configurator.isDoSynonymy()){
|
199
|
populateSynonyms(fullTaxonElement);
|
200
|
}
|
201
|
|
202
|
// get media
|
203
|
if(configurator.isDoImages()){
|
204
|
populateImages(fullTaxonElement);
|
205
|
}
|
206
|
|
207
|
// add taxon element to the node element
|
208
|
XMLHelper.addContent(fullTaxonElement, taxonNodeElement);
|
209
|
|
210
|
// get taxonomically included taxa
|
211
|
if(configurator.isDoPublishEntireBranches()){
|
212
|
populateChildren(taxonNodeElement);
|
213
|
}
|
214
|
|
215
|
progressMonitor.worked(1);
|
216
|
|
217
|
}
|
218
|
|
219
|
private void populateTypeDesignations(Element fullTaxonElement) {
|
220
|
|
221
|
Element nameElement = fullTaxonElement.getChild("name");
|
222
|
|
223
|
List<Element> typeDesignations = factory.getTypeDesignations(nameElement);
|
224
|
|
225
|
nameElement.removeChild("typeDesignations");
|
226
|
|
227
|
for(Element typeDesignation: typeDesignations){
|
228
|
XMLHelper.addContent(typeDesignation, "typeDesignations", nameElement);
|
229
|
}
|
230
|
}
|
231
|
|
232
|
/**
|
233
|
* Populates all child nodes of the given taxonNodeElement
|
234
|
*
|
235
|
* @param container
|
236
|
*/
|
237
|
private void populateChildren(Element taxonNodeElement){
|
238
|
|
239
|
logger.info("populating branch");
|
240
|
|
241
|
List<Element> childNodeElements = factory.getChildNodes(taxonNodeElement);
|
242
|
|
243
|
for(Element childNodeElement : childNodeElements){
|
244
|
logger.info("Creating content for child node");
|
245
|
|
246
|
populateTreeNodeContainer(childNodeElement);
|
247
|
XMLHelper.addContent(childNodeElement, "childNodes", taxonNodeElement);
|
248
|
}
|
249
|
}
|
250
|
|
251
|
/**
|
252
|
* Retrieves descriptions for the given taxonElement
|
253
|
*
|
254
|
* @param taxonElement
|
255
|
*/
|
256
|
private void populateDescriptions(Element taxonElement){
|
257
|
taxonElement.removeChild("descriptions");
|
258
|
|
259
|
Element rawDescriptions = factory.getDescriptions(taxonElement);
|
260
|
|
261
|
Element descriptions = new Element("descriptions");
|
262
|
|
263
|
Element features = new Element("features");
|
264
|
|
265
|
for(SimplifiedFeatureNode simplifiedFeatureNode : simplifiedFeatureTree){
|
266
|
|
267
|
try {
|
268
|
processFeatureNode(simplifiedFeatureNode, rawDescriptions, features);
|
269
|
} catch (JDOMException e) {
|
270
|
logger.error(e);
|
271
|
}
|
272
|
}
|
273
|
XMLHelper.addContent(features, descriptions);
|
274
|
XMLHelper.addContent(descriptions, taxonElement);
|
275
|
}
|
276
|
|
277
|
private void processFeatureNode(SimplifiedFeatureNode featureNode, Object context, Element parentElement) throws JDOMException{
|
278
|
// gets the feature elements with the current feature uuid
|
279
|
UUID featureUuid = XMLHelper.getUuid(featureNode.getFeatureElement());
|
280
|
String featurePattern = "//feature[contains(uuid,'" + featureUuid + "')]";
|
281
|
|
282
|
Element feature = (Element) XPath.selectSingleNode(context, featurePattern);
|
283
|
|
284
|
if(feature != null){
|
285
|
// get the parents of all feature elements with the current uuid
|
286
|
List<Element> descriptionElementElements = XPath.selectNodes(context, featurePattern + "/..");
|
287
|
// add matching description elements as children to this feature element
|
288
|
for(Element descriptionElementElement : descriptionElementElements){
|
289
|
descriptionElementElement.removeChild("feature");
|
290
|
descriptionElementElement.setName("descriptionelement");
|
291
|
XMLHelper.addContent(descriptionElementElement, "descriptionelements", feature);
|
292
|
}
|
293
|
XMLHelper.addContent(feature, parentElement);
|
294
|
}else if(featureNode.getChildren().size() > 0){
|
295
|
Element featureElement = featureNode.getFeatureElement();
|
296
|
Element featureElementClone = (Element) featureElement.clone();
|
297
|
feature = (Element) featureElementClone.detach();
|
298
|
XMLHelper.addContent(feature, parentElement);
|
299
|
}
|
300
|
|
301
|
// recurse into children
|
302
|
for(SimplifiedFeatureNode childFeatureNode : featureNode.getChildren()){
|
303
|
processFeatureNode(childFeatureNode, context, feature);
|
304
|
}
|
305
|
}
|
306
|
|
307
|
/**
|
308
|
* Retrieves the synonymy for the given taxonElement
|
309
|
*
|
310
|
* @param taxonElement
|
311
|
*/
|
312
|
private void populateSynonyms(Element taxonElement){
|
313
|
List<Element> synonymy = factory.getSynonymy(taxonElement);
|
314
|
|
315
|
for(Element synonymyNode : synonymy){
|
316
|
XMLHelper.addContent(synonymyNode, "synonymy", taxonElement);
|
317
|
}
|
318
|
}
|
319
|
|
320
|
|
321
|
|
322
|
/**
|
323
|
* TODO not implemented yet
|
324
|
* @param taxonElement
|
325
|
*/
|
326
|
private void populateImages(Element taxonElement){
|
327
|
logger.warn("not implemented yet");
|
328
|
}
|
329
|
}
|