source: trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.java@ 8699

Last change on this file since 8699 was 8461, checked in by kjdon, 20 years ago

added in Chi's changes for METS documents. mostly the addition of new/improved parseXML methods

  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1package org.greenstone.gsdl3.gs3build.metadata;
2
3import java.util.List;
4import java.util.ArrayList;
5import java.util.Iterator;
6
7import java.io.PrintWriter;
8
9import java.sql.SQLException;
10import java.sql.ResultSet;
11
12import org.w3c.dom.Document;
13import org.w3c.dom.Element;
14import org.w3c.dom.NamedNodeMap;
15import org.w3c.dom.Node;
16import org.w3c.dom.NodeList;
17import org.w3c.dom.Text;
18
19import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
20
21import org.greenstone.gsdl3.gs3build.util.XMLTools;
22import org.greenstone.gsdl3.gs3build.util.GS3SQLConnection;
23import org.greenstone.gsdl3.gs3build.database.*;
24
25/**
26 * Support the descriptive metadata of a given document
27 *
28 * The descriptive metadata can occur multiple times, so this 'wrapper' is
29 * in fact a holder for a number of individual metadata sets. Individual
30 * metadata groups are found in METSNamespace items.
31 *
32 *
33 */
34
35import org.greenstone.gsdl3.gs3build.util.MultiMap;
36
37public class METSDescriptive
38{ MultiMap map;
39 String ID;
40 String name;
41
42 public METSDescriptive(String ID, String name)
43 { this.map = new MultiMap();
44 this.ID = ID;
45 this.name = name;
46 }
47
48 public String getID()
49 { return this.ID;
50 }
51
52 public String getName()
53 { return this.name;
54 }
55
56 public void addNamespace(METSNamespace namespace)
57 { this.map.put(namespace.getName(), namespace);
58 }
59
60 public METSNamespace getNamespace(String namespace)
61 { return (METSNamespace) this.map.get(namespace);
62 }
63
64 /**
65 * Get the version of a metadata namespace that can be used for
66 * adding new values to the document. Remember, each namespace may
67 * occur more than once, but only one of the occurrences can be 'open'.
68 *
69 * @param <code>String</code> the name of the namespace
70 */
71 public METSNamespace getOpenNamespace(String namespace)
72 { if (this.map.getAll(namespace) == null)
73 { return null;
74 }
75
76 Iterator namespaces = ((List) this.map.getAll(namespace)).iterator();
77
78 while (namespaces.hasNext())
79 { METSNamespace namespaceData = (METSNamespace) namespaces.next();
80
81 if (namespaceData.isEditable())
82 { return namespaceData;
83 }
84 }
85 return null;
86 }
87
88 /**
89 * Add a piece of metadata to this document. Existing values are preserved.
90 *
91 * @param <code>String</code> the namespace in which the metadata occurs
92 * @param <code>String</code> the label of the metadata
93 * @param <code>String</code> the value of the metadata
94 */
95 public void addMetadata(String namespace, String label, String value)
96 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
97
98 if (namespaceData == null ||
99 namespaceData.isEditable() == false)
100 { namespaceData = NamespaceFactory.initNamespace(namespace);
101 this.addNamespace(namespaceData);
102 }
103 namespaceData.addMetadata(label, value);
104 }
105
106 /**
107 * Add a piece of metadata to this document. Existing values in editable
108 * parts of the document's metadata are destroyed.
109 *
110 * @param <code>String</code> the namespace in which the metadata occurs
111 * @param <code>String</code> the label of the metadata
112 * @param <code>String</code> the value of the metadata
113 */
114 public void setMetadata(String namespace, String label, String value)
115 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
116
117 if (namespaceData == null ||
118 namespaceData.isEditable() == false)
119 { namespaceData = NamespaceFactory.initNamespace(namespace);
120 this.addNamespace(namespaceData);
121 }
122 namespaceData.setMetadata(label, value);
123 }
124
125 /**
126 * Remove the metadata for a particular label.
127 *
128 * @param <code>String</code> the namespace in which the metadata occurs
129 * @param <code>String</code> the label of the metadata
130 */
131 public void removeMetadata(String namespace, String label)
132 { METSNamespace namespaceData = this.getOpenNamespace(namespace);
133
134 if (namespaceData != null && namespaceData.isEditable() == true)
135 { namespaceData.removeMetadata(label);
136 }
137 }
138
139 /**
140 * Fetch a <code>List</code> of the values matching the given label in
141 * the requisite namespace.
142 *
143 * @param <code>String</code> namespace
144 * @param <code>String</code> label of metadata to match
145 *
146 * @return <code>List</code> the corresponding values found.
147 */
148 public List getMetadata(String namespace, String label)
149 {
150 // Simple case - no metadata
151 if (!this.map.containsKey(namespace))
152 { return null;
153 }
154
155 // if there's just one instance of the requisite namespace,
156 // then again it is a simple case
157 if (this.map.getAll(namespace).size() == 1)
158 { return this.getNamespace(namespace).getMetadata(label);
159 }
160
161 // otherwise, step through and accumulate
162 List accumulatedValues = new ArrayList();
163 Iterator namespaceIterator = this.map.getAll(namespace).iterator();
164 while (namespaceIterator.hasNext())
165 { METSNamespace localNamespace = (METSNamespace) namespaceIterator.next();
166
167 List localList = localNamespace.getMetadata(label);
168 if (localList != null && localList.size() > 0)
169 { accumulatedValues.addAll(localList);
170 }
171 }
172
173 // if the result of the accumulation is empty, return a null item
174 if (accumulatedValues.size() == 0)
175 { return null;
176 }
177
178 return accumulatedValues;
179 }
180
181 protected void parse_xmlData(METSNamespace namespace, Element element)
182 {
183 if (namespace==null) {
184 System.err.println("namespace is null!!!!");
185 }
186 NodeList children = element.getChildNodes();
187
188 for (int c = 0; c < children.getLength(); c++) {
189 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
190 continue;
191 }
192
193 Element child = (Element) children.item(c);
194 String childName = child.getNodeName();
195
196 // if (childName.equals("gsdl2:Metadata")) {
197 if (childName.equals("gsdl3:Metadata")) {
198 String metaName = child.getAttribute("name");
199 Text text = (Text) child.getFirstChild();
200 String metaValue = text.getData();
201
202 addMetadata(namespace.getName(),metaName, metaValue);
203 }
204 }
205 }
206
207 public void parse_mdWrap(Element element)
208 {
209 // deal with mets:mdWrap
210
211 METSNamespace namespace = NamespaceFactory.parseXML(element);
212
213 NodeList children = element.getChildNodes();
214
215 for (int c = 0; c < children.getLength(); c ++) {
216 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
217 continue;
218 }
219
220 Element child = (Element) children.item(c);
221 String childName = child.getNodeName();
222
223 if (childName.equals("mets:xmlData")) {
224 parse_xmlData(namespace, child);
225 } else {
226 System.err.println("Warning: unrecognised tag " + childName
227 + "in mets:mdWrap");
228 }
229 }
230 }
231
232 /**
233 * Parse an XML Element as a METS Descriptive Metadata section
234 *
235 * @param <code>Element</code> the XML element which represents the dmdSec itself
236 */
237
238 //public static METSDescriptive parseXML(Element element, METSDescriptive thisDescriptive)
239 public static METSDescriptive parseXML(Element element)
240 {
241 // Note: no parsing of attributes required, we just move onto
242 // the metadata namespaces/sections themselves
243
244 // deal with mets:dmdSec
245 String ID = element.getAttribute("ID");
246 String label = element.getAttribute("GROUPID");
247
248 METSDescriptive thisDescriptive = new METSDescriptive(ID, label);
249
250 //thisDescriptive = new METSDescriptive(ID, label);
251
252 NodeList children = element.getChildNodes();
253
254 for (int c = 0; c < children.getLength(); c ++) {
255 if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
256 continue;
257 }
258
259 Element child = (Element) children.item(c);
260 String childName = child.getNodeName();
261
262 if (childName.equals("mets:mdRef")) {
263 //for External Descriptive Metadata
264 METSNamespace namespace = NamespaceFactory.parseXML(element);
265 System.err.println("*** mets::mdRef does not appear to be implemented yet");
266 } else if (childName.equals("mets:mdWrap")) {
267 thisDescriptive.parse_mdWrap(child);
268 } else {
269 // TODO: raise an error!
270 System.out.println("Error: METSDescriiptive: unrecognised tag "+childName);
271 }
272 }
273 return thisDescriptive;
274 }
275
276
277 /**
278 * Parse an XML Element as a METS Descriptive Metadata section
279 *
280 * @param <code>Element</code> the XML element which represents the dmdSec itself
281 */
282 /* public static METSDescriptive parseXML(Element element)
283 { // Note: no parsing of attributes required, we just move onto the metadata
284 // namespaces/sections themselves
285 String ID = element.getAttribute("ID");
286 String label = element.getAttribute("GROUPID");
287 METSDescriptive thisDescriptive = new METSDescriptive(ID, label);
288
289 NodeList children = element.getChildNodes();
290
291 for (int c = 0; c < children.getLength(); c ++)
292 { if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
293 continue;
294 }
295
296 Element childElement = (Element) children.item(c);
297 if (childElement.getNodeName().equals("mets:mdRef"))
298 { METSNamespace namespace = NamespaceFactory.parseXML(element);
299 }
300 else if (childElement.getNodeName().equals("mets:mdWrap"))
301 { METSNamespace namespace = NamespaceFactory.parseXML(element);
302 }
303 else
304 { // TODO: raise an error!
305 }
306 }
307 return thisDescriptive;
308 }
309 */
310
311 /**
312 * Write the document metadata to a <code>PrintWriter</code> in METS
313 * XML format.
314 *
315 * @param <code>PrintWriter</code> the writer to use for output
316 */
317 public void write(PrintWriter output)
318 { String tag = XMLTools.getOpenTag("mets", "dmdSec");
319 tag = XMLTools.addAttribute(tag, "ID", this.ID);
320 tag = XMLTools.addAttribute(tag, "GROUPID", this.name);
321 output.println(tag);
322
323 Iterator keys = this.map.keySet().iterator();
324
325 // get the keys one by one
326 while (keys.hasNext())
327 { Object nextKey = keys.next();
328 if (nextKey == null)
329 { continue;
330 }
331 String key = nextKey.toString();
332
333 // get every copy of the current namespace name - namespaces may
334 // occur more than once, so this is a List
335 Iterator namespaces = this.map.getAll(key).iterator();
336
337 // namespaces will write themselves...
338 while (namespaces.hasNext())
339 { METSNamespace namespace = (METSNamespace) namespaces.next();
340
341 namespace.write(output);
342 }
343 }
344
345 tag = XMLTools.getCloseTag("mets", "dmdSec");
346 output.println(tag);
347 }
348
349 public void copy_metadata(METSDescriptive dst)
350 {
351 Iterator keys = this.map.keySet().iterator();
352
353 // get the keys one by one
354 while (keys.hasNext()) {
355 Object nextKey = keys.next();
356 if (nextKey == null) {
357 continue;
358 }
359 String key = nextKey.toString();
360
361 System.err.println("*** Namespace = " + key);
362
363 // get every copy of the current namespace name - namespaces may
364 // occur more than once, so this is a List
365 Iterator namespaces = this.map.getAll(key).iterator();
366
367 while (namespaces.hasNext()) {
368 METSNamespace namespace = (METSNamespace) namespaces.next();
369
370 // for each metadata name
371
372 Iterator mdnIter = namespace.getMetadataNames();
373 while (mdnIter.hasNext()) {
374
375 String md_name = mdnIter.next().toString();
376
377 List values = getMetadata(key, md_name);
378
379 if (values != null) {
380 Iterator valueIter = values.iterator();
381 while (valueIter.hasNext()) {
382 String value = valueIter.next().toString();
383 dst.addMetadata("gsdl3",md_name,value);
384 }
385 }
386 }
387 }
388 }
389 }
390
391
392 public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
393 { // check if this node is in the
394 int sqlId = -1;
395
396 // System.out.println("Writing " + connection.toString());
397
398 GS3SQLSelect select = new GS3SQLSelect("metadata");
399 select.addField("*");
400 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetaID", "=", this.ID);
401 GS3SQLWhereItem item = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
402 GS3SQLWhere where = new GS3SQLWhere(whereItem);
403 where.add(item);
404 select.setWhere(where);
405
406 connection.execute(select.toString());
407
408 try {
409 GS3SQLAction action;
410
411 ResultSet resultSet = connection.getResultSet();
412
413 if (resultSet != null &&
414 resultSet.first()) {
415 // the node already exists - no need to do anything as such
416 GS3SQLUpdate update = new GS3SQLUpdate("metadata");
417 update.setWhere(where);
418 action = update;
419 }
420 else
421 { // Set result set to null, just in case next() didn't work above...
422 resultSet = null;
423
424 // It is a new node and needs writing
425 action = new GS3SQLInsert("metadata");
426
427 action.addValue("DocID", document.getID().toString());
428 action.addValue("MetaID", this.ID);
429 }
430
431 // always set the group identifier
432 action.addValue("GroupID", this.name);
433
434 // execute the action as required
435 connection.execute(action.toString());
436
437 // create a new resultset if necessary
438 if (resultSet == null) {
439 // now execute the select statement again to get the new identifier
440 // 'MetadataRef'
441 // System.out.println(select.toString());
442 connection.execute(select.toString());
443
444 resultSet = connection.getResultSet();
445 resultSet.first();
446 }
447
448 // get the reference for this item...
449 sqlId = resultSet.getInt("MetadataRef");
450 }
451 catch (SQLException sql)
452 { System.out.println(sql);
453 }
454
455 Iterator keys = this.map.keySet().iterator();
456
457 // get the keys one by one
458 while (keys.hasNext())
459 { Object nextKey = keys.next();
460 if (nextKey == null)
461 { continue;
462 }
463 String key = nextKey.toString();
464
465 // get every current namespace - namespaces may
466 // occur more than once, so this is a List
467 Iterator namespaces = this.map.getAll(key).iterator();
468
469 // namespaces will write themselves...
470 while (namespaces.hasNext())
471 { METSNamespace namespace = (METSNamespace) namespaces.next();
472
473 if (!namespace.writeSQL(sqlId, connection))
474 { return false;
475 }
476 }
477 }
478 return true;
479 }
480
481 public static METSDescriptive readSQL(DocumentInterface document, GS3SQLConnection connection,
482 ResultSet resultSet)
483 {
484 try {
485 String ID = resultSet.getString("MetaID");
486 String name = resultSet.getString("GroupID");
487
488 // create the metadata block object
489 METSDescriptive descriptive = new METSDescriptive(ID, name);
490
491 // get its metadata reference to retrieve namespaces
492 int metadataRef = resultSet.getInt("MetadataRef");
493
494 // query the database for matching namespaces for this metadata block
495 GS3SQLSelect select = new GS3SQLSelect("namespaces");
496 select.addField("*");
497 GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(metadataRef),
498 GS3SQLField.INTEGER_TYPE);
499 GS3SQLWhere where = new GS3SQLWhere(whereItem);
500 select.setWhere(where);
501
502 connection.execute(select.toString());
503
504 // parse through the namespaces, calling the namespace class to create instances
505 // as it will
506 ResultSet namespaceSet = connection.getResultSet();
507 if (namespaceSet != null && namespaceSet.first()) {
508 do {
509 METSNamespace namespace = METSNamespace.readSQL(connection, namespaceSet);
510 if (namespace != null) {
511 descriptive.addNamespace(namespace);
512 }
513 else {
514 System.out.println("Null namespace output");
515 }
516 }
517 while (namespaceSet.next());
518 }
519
520 return descriptive;
521 }
522 catch (SQLException sqlEx)
523 { System.out.println(sqlEx);
524 System.exit(1);
525 }
526 return null;
527 }
528}
Note: See TracBrowser for help on using the repository browser.