source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIXML.java@ 26248

Last change on this file since 26248 was 26096, checked in by ak19, 12 years ago

Now the dc:identifier is set for OAI to either gs.OAIResourceURL if this was set by the user, else to srclinkFile if this exists, else a url to the Greenstone version of a document. This is the logic that GS2 used (in the output_custom_metadata function of dublincore.cpp of runtime-src's oaiservr). Having made this change, doing get-document over OAI works, as is required for the Downloading Over OAI tutorial. Get-document was previously not implemented during the updates to get GS3's OAI server to validate, since the OAI validator never checked for this. This is an optional operation that Greenstone 2 provided, and which GS3 now also allows.

File size: 30.0 KB
Line 
1/*
2 * OAIXML.java
3 * Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.util;
20
21import org.greenstone.util.GlobalProperties;
22
23import org.w3c.dom.*;
24
25import java.io.*;
26import java.net.*;
27import java.util.*;
28import java.text.DateFormat;
29import java.text.SimpleDateFormat;
30import org.apache.xerces.parsers.*;
31import org.apache.xml.serialize.*;
32
33// SAX
34import org.xml.sax.XMLReader;
35import org.xml.sax.SAXException;
36import org.xml.sax.SAXParseException;
37import org.xml.sax.helpers.DefaultHandler;
38import org.xml.sax.InputSource;
39
40// JAXP
41import javax.xml.parsers.FactoryConfigurationError;
42import javax.xml.parsers.ParserConfigurationException;
43import javax.xml.parsers.SAXParser;
44import javax.xml.parsers.SAXParserFactory;
45
46// import file Logger.java
47import org.apache.log4j.*;
48
49/** these constants are used for the OAI service */
50public class OAIXML {
51
52 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GSXML.class.getName());
53
54 // the leading keyword of oai protocol
55 public static final String VERB = "verb";
56
57 // six valid oai verbs
58 public static final String GET_RECORD = "GetRecord";
59 public static final String LIST_RECORDS = "ListRecords";
60 public static final String LIST_IDENTIFIERS = "ListIdentifiers";
61 public static final String LIST_SETS = "ListSets";
62 public static final String LIST_METADATA_FORMATS = "ListMetadataFormats";
63 public static final String IDENTIFY = "Identify";
64
65 // other valid oai parameters
66 public static final String OAI_METADATAFORMAT = "OAIMetadataFormat";
67 public static final String METADATA_NAMESPACE = "metadataNamespace";
68 public static final String OAI_DC = "oai_dc";
69 public static final String DC = "dc";
70 public static final String METADATA_PREFIX = "metadataPrefix";
71 public static final String FROM = "from";
72 public static final String UNTIL = "until";
73 public static final String SET = "set";
74 public static final String RESUMPTION_TOKEN = "resumptionToken";
75 public static final String RESUMPTION_TOKEN_EXPIRATION = "resumptionTokenExpiration";
76 public static final String IDENTIFIER = "identifier";
77
78 public static final String USE_STYLESHEET = "useOAIStylesheet";
79 public static final String STYLESHEET = "OAIStylesheet";
80 // words used to compose oai responses
81 public static final String ADMIN_EMAIL = "adminEmail";
82 public static final String BAD_ARGUMENT = "badArgument";
83 public static final String BAD_RESUMPTION_TOKEN = "badResumptionToken";
84 public static final String BAD_VERB = "badVerb";
85 public static final String BASE_URL = "baseURL";
86 public static final String CANNOT_DISSEMINATE_FORMAT = "cannotDisseminateFormat";
87 public static final String CODE = "code";
88 public static final String COLLECTION = "collection";
89 public static final String COLLECTION_LIST = "collectionList";
90 public static final String COMPLETE_LIST_SIZE = "completeListSize";
91 public static final String COMPRESSION = "compression";
92 public static final String CURSOR = "cursor";
93 public static final String DATESTAMP = "datestamp";
94 public static final String DELETED_RECORD = "deletedRecord";
95 public static final String DESCRIPTION = "description";
96 public static final String EARLIEST_DATESTAMP = "earliestDatestamp";
97 public static final String ERROR = "error";
98 public static final String EXPIRATION_DATE = "expirationDate";
99 public static final String GRANULARITY = "granularity";
100 public static final String GS3OAI = "GS3OAI";
101 public static final String GS_OAI_RESOURCE_URL = "gs.OAIResourceURL";
102 public static final String HAS_OAI = "hasOAI";
103 public static final String HEADER = "header";
104 public static final String ILLEGAL_OAI_VERB = "Illegal OAI verb";
105 public static final String INDEX_STEM = "indexStem";
106 public static final String LASTMODIFIED = "lastmodified";
107 public static final String MAPPING = "mapping";
108 public static final String MAPPING_LIST = "mappingList";
109 public static final String MESSAGE = "message";
110 public static final String METADATA = "metadata";
111 public static final String METADATA_FORMAT = "metadataFormat";
112 public static final String NAME = "name";
113 public static final String NO_RECORDS_MATCH = "noRecordsMatch";
114 public static final String OAI = "OAI";
115 public static final String OAI_DASH_PMH = "OAI-PMH";
116 public static final String OAI_LASTMODIFIED = "oailastmodified";
117 public static final String OAIPMH = "OAIPMH";
118 public static final String OAI_RESUMPTION_TOKENS = "OAIResumptionTokens";
119 public static final String OAI_SERVICE = "oaiService";
120 public static final String OAI_SET_LIST = "oaiSetList";
121 public static final String OAI_SERVICE_UNAVAILABLE = "OAI service unavailable";
122 public static final String OID = "OID";
123 public static final String PARAM = "param";
124 public static final String PARAM_LIST = "paramList";
125 public static final String PROTOCOL_VERSION = "protocolVersion";
126 public static final String RECORD = "record";
127 public static final String REQUEST = "request";
128 public static final String REPOSITORY_NAME = "repositoryName";
129 public static final String RESPONSE = "response";
130 public static final String RESPONSE_DATE = "responseDate";
131 public static final String RESUME_AFTER = "resumeAfter";
132 public static final String SCHEMA = "schema";
133 public static final String SERVICE = "service";
134 public static final String SERVICE_UNAVAILABLE = "service unavailable";
135 public static final String SET_SPEC = "setSpec";
136 public static final String SET_NAME = "setName";
137 public static final String SET_DESCRIPTION = "setDescription";
138 public static final String SITE = "site";
139 public static final String TO = "to";
140 public static final String TYPE = "type";
141 public static final String VALUE = "value";
142
143 //Two error and exception conditions for the verb 'ListMetadataFormats'
144 public static final String ID_DOES_NOT_EXIST = "idDoesNotExist";
145 public static final String NO_METADATA_FORMATS = "noMetadataFormats";
146
147 // The node id in the collection database, which contains all the OIDs in the database
148 public static final String BROWSELIST = "browselist";
149
150 //system-dependent file separator, maybe '/' or '\'
151 public static final String FILE_SEPARATOR = File.separator;
152 public static final String OAI_VERSION1 = "1.0";
153 public static final String OAI_VERSION2 = "2.0";
154 /*************************above are final values****************************/
155
156 public static Element resumption_token_elem = null;
157 //used when saving the token file
158 public static File resumption_token_file = null;
159 //public static ArrayList token_list = new ArrayList();
160
161 //initialized in getOAIConfigXML()
162 public static Element oai_config_elem = null;
163
164 //stores the date format "yyyy-MM-ddTHH:mm:ssZ"
165 public static String granularity = "";
166
167 // http://www.openarchives.org/OAI/openarchivesprotocol.html#DatestampsRequests
168 // specifies that all repositories must support YYYY-MM-DD (yyyy-MM-dd in Java)
169 // this would be in addition to the other (optional) granularity of above that
170 // a repository may additionally choose to support.
171 public static final String default_granularity = "yyyy-MM-dd";
172
173 //this value is overriden in getOAIConfigXML()
174 public static long token_expiration = 7200;
175
176 /** which version of oai that this oaiserver supports; default is 2.0
177 * initialized in getOAIConfigXML()
178 */
179 public static String oai_version = "2.0";
180 public static String baseURL = "";
181
182 /**response owner document */
183 public static Document response_doc = new XMLConverter().newDOM();
184
185 public static String[] special_char = {"/", "?", "#", "=", "&", ":", ";", " ", "%", "+"};
186 public static String[] escape_sequence = {"%2F", "%3F", "%23", "%3D", "%26", "%3A", "%3B", "%20", "%25", "%2B"};
187// /** key=special character; value=escaped sequence */
188// public static HashMap encode_map = new HashMap();
189// /** key=escaped sequence; value=special character */
190// public static HashMap decode_map = new HashMap();
191
192 public static void init() {
193 resumption_token_elem = getOAIResumptionTokenXML();
194 }
195 public static String getOAIVersion() {
196 return oai_version;
197 }
198
199 public static String getBaseURL() {
200 return baseURL;
201 }
202
203 public static Element createElement(String tag_name) {
204 return response_doc.createElement(tag_name);
205 }
206 /**Compose a response element used when OAIPMH service sending responses thru
207 * ServiceCluster and MessageRouter, as they automatically wrap a message element
208 * on this response element
209 */
210 public static Element getResponse(Element core_msg) {
211 Element res = createElement(RESPONSE);
212 res.appendChild(response_doc.importNode(core_msg, true));
213 return res;
214 }
215 /** Read in OAIResumptionToken.xml (residing web/WEB-INF/classes/) */
216 public static Element getOAIResumptionTokenXML() {
217
218 // The system environment variable $GSDL3HOME(ends ../web) does not contain the file separator
219 resumption_token_file = new File(GlobalProperties.getGSDL3Home() + FILE_SEPARATOR +
220 "WEB-INF" + FILE_SEPARATOR + "classes" +FILE_SEPARATOR + "OAIResumptionToken.xml");
221 if (resumption_token_file.exists()) {
222 Document token_doc = parseXMLFile(resumption_token_file);
223 if (token_doc != null) {
224 resumption_token_elem = token_doc.getDocumentElement();
225 } else {
226 logger.error("Fail to parse resumption token file OAIReceptionToken.xml.");
227 return null;
228 }
229 //remove all expired tokens
230 clearExpiredTokens();
231 return resumption_token_elem;
232 }
233 //if resumption_token_file does not exist
234 logger.info("resumption token file: "+ resumption_token_file.getPath()+" not found! create an empty one.");
235 resumption_token_elem = createElement(OAI_RESUMPTION_TOKENS);
236 saveOAIResumptionTokenXML(resumption_token_elem);
237 return resumption_token_elem;
238 }
239 public static void saveOAIResumptionTokenXML(Element token_elem) {
240 if(writeXMLFile(resumption_token_file, token_elem.getOwnerDocument()) == false) {
241 logger.error("Fail to save the resumption token file");
242 }
243 }
244 public static void clearExpiredTokens() {
245 boolean token_deleted = false;
246 NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, RESUMPTION_TOKEN);
247 for (int i=0; i<tokens.getLength(); i++) {
248 Element token_elem = (Element)tokens.item(i);
249 String expire_str = token_elem.getAttribute(EXPIRATION_DATE);
250 long datestamp = getTime(expire_str); // expire_str is in milliseconds
251 if(datestamp < System.currentTimeMillis()) {
252 resumption_token_elem.removeChild(token_elem);
253 token_elem = null;
254 token_deleted = true;
255 }
256 }
257
258 if(token_deleted) {
259 saveOAIResumptionTokenXML(resumption_token_elem);
260 }
261 }
262 public static boolean containsToken(String token) {
263 NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, OAIXML.RESUMPTION_TOKEN);
264 for (int i=0; i<tokens.getLength(); i++) {
265 if(token.equals(GSXML.getNodeText((Element)tokens.item(i)).trim() ))
266 return true;
267 }
268 return false;
269 }
270 public static void addToken(Element token) {
271 Document doc = resumption_token_elem.getOwnerDocument();
272 resumption_token_elem.appendChild(duplicateElement(doc, token, true));
273 saveOAIResumptionTokenXML(resumption_token_elem);
274 }
275 public static void addToken(String token) {
276 Element te = resumption_token_elem.getOwnerDocument().createElement(OAIXML.RESUMPTION_TOKEN);
277 //add expiration att
278 resumption_token_elem.appendChild(te);
279 saveOAIResumptionTokenXML(resumption_token_elem);
280 }
281 public static boolean removeToken(String token) {
282 NodeList tokens = GSXML.getChildrenByTagName(resumption_token_elem, OAIXML.RESUMPTION_TOKEN);
283 int num_tokens = tokens.getLength();
284 for (int i=0; i<num_tokens; i++) {
285 Element e = (Element)(tokens.item(i));
286 if(token.equals(GSXML.getNodeText(e))) {
287 resumption_token_elem.removeChild(e);
288 saveOAIResumptionTokenXML(resumption_token_elem);
289 return true;
290 }
291 }
292 return false;
293 }
294 /** Read in OAIConfig.xml (residing web/WEB-INF/classes/) and use it to configure the receptionist etc.
295 * the oai_version and baseURL variables are also set in here.
296 * The init() method is also called in here. */
297 public static Element getOAIConfigXML() {
298 init();
299
300 // The system environment variable $GSDL3HOME(ends ../web) does not contain the file separator
301 File oai_config_file = new File(GlobalProperties.getGSDL3Home() + FILE_SEPARATOR +
302 "WEB-INF" + FILE_SEPARATOR + "classes" +FILE_SEPARATOR + "OAIConfig.xml");
303 if (!oai_config_file.exists()) {
304 logger.error(" oai config file: "+oai_config_file.getPath()+" not found!");
305 return null;
306 }
307 Document oai_config_doc = parseXMLFile(oai_config_file);
308 if (oai_config_doc != null) {
309 oai_config_elem = oai_config_doc.getDocumentElement();
310 } else {
311 logger.error("Fail to parse oai config file OAIConfig.xml.");
312 return null;
313 }
314
315 //initialize oai_version
316 Element protocol_version = (Element)GSXML.getChildByTagName(oai_config_elem, PROTOCOL_VERSION);
317 oai_version = GSXML.getNodeText(protocol_version).trim();
318
319 // initialize baseURL
320 Element base_url_elem = (Element)GSXML.getChildByTagName(oai_config_elem, BASE_URL);
321 baseURL = GSXML.getNodeText(base_url_elem);
322
323 //initialize token_expiration
324 Element expiration = (Element)GSXML.getChildByTagName(oai_config_elem, RESUMPTION_TOKEN_EXPIRATION);
325 String expire_str = GSXML.getNodeText(expiration).trim();
326 if (expiration != null && !expire_str.equals("")) {
327 token_expiration = Long.parseLong(expire_str);
328 }
329
330 // read granularity from the config file
331 Element granu_elem = (Element)GSXML.getChildByTagName(oai_config_elem, GRANULARITY);
332 //initialize the granu_str which might be used by other methods (eg, getDate())
333 granularity = GSXML.getNodeText(granu_elem).trim();
334
335 //change "yyyy-MM-ddTHH:mm:ssZ" to "yyyy-MM-dd'T'HH:mm:ss'Z'"
336 granularity = granularity.replaceAll("T", "'T'");
337 granularity = granularity.replaceAll("Z", "'Z'");
338 granularity = granularity.replaceAll("YYYY", "yyyy").replaceAll("DD", "dd").replaceAll("hh", "HH");
339 return oai_config_elem;
340 }
341
342 public static String[] getMetadataMapping(Element metadata_format) {
343
344 if (metadata_format == null) {
345 return null;
346 }
347 NodeList mappings = metadata_format.getElementsByTagName(MAPPING);
348 int size = mappings.getLength();
349 if (size == 0) {
350 logger.info("No metadata mappings are provided in OAIConfig.xml.");
351 return null;
352 }
353 String[] names = new String[size];
354 for (int i=0; i<size; i++) {
355 names[i] = GSXML.getNodeText((Element)mappings.item(i)).trim();
356 }
357 return names;
358
359 }
360
361 public static String[] getGlobalMetadataMapping(String prefix) {
362 Element list_meta_formats = (Element)GSXML.getChildByTagName(oai_config_elem, LIST_METADATA_FORMATS);
363 if(list_meta_formats == null) {
364 return null;
365 }
366 Element metadata_format = GSXML.getNamedElement(list_meta_formats, METADATA_FORMAT, METADATA_PREFIX, prefix);
367 if(metadata_format == null) {
368 return null;
369 }
370 return getMetadataMapping(metadata_format);
371 }
372
373
374 public static long getTokenExpiration() {
375 return token_expiration*1000; // in milliseconds
376 }
377
378 /** TODO: returns a basic response for appropriate oai version
379 *
380 */
381 public static Element createBasicResponse(String verb, String[] pairs) {
382
383 Element response = createResponseHeader(verb);
384
385 //set the responseDate and request elements accordingly
386 Element request_elem = (Element)GSXML.getChildByTagName(response, REQUEST);
387 if (verb.equals("")) {
388 request_elem.setAttribute(VERB, verb);
389 }
390 int num_pairs = (pairs==null)? 0 : pairs.length;
391 for (int i=num_pairs - 1; i>=0; i--) {
392 int index = pairs[i].indexOf("=");
393 if (index != -1) {
394 String[] strs = pairs[i].split("=");
395 if(strs != null && strs.length == 2) {
396 request_elem.setAttribute(strs[0], oaiDecode(strs[1]));
397 }
398 }
399 }//end of for()
400
401 GSXML.setNodeText(request_elem, baseURL);
402
403 Node resp_date = GSXML.getChildByTagName(response, RESPONSE_DATE);
404 if (resp_date != null) {
405 GSXML.setNodeText((Element)resp_date, getCurrentUTCTime());
406 }
407
408 return response;
409 }
410 /** @param error_code the value of the code attribute
411 * @param error_text the node text of the error element
412 * @return an oai error element
413 * Used by receptionist
414 */
415 public static Element createErrorElement(String error_code, String error_text) {
416 Element error = createElement(ERROR);
417 error.setAttribute(CODE, error_code);
418 GSXML.setNodeText(error, error_text);
419 return error;
420 }
421
422 /** convert the escaped sequences (eg, '%3A') of those special characters back to their
423 * original form (eg, ':').
424 */
425 public static String oaiDecode(String escaped_str) {
426 logger.info("oaiDecode() " +escaped_str);
427 for (int i=0; i<special_char.length; i++) {
428 if (escaped_str.indexOf(escape_sequence[i]) != -1) {
429 escaped_str = escaped_str.replaceAll(escape_sequence[i], special_char[i]);
430 }
431 }
432 //escaped_str = escaped_str.replaceAll("%3A", ":");
433 return escaped_str;
434 }
435 /** convert those special characters (eg, ':') to their
436 * escaped sequences (eg, '%3A').
437 */
438 public static String oaiEncode(String original_str) {
439 logger.info("oaiEncode() " + original_str);
440 for (int i=0; i<special_char.length; i++) {
441 if (original_str.indexOf(special_char[i]) != -1) {
442 original_str = original_str.replaceAll(special_char[i], escape_sequence[i]);
443 }
444 }
445 //original_str = original_str.replaceAll(":", "%3A");
446 return original_str;
447 }
448 /** convert YYYY-MM_DDThh:mm:ssZ to yyyy-MM-ddTHH:mm:ssZ
449 */
450 public static String convertToJava(String oai_format) {
451 oai_format = oai_format.replaceAll("YYYY", "yyyy").replaceAll("DD", "dd").replaceAll("hh", "HH");
452 return oai_format;
453 }
454 /** convert yyyy-MM-ddTHH:mm:ssZ to YYYY-MM_DDThh:mm:ssZ
455 */
456 public static String convertToOAI(String java_format) {
457 java_format = java_format.replaceAll("yyyy", "YYYY").replaceAll("dd", "DD").replaceAll("HH", "hh");
458 return java_format;
459 }
460 public static String getCurrentUTCTime() {
461 Date current_utc = new Date(System.currentTimeMillis());
462 //granularity is in the form: yyyy-MM-dd'T'HH:mm:ss'Z '
463 DateFormat formatter = new SimpleDateFormat(granularity);
464 return formatter.format(current_utc);
465 }
466 /** get a Date object from a Date format pattern string
467 *
468 * @param pattern - in the form: 2007-06-14T16:48:25Z, for example.
469 * @return a Date object - null if the pattern is not in the specified form
470 */
471
472 public static Date getDate(String pattern) {
473 if (pattern == null || pattern.equals("")) {
474 return null;
475 }
476 Date date = null;
477// String str = pattern.replaceAll("T", " ");
478// str = str.replaceAll("Z", "");
479 SimpleDateFormat sdf = null;
480 try {
481 sdf = new SimpleDateFormat(granularity);
482 date = sdf.parse(pattern);
483 } catch(Exception e) {
484 if(!default_granularity.equals(granularity)) { // try validating against default granularity
485 try {
486 date = null;
487 sdf = null;
488 sdf = new SimpleDateFormat(default_granularity);
489 date = sdf.parse(pattern);
490 } catch(Exception ex) {
491 logger.error("invalid date format: " + pattern);
492 return null;
493 }
494 } else {
495 logger.error("invalid date format: " + pattern);
496 return null;
497 }
498 }
499 return date;
500 }
501 /** get the million second value from a string representing time in a pattern
502 * (eg, 2007-06-14T16:48:25Z)
503 */
504 public static long getTime(String pattern) {
505 if (pattern == null || pattern.equals("")) {
506 return -1;
507 }
508 Date date = null;
509 SimpleDateFormat sdf = null;
510 try {
511 //granularity is a global variable in the form: yyyy-MM-ddTHH:mm:ssZ
512 sdf = new SimpleDateFormat(granularity);
513 date = sdf.parse(pattern);
514 } catch(Exception e) {
515 if(!default_granularity.equals(granularity)) { // try validating against default granularity
516 try {
517 date = null;
518 sdf = null;
519 sdf = new SimpleDateFormat(default_granularity);
520 date = sdf.parse(pattern);
521 } catch(Exception ex) {
522 logger.error("invalid date format: " + pattern);
523 return -1;
524 }
525 } else {
526 logger.error("invalid date format: " + pattern);
527 return -1;
528 }
529 }
530 return date.getTime();
531 }
532 /** get the string representation of a time from a long value(long type)
533 */
534 public static String getTime(long milliseconds) {
535 Date date = new Date(milliseconds);
536 SimpleDateFormat sdf = new SimpleDateFormat(granularity);
537 return sdf.format(date);
538 }
539 public static Element createResponseHeader(String verb) {
540 String tag_name = (oai_version.equals(OAI_VERSION2))? OAI_DASH_PMH : verb;
541 Element oai = response_doc.createElement(tag_name);
542 Element resp_date = response_doc.createElement(RESPONSE_DATE);
543 Element req = response_doc.createElement(REQUEST);
544 oai.appendChild(resp_date);
545 oai.appendChild(req);
546
547 if(oai_version.equals(OAI_VERSION2)) {
548 oai.setAttribute("xmlns", "http://www.openarchives.org/OAI/2.0/");
549 oai.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
550 oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/ \n http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd");
551 } else {
552 oai.setAttribute("xmlns", "http://www.openarchives.com/OAI/1.1/OAI_" + verb);
553 oai.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
554 oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/1.1/OAI_" + verb + "\n http://www.openarchives.org/OAI/1.1/OAI_" + verb + ".xsd");
555 }
556 return oai;
557 }
558 public static Element getMetadataPrefixElement(String tag_name, String version) {
559 //examples of tag_name: dc, oai_dc:dc, etc.
560 Element oai = response_doc.createElement(tag_name);
561 if (version.equals(OAI_VERSION2)) {
562 oai.setAttribute("xmlns:oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/");
563 oai.setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
564 oai.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
565 oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/oai_dc/ \n http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
566 } else {
567 oai.setAttribute("xmlns", "ttp://www.openarchives.com/OAI/1.1/");
568 oai.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
569 oai.setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/1.1/" + tag_name + ".xsd");
570 }
571
572 return oai;
573 }
574 public static HashMap<String, Node> getChildrenMapByTagName(Node n, String tag_name) {
575
576 HashMap<String, Node> map= new HashMap<String, Node>();
577 Node child = n.getFirstChild();
578 while (child!=null) {
579 String name = child.getNodeName();
580 if(name.equals(tag_name)) {
581 map.put(name, child);
582 }
583 child = child.getNextSibling();
584 }
585 return map;
586 }
587
588 /** Duplicates an element */
589 public static Element duplicateElement (Document owner, Element element, boolean with_attributes) {
590 return duplicateElementNS (owner, element, null, with_attributes);
591 }
592
593 /** Duplicates an element */
594 public static Element duplicateElementNS (Document owner,
595 Element element,
596 String namespace_uri,
597 boolean with_attributes) {
598 Element duplicate;
599 if (namespace_uri == null) {
600 duplicate = owner.createElement (element.getTagName ());
601 } else {
602 duplicate = owner.createElementNS (namespace_uri, element.getTagName ());
603 }
604 // Copy element attributes
605 if (with_attributes) {
606 NamedNodeMap attributes = element.getAttributes ();
607 for (int i = 0; i < attributes.getLength (); i++) {
608 Node attribute = attributes.item (i);
609 duplicate.setAttribute (attribute.getNodeName (), attribute.getNodeValue ());
610 }
611 }
612
613 // Copy element children
614 NodeList children = element.getChildNodes ();
615 for (int i = 0; i < children.getLength (); i++) {
616 Node child = children.item (i);
617 duplicate.appendChild (owner.importNode (child, true));
618 }
619
620 return duplicate;
621 }
622
623 public static void copyElement(Element to, Element from, String elem_name) {
624
625 Document to_doc = to.getOwnerDocument();
626 Node child = from.getFirstChild();
627 while (child != null) {
628 if (child.getNodeName().equals(elem_name)) {
629 to.appendChild(to_doc.importNode(child, true));
630 return;
631 }
632 child = child.getNextSibling();
633 }
634 }
635 public static HashMap<String, String> getParamMap(NodeList params) {
636 HashMap<String, String> map = new HashMap<String, String>();
637 for(int i=0; i<params.getLength(); i++) {
638 Element param = (Element)params.item(i);
639 String param_name = param.getAttribute(OAIXML.NAME);
640 String param_value = param.getAttribute(OAIXML.VALUE);
641 map.put(param_name, param_value);
642 }
643 return map;
644 }
645 /** Parse an XML document from a given file */
646 static public Document parseXMLFile (File xml_file) {
647 // No file? No point trying!
648 if (xml_file.exists () == false) {
649 return null;
650 }
651 Document doc = null;
652 try {
653 doc = parseXML (new FileInputStream (xml_file));
654 }
655 catch (Exception exception) {
656 logger.error(exception.toString());
657 return null;
658 }
659 return doc;
660 }
661
662
663 /** Parse an XML document from a given input stream */
664 static public Document parseXML (InputStream xml_input_stream) {
665 Document document = null;
666
667 try {
668 InputStreamReader isr = new InputStreamReader (xml_input_stream, "UTF-8");
669 Reader xml_reader = new BufferedReader (isr);
670 document = parseXML (xml_reader);
671 isr.close ();
672 xml_input_stream.close ();
673 }
674 catch (Exception exception) {
675 logger.error(exception.toString());
676 }
677
678 return document;
679 }
680
681 /** Parse an XML document from a given reader */
682 static public Document parseXML (Reader xml_reader) {
683 Document document = null;
684
685 try {
686 InputSource isc = new InputSource (xml_reader);
687 DOMParser parser = new DOMParser ();
688 parser.setFeature ("http://xml.org/sax/features/validation", false);
689 parser.setFeature ("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
690 // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
691 parser.setFeature ("http://apache.org/xml/features/dom/defer-node-expansion", true);
692 parser.setFeature ("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
693 parser.parse (isc);
694 document = parser.getDocument ();
695 }
696 catch (SAXException exception) {
697 System.err.println ("SAX exception: " + exception.getMessage ());
698 logger.error(exception.toString());
699 }
700 catch (Exception exception) {
701 logger.error(exception.toString());
702 }
703
704 return document;
705 }
706 /** Write an XML document to a given file */
707 static public boolean writeXMLFile (File xml_file, Document document) {
708 try {
709 OutputStream os = new FileOutputStream (xml_file);
710 // Create an output format for our document.
711 OutputFormat f = new OutputFormat (document);
712 f.setEncoding ("UTF-8");
713 f.setIndenting (true);
714 f.setLineWidth (0); // Why isn't this working!
715 f.setPreserveSpace (false);
716 // Create the necessary writer stream for serialization.
717 OutputStreamWriter osw = new OutputStreamWriter (os, "UTF-8");
718 Writer w = new BufferedWriter (osw);
719 // Generate a new serializer from the above.
720 XMLSerializer s = new XMLSerializer (w, f);
721 s.asDOMSerializer ();
722 // Finally serialize the document to file.
723 s.serialize (document);
724 // And close.
725 os.close ();
726 return true;
727 }
728 catch (Exception exception) {
729 logger.error(exception.toString());
730 return false;
731 }
732 }
733
734
735}
736
737
738
739
740
741
Note: See TracBrowser for help on using the repository browser.