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

Last change on this file since 25635 was 25635, checked in by sjm84, 12 years ago

Fixing Greenstone 3's use (or lack thereof) of generics, this was done automatically so we may want to change it over time. This change will also auto-format any files that have not already been formatted.

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