source: trunk/gli/src/org/greenstone/gatherer/gems/MSMUtils.java@ 8971

Last change on this file since 8971 was 8971, checked in by mdewsnip, 19 years ago

More GEMS fixes, by Matthew Whyte. Can now create subelements of subelements.

  • Property svn:keywords set to Author Date Id Revision
File size: 51.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.gems;
28
29/**************************************************************************************
30 * Title: Gatherer
31 * Description: The Gatherer: a tool for gathering and enriching a digital collection.
32 * Company: The University of Waikato
33 * Written: / /01
34 * Revised: 16/08/02 Improved
35 * 06/08/03 Bug fixes
36 * @author John Thompson, Greenstone Digital Libraries
37 * @version 2.3
38 **************************************************************************************/
39import java.io.*;
40import java.util.*;
41import org.greenstone.gatherer.Configuration;
42import org.greenstone.gatherer.cdm.CommandTokenizer;
43import org.greenstone.gatherer.util.ArrayTools;
44import org.greenstone.gatherer.util.StaticStrings;
45import org.greenstone.gatherer.util.Utility;
46import org.greenstone.gatherer.util.XMLTools;
47import org.w3c.dom.*;
48/** This class contains a plethora of methods associated with handling the content of <strong>MetadataSet</strong>s and the <strong>Element</strong>s within. For example this is where you will find methods for comparing various parts of two <strong>MetadataSet</strong>s for equality. It also has methods for extracting common and useful data from <strong>Element</strong>s such as the AssignedValue nodes.
49 * @author John Thompson, Greenstone Digital Libraries
50 * @version 2.3
51 */
52public class MSMUtils {
53 /** Used to order metadata according to set standard element order then alphabetically by value. */
54 // static private MetadataComparator METADATA_COMPARATOR = new MetadataComparator();
55 /** An element of the enumeration of type filter. */
56 static public int NONE = 0;
57 /** An element of the enumeration of type filter. */
58 static public int VALUES = 1;
59 /** An element of the enumeration of type filter. */
60 static public int ALIASES = 2;
61 /** An element of the enumeration of type filter. */
62 static public int BOTH = 3;
63 /** The character used to separate name space from metadata element. */
64 static public char NS_SEP= '.';
65 /** The character used to separate subfields from metadata element. */
66 static public String SF_SEP= "^";
67 /** Method to add one node as a child of another, after migrating into the target document.
68 * @param parent The <strong>Node</strong> we are inserting into.
69 * @param child The original <strong>Node</strong> we are inserting. Must first be cloned into the parents document.
70 */
71 static public void add(Node parent, Node child) {
72 Document document = parent.getOwnerDocument();
73 Node new_child = document.importNode(child, true);
74 parent.appendChild(new_child);
75 }
76
77 /** Method to add an attribute element to the given element. This method makes use of the language_dependant attribute of the document to not only determine if the attribute is language dependant, but also to see whether a Language element should be created if doesn't already exist.
78 * @param element_element the Element to add the attribute element to
79 * @param attribute_name_str the name of the new attribute to add as a String
80 * @param language_code_str the two letter code String of the language this attribute is to be added as
81 * @param value_str the String to be assigned as the attribute elements value
82 * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependant
83 * @see org.greenstone.gatherer.msm.MSMUtils#setValue(Element, String)
84 * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
85 * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
86 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
87 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
88 * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
89 */
90 static public void addElementAttribute(Element element_element, String attribute_name_str, String language_code_str, String value_str) {
91 Document document = element_element.getOwnerDocument();
92 // Create the basic new attribute (everything except language attribute)
93 Element attribute_element = document.createElement(StaticStrings.ATTRIBUTE_ELEMENT);
94 attribute_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, attribute_name_str);
95 MSMUtils.setValue(attribute_element, value_str);
96
97 // Start off by determining if we have to add this node in the new multilingual optimized way
98 if(isAttributeLanguageDependant(document, attribute_name_str)) {
99 boolean found = false;
100 // Try to retrieve a language element for the given language code
101 //NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
102 ArrayList language_elements = XMLTools.getChildElementsByTagName(element_element, StaticStrings.LANGUAGE_ELEMENT);
103 for(int i = 0; i < language_elements.size(); i++) {
104 Element language_element = (Element) language_elements.get(i);
105 if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equals(language_code_str)) {
106 found = true;
107 // Add attribute
108 language_element.appendChild(attribute_element);
109 }
110 language_element = null;
111 }
112 language_elements = null;
113 // If it still hasn't been found, then add it
114 if(!found) {
115 Element language_element = document.createElement(StaticStrings.LANGUAGE_ELEMENT);
116 language_element.setAttribute(StaticStrings.CODE_ATTRIBUTE, language_code_str);
117 element_element.appendChild(language_element);
118 // Add attribute
119 language_element.appendChild(attribute_element);
120 language_element = null;
121 }
122 }
123 // Just add the attribute the old fashioned way
124 else {
125 attribute_element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, language_code_str);
126 element_element.appendChild(attribute_element);
127 }
128 // Clean up
129 attribute_element = null;
130 document = null;
131 }
132
133
134 /** A method for comparing two AssignedValues trees. This compares not only the Subject hierarchies but also the values themselves.
135 * @param avt A <strong>Node</strong> which is the root of an AssignedValues tree.
136 * @param bvt The <strong>Node</strong> which is the root of the tree we wish to compare it to.
137 * @return <i>true</i> if the two trees are equal, <i>false</i> otherwise.
138 */
139 static final private boolean assignedValuesEqual(Node avt, Node bvt) {
140 if(avt == null && bvt == null) {
141 return true; // Both are null so both are equal.
142 }
143 else if(avt == null || bvt == null) {
144 // One is null and the other isn't.
145 return false;
146 }
147 else {
148 Hashtable a_map = new Hashtable();
149 getValueMappings(avt, null, a_map);
150 Hashtable b_map = new Hashtable();
151 getValueMappings(bvt, null, b_map);
152 if(a_map.size() == b_map.size()) {
153 /** @TODO - Figure out what to do now. */
154 return true;
155 }
156 }
157 return false;
158 }
159 /** A method for comparing two attribute nodes of type Node not Attr as you might think. Attr objects are used to describe the attributes of tags themselves, while in a metadata set we intend attribute nodes to describe qualities of metadata elements. It's just confusing because the two systems (DOM model and Dublin Core) are quite similar.
160 * @param an A <strong>Node</strong> representing some attribute of an element.
161 * @param bn The <strong>Node</strong> we wish to compare it to.
162 * @return <i>true</i> if and only if the attributes are equal.
163 */
164 static final public boolean attributesEqual(Node an, Node bn) {
165 // Check we are comparing apples and apples...
166 if(an.getNodeName().equals("Attribute") && bn.getNodeName().equals("Attribute")) {
167 Element ae = (Element) an;
168 Element be = (Element) bn;
169 // Ensure we are comparing the same type of attribute.
170 if(ae.getAttribute("name").equals(be.getAttribute("name"))) {
171 // And finally retrieve and compare the values.
172 if(getValue(ae).equals(getValue(be))) {
173 // We have a match.
174 return true;
175 }
176 }
177 }
178 // And if anything goes wrong we can't be dealing with equal attributes.
179 return false;
180 }
181
182 /** Remove all of the child nodes from a certain node. */
183 static final public void clear(Node parent) {
184 while(parent.hasChildNodes()) {
185 parent.removeChild(parent.getFirstChild());
186 }
187 }
188
189 /** Method to compare two metadata elements (of type Element, which is bound to get more than a bit confusing) for equality. This test may only check the structural (ie pretty much unchanging) consistancy, or may include the AssignedValue tree as well (which will be different for each collection I'd imagine).
190 * @param a_set The <strong>MetadataSet</strong> a comes from.
191 * @param ae An <strong>Element</strong>.
192 * @param b_set The <strong>MetadataSet</strong> b comes from.
193 * @param be The <strong>Element</strong> to compare it to.
194 * @param values <i>true</i> if the AssignedValues tree should also be compared, <i>false</i> otherwise.
195 * @return <i>true</i> if the elements are equal, <i>false</i> otherwise.
196 */
197 static final public boolean elementsEqual(MetadataSet a_set, Element ae, MetadataSet b_set, Element be, boolean values) {
198 // Compare Element Attr(ibutes) within the DOM, not to be confused with comparing element attributes in a Dublin Core sense...
199 NamedNodeMap aas = ae.getAttributes();
200 NamedNodeMap bas = be.getAttributes();
201 // For each attribute in a...
202 for(int i = 0; i < aas.getLength(); i++) {
203 Attr aa = (Attr)aas.item(i);
204 // Try to retrieve an attribute of the same name from b.
205 Attr ba = (Attr)bas.getNamedItem(aa.getNodeName());
206 // Now if there was no such attribute, or if the values for the
207 // two attributes are different the structures different.
208 if(ba == null || (!aa.getValue().equals(ba.getValue()))) {
209 //ystem.err.println("Attributes are not equal");
210 return false;
211 }
212 }
213 // Quickest test of children is to see we have the same number in
214 // each. Remember to modify for missing AssignedValues which have
215 // nothing to do with structure.
216 int anc = getAttributeCount(ae);
217 int bnc = getAttributeCount(be);
218 if(anc != bnc) {
219 return false;
220 }
221 // Now we compare the child nodes of the two Elements taking into
222 // account three special cases...
223 // 1. We don't test the AssignedValues element here.
224 // 2. Remember OptionList node.
225 // 3. The Attributes of each metadata element.
226 // For each child node of a.
227 for(Node an = ae.getFirstChild(); an !=null; an =an.getNextSibling()) {
228 if(an.getNodeName().equals("OptionList")) {
229 //ystem.err.println("Matching OptionLists.");
230 Node bn = getNodeFromNamed(be, "OptionList");
231 if(bn == null || !optionListsEqual(an, bn)) {
232 //ystem.err.println("OptionLists are not equal");
233 return false;
234 }
235 }
236 // Matching attributes.
237 else if(an.getNodeName().equals("Attribute")) {
238 //ystem.err.println("Matching Attributes.");
239 boolean matched = false;
240 for(Node bn = be.getFirstChild(); bn != null && !matched;
241 bn = bn.getNextSibling()) {
242 if(bn.getNodeName().equals("Attribute")) {
243 matched = attributesEqual(an, bn);
244 }
245 }
246 if(!matched) {
247 //ystem.err.println("Cannot match attribute.");
248 return false;
249 }
250 }
251 }
252 // Finally, if we've been asked to compares value trees (for some unknown reason) go ahead and compare them too.
253 if(values) {
254 GValueModel avt = a_set.getValueTree(new ElementWrapper(ae));
255 GValueModel bvt = b_set.getValueTree(new ElementWrapper(be));
256 return assignedValuesEqual(avt.getDocument().getDocumentElement(), bvt.getDocument().getDocumentElement());
257 }
258 // If we've got this far the elements match!
259 return true;
260 }
261 /** This method extracts the assigned value trees details, if any, from a certain element and stores them in an array ready to be passed as arguments to the Dictionary.
262 * @param element The <strong>Element</strong> whose values we wish to view.
263 * @return A <strong>String[]</strong> containing the details of the assigned values tree.
264 * @see org.greenstone.gatherer.Dictionary
265 */
266 static final public String[] getAssignedValuesDetails(MetadataSet mds, Element element) {
267 String details[] = null;
268 //Node avt = getNodeFromNamed(element, "AssignedValues");
269 GValueModel avt = mds.getValueTree(new ElementWrapper(element));
270 if(avt != null) {
271 Hashtable mapping = new Hashtable();
272 getValueMappings(avt.getDocument().getDocumentElement(), null, mapping);
273 ArrayList values = new ArrayList(mapping.keySet());
274 Collections.sort(values);
275 details = new String[1];
276 for(int i = 0; i < values.size(); i++) {
277 if(details[0] == null) {
278 details[0] = " " + values.get(i);
279 }
280 else {
281 details[0] = details[0] + "\n " + values.get(i);
282 }
283 }
284 mapping = null;
285 values = null;
286 }
287 avt = null;
288 return details;
289 }
290
291 /** Retrieve all of the attributes for the given element as a tree set. Note that this requires significant manipulation if the source is a multilingual optimized metadata set.
292 * @param element the Element whose attributes we wish to catalog
293 * @return a TreeSet of the attributes sorted by their natural ordering
294 * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
295 * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
296 * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
297 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
298 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
299 * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
300 */
301 static public TreeSet getAttributes(Element element) {
302 TreeSet attribute_tree = new TreeSet();
303
304 // GemsLanguageManager gemsLangManager = new GemsLanguageManager("/home/arosmain/gsdl/gli/classes/xml/languages.xml");
305 GEMSLanguageManager gemsLangManager = new GEMSLanguageManager(Configuration.gsdl_path + "/gli/classes/xml/languages.xml");
306
307 String[] enabled_langs = gemsLangManager.getEnabledLanguageCodesToArray();
308
309 for(Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
310 if(node instanceof Element) {
311 Element some_element = (Element) node;
312 String some_element_name = some_element.getNodeName();
313 if(some_element_name.equals(StaticStrings.ATTRIBUTE_ELEMENT)) {
314 attribute_tree.add(new Attribute(some_element.getAttribute(StaticStrings.NAME_ATTRIBUTE), some_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE), MSMUtils.getValue(some_element)));
315 // System.out.println(some_element_name + "<- some_element nodes' value");
316 }
317 else if(some_element_name.equals(StaticStrings.LANGUAGE_ELEMENT)) {
318 ///Added by Attila on Nov 05 04
319 //System.out.println(some_element_name + "<- some_element nodes' value"); //debug
320
321 String language_code = some_element.getAttribute(StaticStrings.CODE_ATTRIBUTE);
322 NodeList attribute_elements = some_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
323
324 for(int i = 0; i < attribute_elements.getLength(); i++) {
325 Element attribute_element = (Element) attribute_elements.item(i);
326
327 for(int k = 0; k < enabled_langs.length; k++){
328
329 if(enabled_langs[k].trim().compareTo(some_element.getAttributes().item(0).getNodeValue().toString()) == 0){
330
331 attribute_tree.add(new Attribute(attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE), language_code, MSMUtils.getValue(attribute_element)));
332 attribute_element = null;
333
334 break;
335 }
336 //else {
337 // System.out.println(enabled_langs[k].trim().toString() + some_element.getAttributes().item(0).getNodeValue().toString());
338 // }
339
340 }
341 // enabled_languages_split[k].toLowerCase().trim();
342
343
344 // if(match_exit_flag == false)
345 // break;
346 //add language specific attr's:
347 //attribute_tree.add(new Attribute(attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE), language_code, MSMUtils.getValue(attribute_element)));
348 attribute_element = null;
349 }
350 attribute_elements = null;
351 language_code = null;
352 }
353 some_element_name = null;
354 some_element = null;
355 }
356 }
357 return attribute_tree;
358 }
359
360 /** Method to count the number of Attribute nodes under a certain Element. This ignores other nodes such as #text, OptionList and AssignedValues nodes.
361 * @param element The <strong>Element</strong> whose attributes you want to count.
362 * @return An <i>int</i> which is the number of attribute nodes.
363 */
364 static final private int getAttributeCount(Node element) {
365 int count = 0;
366 for(Node n = element.getFirstChild(); n != null;
367 n = n.getNextSibling()) {
368 if(n.getNodeName().equals("Attribute")) {
369 count++;
370 }
371 }
372 return count;
373 }
374
375 /** This method is a slight variation on getNodeNamed in that it is especially written to retrieve the attribute Nodes of a certain name present under the given element.
376 * @param element The target element <strong>Node</strong>.
377 * @param name The name of the attribute you wish to return.
378 * @return An <strong>Element[]</strong> containing the attributes you requested, or <i>null</i> if no such attributes exists.
379 */
380 static final public Element[] getAttributeNodesNamed(Node element, String name) {
381 Element attributes[] = null;
382 for(Node n = element.getFirstChild(); n != null; n = n.getNextSibling()) {
383 if(n.getNodeName().equals("Attribute")) {
384 Element e = (Element)n;
385 if(e.getAttribute("name").equals(name)) {
386 if(attributes == null) {
387 attributes = new Element[1];
388 attributes[0] = e;
389 }
390 else {
391 Element temp[] = attributes;
392 attributes = new Element[temp.length + 1];
393 System.arraycopy(temp, 0, attributes, 0, temp.length);
394 attributes[temp.length] = e;
395 temp = null;
396 }
397 }
398 e = null;
399 }
400 }
401 return attributes;
402 }
403
404 /** Method to construct an elements description by retrieving the correct attribute.
405 * @param element the Element whose name we wish to retrieve
406 * @return a String which is the elements description, or an empty string if no description exists
407 * @see org.greenstone.gatherer.msm.MSMUtils#getElementAttribute
408 * @see org.greenstone.gatherer.util.StaticStrings#COMMENT_VALUE
409 * @see org.greenstone.gatherer.util.StaticStrings#DEFINITION_VALUE
410 * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
411 * @see org.greenstone.gatherer.util.StaticStrings#SPACE_CHARACTER
412 */
413 static public String getDescription(Element element) {
414 String language_code_str = Configuration.getLanguage();
415 StringBuffer description = new StringBuffer(StaticStrings.EMPTY_STR);
416 description.append(getElementAttribute(element, StaticStrings.DEFINITION_VALUE, language_code_str));
417 if(description.length() > 0) {
418 description.append(StaticStrings.SPACE_CHARACTER);
419 }
420 description.append(getElementAttribute(element, StaticStrings.COMMENT_VALUE, language_code_str));
421 language_code_str = null;
422 return description.toString();
423 }
424
425 /** Retrieve the value for the requested attribute in the required language. Once again this method must be aware of the differences between the old metadata sets and the new multilingual optimized ones.
426 * @param element_element the Element whose attributes we are searching through
427 * @param attribute_name_str the name of the desired attribute as a String
428 * @param language_code_str the two letter code String indicating the desired language
429 * @see org.greenstone.gatherer.msm.MSMUtils#getValue
430 * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependant
431 * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
432 * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
433 * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
434 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
435 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
436 * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
437 */
438 static private String getElementAttribute(Element element_element, String attribute_name_str, String language_code_str) {
439 boolean found = false;
440 String result = StaticStrings.EMPTY_STR;
441 Document document = element_element.getOwnerDocument();
442 // Determine if the attribute is language specific
443 if(isAttributeLanguageDependant(document, attribute_name_str)) {
444 NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
445 for(int i = 0; !found && i < language_elements.getLength(); i++) {
446 Element language_element = (Element) language_elements.item(i);
447 if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equals(language_code_str)) {
448 NodeList attribute_elements = language_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
449 for(int j = 0; !found && j < attribute_elements.getLength(); j++) {
450 Element attribute_element = (Element) attribute_elements.item(j);
451 if(attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(attribute_name_str)) {
452 found = true;
453 result = MSMUtils.getValue(attribute_element);
454 }
455 attribute_element = null;
456 }
457 attribute_elements = null;
458 }
459 language_element = null;
460 }
461 language_elements = null;
462 }
463 else {
464 boolean first_match = false;
465 NodeList attribute_elements = element_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
466 for(int k = 0; !found && k < attribute_elements.getLength(); k++) {
467 Element attribute_element = (Element) attribute_elements.item(k);
468 // We don't want to consider those attributes found inside language elements
469 if(attribute_element.getParentNode() == element_element) {
470 ///ystem.err.println("First level");
471 String target_name_str = attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
472 String target_language_str = attribute_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE);
473 ///ystem.err.println("Does " + target_name_str + " equal " + attribute_name_str + "?");
474 if(attribute_name_str.equals(target_name_str)) {
475 ///ystem.err.println("Does " + target_language_str + " equal " + language_code_str + "?");
476 if(language_code_str.equals(target_language_str)) {
477 ///ystem.err.println("Perfect match!");
478 found = true;
479 result = MSMUtils.getValue(attribute_element);
480 }
481 else if((result == StaticStrings.EMPTY_STR || first_match) && isLegacyMDS(document)) {
482 ///ystem.err.println("Legacy MDS");
483 // Special case for old style documents, where the english match is good enough
484 if(target_language_str.equals(StaticStrings.ENGLISH_LANGUAGE_STR)) {
485 ///ystem.err.println("English plate.");
486 result = MSMUtils.getValue(attribute_element);
487 }
488 // Super special case where the first match is better than nothing
489 else if(result == StaticStrings.EMPTY_STR && !first_match) {
490 ///ystem.err.println("First match.");
491 first_match = true;
492 result = MSMUtils.getValue(attribute_element);
493 }
494 }
495 }
496 target_language_str = null;
497 target_name_str = null;
498 }
499 //else {
500 ///ystem.err.println("Second level");
501 //}
502 attribute_element = null;
503 }
504 attribute_elements = null;
505
506 }
507 document = null;
508 return result;
509 }
510
511 /*************************************************************************/
512 /** Method to construct an elements fully qualified name. Note that this is different from a nodes identifier. Think of name as a short, unique reference to a metadata element, whereas identifier can be much longer, language specific and non-unique.
513 * @param element An <strong>Element</strong> whose name we are interested in.
514 * @return A <strong>String</strong> representing this given elements fully namespace qualified name.
515 */
516 static final public String getFullName(Element element) {
517 return getFullName(element, "");
518
519 }
520 /*************************************************************************/
521 /** Method to construct an elements fully qualified name. Note that this is different from a nodes identifier. Think of name as a short, unique reference to a metadata element, whereas identifier can be much longer, language specific and non-unique.
522 * @param element An <strong>Element</strong> whose name we are interested in.
523 * @return A <strong>String</strong> representing this given elements fully namespace qualified name.
524 */
525 static final public String getFullName(Element element, String namespace) {
526 StringBuffer name_buffer = new StringBuffer();
527 if(element == null) {
528 return "Error";
529 }
530 // First get the root node.
531 Document document = element.getOwnerDocument();
532 Element root = document.getDocumentElement();
533 document = null;
534 // Retrieve this elements name
535 name_buffer.append(element.getAttribute("name"));
536
537 // Now we check if element has a parent node, other than root. If so we begin building up the full name
538 //For some reason this doesn't work in specific cases of subelements.
539 Element parent_element = (Element) element.getParentNode();
540 while(parent_element != null && parent_element != root) {
541 name_buffer.insert(0, SF_SEP);
542 name_buffer.insert(0, parent_element.getAttribute("name"));
543 parent_element = (Element)parent_element.getParentNode();
544 }
545 parent_element = null;
546 // Finally insert the namespace and we are all done.
547 if(root != null) {
548 namespace = root.getAttribute("namespace");
549 }
550 root = null;
551 // If no root, or no namespace found, assume its extracted (at least then they can't edit it)
552 if(namespace == null || namespace.equals("")) {
553 namespace = Utility.EXTRACTED_METADATA_NAMESPACE;
554 }
555 name_buffer.insert(0, NS_SEP);
556 name_buffer.insert(0, namespace);
557 namespace = null;
558 return name_buffer.toString();
559 } // static public String getFullName(Element element)
560
561 /**
562 Method to get an element's name, not including its namespace.
563 @param element an <strong>Element</strong> whose name we are interested in.
564 @return A <strong>Strong</strong> representing the given elements name
565 @author Matthew Whyte
566 @date last modified: 21/01/04
567 */
568 static final public String getNameOnly(Element element)
569 {
570 StringBuffer name_buffer = new StringBuffer();
571 if(element == null) {
572 return "Error";
573 }
574 // Retrieve this elements name
575 name_buffer.append(element.getAttribute("name"));
576
577 return name_buffer.toString();
578 }
579
580
581 /** Method to construct an elements name (sic identifier) by retrieving the correct attribute, language specific.
582 * @param element the Element whose name we wish to retrieve
583 * @return a String which is the elements identifier, or an empty string if no identifier exists
584 * @see org.greenstone.gatherer.msm.MSMUtils#getElementAttribute
585 * @see org.greenstone.gatherer.util.StaticStrings#IDENTIFIER_VALUE
586 * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
587 */
588 static final public String getIdentifier(Element element) {
589 String identifier = getElementAttribute(element, StaticStrings.IDENTIFIER_VALUE, Configuration.getLanguage());
590 // Failing the above we return the nodes name instead.
591 if(identifier == null || identifier.length() == 0) {
592 identifier = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
593 }
594
595 return identifier;
596 }
597
598
599
600 /** Method to retrieve from the node given, a certain child node with the specified name.
601 * @param parent The <strong>Node</strong> whose children should be searched.
602 * @param name The required nodes name as a <strong>String</strong>.
603 * @return The requested <strong>Node</strong> if it is found, <i>null</i> otherwise.
604 */
605 static final public Node getNodeFromNamed(Node parent, String name) {
606 Node child = null;
607 for(Node i = parent.getFirstChild(); i != null && child == null;
608 i = i.getNextSibling()) {
609 if(i.getNodeName().equals(name)) {
610 child = i;
611 }
612 }
613 return child;
614 }
615 /** Look for the occurances 'field' of the element and return it if found.
616 * @return An <i>int</i> which matches the number in the occurances attribute of the element, or 0 if no such attribute.
617 */
618 static final public int getOccurances(Element element) {
619 int count = 0;
620 String number = null;
621 if((number = element.getAttribute("occurances")) != null) {
622 try {
623 count = Integer.parseInt(number);
624 }
625 catch(Exception error) {
626 count = 0;
627 }
628 }
629 return count;
630 }
631 /** This method extracts the option list details, if any, from a certain element and stores them in an array ready to be passed as arguments to the <strong>Dictionary</strong>.
632 * @param element The <strong>Element</strong> whose option list we wish to view.
633 * @return A <strong>String[]</strong> containing the details of the option list.
634 * TODO implement.
635 * @see org.greenstone.gatherer.Dictionary
636 */
637 static final public String[] getOptionListDetails(Element element) {
638 return null;
639 }
640
641
642 /** This method extracts the structural details from a certain element and stores them in an array, all ready for passing to the <strong>Dictionary</strong>.
643 * @param element The <Strong>Element</strong> whose details we wish to gather.
644 * @return A <strong>String[]</strong> containing the structural details.
645 */
646 static final public String[] getStructuralDetails(MetadataSet mds, Element element) {
647 String details[] = new String[4];
648 //Element root = (Element)element.getParentNode();
649 //details[0] = root.getAttribute("name");
650 //details[1] = root.getAttribute("namespace");
651 details[0] = mds.getName();
652 details[1] = mds.getNamespace();
653 details[2] = getFullName(element);
654 details[3] = null;
655 // Get attributes
656 Vector attributes = new Vector();
657 for(Node n=element.getFirstChild(); n!=null; n=n.getNextSibling()) {
658 if(n.getNodeName().equals("Attribute")) {
659 Element temp = (Element)n;
660 attributes.add(temp.getAttribute("name") + "=" + getValue(n));
661 }
662 }
663 // Sort attributes
664 Collections.sort(attributes);
665 // Add attributes to details.
666 for(int i = 0; i < attributes.size(); i++) {
667 if(details[3] == null) {
668 details[3] = " " + attributes.get(i);
669 }
670 else {
671 details[3] = details[3] + "\n " + attributes.get(i);
672 }
673 }
674 return details;
675 }
676
677 /** Method to retrieve the value of a given node (not the assigned values tree!).
678 * @param element The <strong>Element</strong> whose value we wish to find.
679 * @return The value found as a <strong>String</strong>, or <i>null</i> if this element has no value.
680 */
681 static final public String getValue(Node element) {
682 // If we've been given a subject node first retrieve its value node.
683 if(element.getNodeName().equals("Subject")) {
684 element = getNodeFromNamed(element, "Value");
685 }
686 // If we've got a value node, then reconstruct the text. Remember that DOM will split text over 256 characters into several text nodes
687 if(element != null && element.hasChildNodes()) {
688 StringBuffer text_buffer = new StringBuffer();
689 NodeList text_nodes = element.getChildNodes();
690 for(int i = 0; i < text_nodes.getLength(); i++) {
691 Node possible_text = text_nodes.item(i);
692 if(possible_text.getNodeName().equals(StaticStrings.TEXT_NODE)) {
693 text_buffer.append(possible_text.getNodeValue());
694 }
695 }
696 return text_buffer.toString();
697 }
698 return "";
699 }
700
701 /** Method to traverse the given value tree, and build up a hashtable of mappings between the value path key names and the Subject nodes of the tree.
702 * @param current The root <strong>Node</strong> of a subtree of the AssignedValues tree.
703 * @param prefix The value path key <strong>String</string>, which shows the path from the root of the AssignedValue tree to <i>current</i>s parent using '\' as a separator.
704 * @param values A <strong>Hashtable</strong> containing the mapping discovered so far in our tree traversal.
705 */
706 static final private void getValueMappings(Node current, String prefix, Hashtable values) {
707 if(current != null) {
708 String name = current.getNodeName();
709 String new_prefix = prefix;
710 // If we've found the outer layer of a new value, add it to our mapping
711 if(name.equals("Subject")) {
712 Node value_node = getNodeFromNamed(current, "Value");
713 String value = getValue(value_node);
714 if(new_prefix != null) {
715 new_prefix = new_prefix + "\\" + value;
716 }
717 else {
718 new_prefix = value;
719 }
720 values.put(new_prefix, current);
721 }
722 if(name.equals("Subject") || name.equals("AssignedValues")) {
723 for(Node child = current.getFirstChild(); child != null;
724 child = child.getNextSibling()) {
725 getValueMappings(child, new_prefix, values);
726 }
727 }
728 }
729 }
730 /** Parses the value tree template file.
731 * @return The Document parsed.
732 */
733 static final public Document getValueTreeTemplate() {
734 return Utility.parse(GEMS.METADATA_VALUE_TEMPLATE, true);
735 }
736
737 /** Determine if the named attribute is language specific for this collection. This information is found in a DOM attribute of the document element, as a comma separated list of attribute names.
738 * @param document the Document for which we wish to check the language requirements
739 * @param attribute_name_str the name of the attribute we a testing as a String
740 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGEDEPENDANT_ATTRIBUTE
741 * Modified by Matthew Whyte 4/02/05
742 */
743 static private boolean isAttributeLanguageDependant(Document document, String attribute_name_str)
744 {
745 //gives a list of comma seperated language specific attributes.
746 String language_specific_attributes = document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDANT_ATTRIBUTE).toLowerCase();
747 //System.err.println("lang_specific: " + language_specific_attributes); //debug
748
749 //Seperate out language_specific_attributes
750 String[] attributes_split = language_specific_attributes.split(",");
751
752 //Compare each to attribute_name_str
753 for(int i = 0; i < attributes_split.length; i++)
754 {
755 if(attributes_split[i].trim().compareTo(attribute_name_str.toLowerCase()) == 0)
756 return true;
757 }
758 return false;
759 }
760
761 /** Determine if the given document is a legacy MDS or a new multilingual one. The easiest way to tell is whether there is a language_dependant attribute in the document element.
762 * @param document the Document to test
763 * @return true if this is an old mds, false otherwise
764 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGEDEPENDANT_ATTRIBUTE
765 * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
766 */
767 static private boolean isLegacyMDS(Document document) {
768 ///ystem.err.println("isLegacyMDS(): l_d = " + document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDANT_ATTRIBUTE));
769 return (document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDANT_ATTRIBUTE)).equals(StaticStrings.EMPTY_STR);
770 }
771
772 /** Method to compare two OptionsLists for equality.
773 * @param al A <strong>Node</strong> which represents an OptionList.
774 * @param bl The <strong>Node</strong> we wish to test against.
775 * @return A <i>boolean</i> which is <i>true</i> if the two option lists are equal, <i>false</i> otherwise.
776 * TODO Implementation
777 */
778 static final private boolean optionListsEqual(Node al, Node bl) {
779 // Compare the 'restricted' attribute of the two lists.
780 Element ae = (Element) al;
781 Element be = (Element) bl;
782 if(!ae.getAttribute("restricted").equals
783 (be.getAttribute("restricted"))) {
784 return false;
785 }
786 // Compare the Values under each list.
787 for(Node an = al.getFirstChild(); an != null;
788 an = an.getNextSibling()){
789 if(an.getNodeName().equals("Value")) {
790 boolean matched = false;
791 for(Node bn = bl.getFirstChild(); bn != null && !matched;
792 bn = bn.getNextSibling()) {
793 if(bn.getNodeName().equals("Value")) {
794 matched = valuesEqual(an, bn);
795 }
796 }
797 if(!matched) {
798 return false;
799 }
800 }
801 }
802 return true;
803 }
804
805 /** A method to remove a specific attribute element from an element. This attribute must match in name, language and in value before being removed. Note that this method supports both legacy and multilingual optimized versions of the mds.
806 * @param element_element the Element which represent the metadata element we are altering
807 * @param attribute_name_str the name of the attribute to remove as a String
808 * @param language_code_str the language code we must match as a String
809 * @param value_str the value String which also must match before we remove anything
810 * @return true if the desired attribute was successfully found and removed, false otherwise
811 * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependant
812 * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
813 * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
814 * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
815 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
816 * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
817 * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
818 */
819 static public boolean removeElementAttribute(Element element_element, String attribute_name_str, String language_code_str, String value_str) {
820 //Determine the if this is one of the language specific attributes.
821 //This can sometimes give a false result, if an attribute is made language specific half way through creation of a metadata set (or vice versa).
822 if(isAttributeLanguageDependant(element_element.getOwnerDocument(), attribute_name_str))
823 {
824 /*
825 Multilingual Optimized version, eg:
826 <Language code="en">
827 <Attribute name="identifier">second</Attribute>
828 </Language>
829 */
830 return removeElementAttributeNew(element_element, attribute_name_str, language_code_str, value_str, false);
831 }
832 else
833 {
834 /*
835 The old way, eg:
836 <Attribute language="en" name="identifier">second</Attribute>
837 */
838 return removeElementAttributeOld(element_element, attribute_name_str, language_code_str, value_str, false);
839 }
840
841 }
842 static final private boolean removeElementAttributeNew(Element element_element, String attribute_name_str, String language_code_str, String value_str, boolean run_once)
843 {
844 // Retrieve the language elements, and determine the correct one
845 NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
846 for(int i = 0; i < language_elements.getLength(); i++) {
847 Element language_element = (Element) language_elements.item(i);
848 if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equalsIgnoreCase(language_code_str)) {
849 NodeList attribute_elements = language_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
850 for(int j = 0; j < attribute_elements.getLength(); j++) {
851 Element attribute_element = (Element) attribute_elements.item(j);
852 String target_name_str = attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
853 String target_value_str = MSMUtils.getValue(attribute_element);
854 if(attribute_name_str.equals(target_name_str) && value_str.equals(target_value_str)) {
855 language_element.removeChild(attribute_element);
856 if(attribute_elements.getLength() == 0) {
857 element_element.removeChild(language_element);
858 }
859 target_value_str = null;
860 target_name_str = null;
861 attribute_element = null;
862 attribute_elements = null;
863 language_element = null;
864 language_elements = null;
865 return true;
866 }
867 target_value_str = null;
868 target_name_str = null;
869 attribute_element = null;
870 }
871 attribute_elements = null;
872 }
873 language_element = null;
874 }
875 language_elements = null;
876 // Not found. Try the old way before failing.
877 if(!run_once)
878 return removeElementAttributeOld(element_element, attribute_name_str, language_code_str, value_str, true);
879 return false;
880 }
881 static final private boolean removeElementAttributeOld(Element element_element, String attribute_name_str, String language_code_str, String value_str, boolean run_once)
882 {
883 // Find the attribute to remove
884 NodeList attribute_elements = element_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
885 for (int k = 0; k < attribute_elements.getLength(); k++) {
886 Element attribute_element = (Element) attribute_elements.item(k);
887 // Remember to ignore any attributes that live within nested language elements
888 if (attribute_element.getParentNode() == element_element && attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(attribute_name_str) && attribute_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE).equalsIgnoreCase(language_code_str) && MSMUtils.getValue(attribute_element).equals(value_str)) {
889 // Match found, so remove the attribute node and return
890 element_element.removeChild(attribute_element);
891 attribute_element = null;
892 attribute_elements = null;
893 return true;
894 }
895 attribute_element = null;
896 }
897 attribute_elements = null;
898 // No match found. Try the new way before failing.
899 if(!run_once)
900 return removeElementAttributeNew(element_element, attribute_name_str, language_code_str, value_str, true);
901 return false;
902 }
903
904 /** can only be used to set the english value */
905 static final public void setIdentifier(Node element, String value) {
906 // Get the 'identifier' Element
907 for(Node node = element.getFirstChild(); node != null;
908 node = node.getNextSibling()) {
909 if(node.getNodeName().equals("Attribute")) {
910 Element target = (Element)node;
911 if(target.getAttribute("name").equals("identifier") && target.getAttribute("language").equals("en")) {
912 Node text = target.getFirstChild();
913 text.setNodeValue(value);
914 break;
915 }
916 }
917 }
918 }
919 /** Set the value of the element attribute occurances.
920 * @param element The <strong>Element</strong> to change.
921 * @param value The value to change by as an <i>int</i>.
922 */
923 static final public void setOccurance(Element element, int value) {
924 Integer new_value = new Integer(getOccurances(element) + value);
925 element.setAttribute("occurances", new_value.toString());
926 }
927
928 /** Set the #text node value of some element.
929 * @param element the Element whose value we wish to set
930 * @param value the new value for the element as a String
931 */
932 static final public void setValue(Element element, String value) {
933 // Remove any existing child node(s)
934 clear(element);
935 // Add new text node.
936 if (value != null) {
937 element.appendChild(element.getOwnerDocument().createTextNode(value));
938 }
939 }
940
941 /** This method also traverses the tree, but this one is used to gather all the values and aliases at once, and to 'prune' the tree if necessary.
942 * @param current The current root <strong>Node</strong> of this AssignedValues tree subtree.
943 * @param return_filter This <i>int</i> specifies what nodes from the tree should be returned, where;<br>VALUES = return values only<br>ALIASES = return aliases only<br>BOTH = return both values and aliases<br>NONE = return nothing.
944 * @param remove_leaves A leaf node is a subject that contains no child subjects. If this <i>boolean</i> is set to <i>true</i> then the leaf nodes will be removed from the tree.
945 * @return A <strong>Node[]</strong> containing whatever values or aliases have been found during the trees traversal.
946 */
947 static final public Node[] traverseTree(Node current, int return_filter, boolean remove_leaves) {
948 Node leaves[] = null;
949 String name = current.getNodeName();
950 if(name.equals("Value") && (return_filter == VALUES || return_filter == BOTH)) {
951 leaves = ArrayTools.add(leaves, current);
952 }
953 else if(name.equals("Alias") && (return_filter == ALIASES || return_filter == BOTH)) {
954 leaves = ArrayTools.add(leaves, current);
955 }
956 else if(name.equals("Subject")) {
957 boolean has_subject_child = false;
958 Node children[] = ArrayTools.nodeListToNodeArray(current.getChildNodes());
959 for(int i = 0; i < children.length; i++) {
960 if(children[i].getNodeName().equals("Subject")) {
961 has_subject_child = true;
962 }
963 leaves = ArrayTools.add(leaves, traverseTree(children[i], return_filter, remove_leaves));
964 }
965 if(!has_subject_child && remove_leaves) {
966 Node parent = current.getParentNode();
967 parent.removeChild(current);
968 }
969 }
970 else if(name.equals("AssignedValues")) {
971 Node children[] = ArrayTools.nodeListToNodeArray(current.getChildNodes());
972 for(int i = 0; i < children.length; i++) {
973 leaves = ArrayTools.add(leaves, traverseTree(children[i], return_filter, remove_leaves));
974 }
975 }
976 return leaves;
977 }
978
979 /** This method is used to systematically merge two AssignedValues tree. Both trees have their current values mapped, then the new tree is searched for key paths that don't exist in the current tree. If such a key is found, the Subject <strong>Node</strong> it maps to is retrieved and then imported and added to whatever was the closest available node (in terms of tree path) in the current tree.
980 * @param a_set The MetadataSet from which the Element a came from.
981 * @param a The Element at the root of the current AssignedValues tree.
982 * @param b_set The MetadataSet from which the Element b came from.
983 * @param b The root Element of the tree that is being merged.
984 * @return A <i>boolean</i> which is <i>true</i> if the trees merged without error, <i>false</i> otherwise.
985 */
986 static final public boolean updateValueTree(MetadataSet a_set, Element a, MetadataSet b_set, Element b) {
987 GValueModel avt = a_set.getValueTree(new ElementWrapper(a));
988 GValueModel bvt = b_set.getValueTree(new ElementWrapper(b));
989 // If neither element even has a value tree, we're all done.
990 if(avt == null && bvt == null) {
991 avt = null;
992 bvt = null;
993 return true;
994 }
995 // If the new element has no value tree then nothing needs to be done.
996 else if(avt != null && bvt == null) {
997 avt = null;
998 bvt = null;
999 return true;
1000 }
1001 // If only the new element has a value tree, then add all of its values
1002 // immediately.
1003 else if(avt == null && bvt != null) {
1004 a_set.addValueTree(new ElementWrapper(a), bvt);
1005 avt = null;
1006 bvt = null;
1007 return true;
1008 }
1009 // We have both trees for both elements, time to merge.
1010 else {
1011 Document document = avt.getDocument();
1012 Hashtable a_map = new Hashtable();
1013 getValueMappings(document.getDocumentElement(), null, a_map);
1014 Hashtable b_map = new Hashtable();
1015 getValueMappings(bvt.getDocument().getDocumentElement(), null, b_map);
1016 // For each new entry in b_map
1017 for(Enumeration b_keys = b_map.keys(); b_keys.hasMoreElements(); ) {
1018 String b_key = (String)b_keys.nextElement();
1019 // Test if there is already an entry in a_map.
1020 if(!a_map.containsKey(b_key)) {
1021 // If not, search through a_map for the longest match.
1022 Node target = document.getDocumentElement();
1023 String last_match = null;
1024 for(Enumeration a_keys = a_map.keys();
1025 a_keys.hasMoreElements(); ) {
1026 String a_key = (String)a_keys.nextElement();
1027 if(b_key.startsWith(a_key)) {
1028 if(last_match == null || a_key.length() > last_match.length()) {
1029 last_match = a_key;
1030 target = (Node)a_map.get(a_key);
1031 }
1032 }
1033 a_key = null;
1034 }
1035 // Now import the node at b_key and add it to target.
1036 Node subtree = (Node)b_map.get(b_key);
1037 subtree = document.importNode(subtree, true);
1038 // Find the node to insert before...
1039 String name = getValue(subtree);
1040 Node move = null;
1041 for(Node n = target.getFirstChild(); n != null && move == null; n = n.getNextSibling()) {
1042 if(n.getNodeName().equals("Subject")) {
1043 if(name.compareTo(getValue(n)) <= 0) {
1044 move = n;
1045 }
1046 }
1047 }
1048 if(move == null) {
1049 target.appendChild(subtree);
1050 }
1051 else {
1052 target.insertBefore(subtree, move);
1053 }
1054 target = null;
1055 last_match = null;
1056 subtree = null;
1057 name = null;
1058 move = null;
1059 }
1060 b_key = null;
1061 }
1062 document = null;
1063 a_map = null;
1064 b_map = null;
1065 avt = null;
1066 bvt = null;
1067 return true;
1068 }
1069 }
1070
1071 /** Method to determine if two Value nodes are equal.
1072 * @param av A <strong>Node</strong> representing a value.
1073 * @param bv The <strong>Node</strong> we want to compare it to.
1074 * @return A <i>boolean</i> which is <i>true</i> if the two value nodes are equal, <i>false</i> otherwise.
1075 */
1076 static final private boolean valuesEqual(Node av, Node bv) {
1077 // Check we are comparing apples and apples...
1078 if(av.getNodeName().equals("Value") &&
1079 bv.getNodeName().equals("Value")) {
1080 // Retrieve and then compare their text values.
1081 Node at = av.getFirstChild();
1082 Node bt = bv.getFirstChild();
1083 if(at.getNodeValue().equals(bt.getNodeValue())) {
1084 return true;
1085 }
1086 }
1087 return false;
1088 }
1089
1090 /** A comparator for sorting metadata element-value pairs into their standard order (elements) then alphabetical order (values). */
1091// static final private class MetadataComparator
1092// implements Comparator {
1093// /** Compares its two arguments for order. */
1094// public int compare(Object o1, Object o2) {
1095// int result = 0;
1096// ElementWrapper e1 = null;
1097// ElementWrapper e2 = null;
1098// String v1 = null;
1099// String v2 = null;
1100// if(o1 instanceof Metadata && o2 instanceof Metadata) {
1101// Metadata m1 = (Metadata) o1;
1102// Metadata m2 = (Metadata) o2;
1103// ///ystem.err.println("MSMUtils.compare(" + m1 + ", " + m2 + ") = ");
1104// e1 = m1.getElement();
1105// e2 = m2.getElement();
1106// v1 = m1.getValue().toLowerCase();
1107// v2 = m2.getValue().toLowerCase();
1108// }
1109// else if(o1 instanceof ElementWrapper && o2 instanceof ElementWrapper) {
1110// e1 = (ElementWrapper) o1;
1111// e2 = (ElementWrapper) o2;
1112// }
1113// if(e1 != null && e2 != null) {
1114// // First we compare the namespaces
1115// result = e1.getNamespace().compareTo(e2.getNamespace());
1116// if(result == 0 && Gatherer.c_man != null && Gatherer.c_man.ready() && e1.getNamespace() != null) {
1117// // Now, given both elements are in the same set, we compare the element ordering using methods in MetadataSet
1118// MetadataSet set = Gatherer.c_man.getCollection().msm.getSet(e1.getNamespace());
1119// ///ystem.err.print("MetadataSet.compare(" + e1 + ", " + e2 + ") = ");
1120// if(set != null) {
1121// result = set.compare(e1.getElement(), e2.getElement());
1122// ///ystem.err.println(result);
1123// if(result == 0 && v1 != null && v2 != null) {
1124// // Finally we compare the values alphabetically.
1125// result = v1.compareTo(v2);
1126// }
1127// }
1128// else {
1129// return 0;
1130// }
1131// }
1132// }
1133// else {
1134// result = o1.toString().compareTo(o2.toString());
1135// }
1136// ///ystem.err.println("Result: " + result);
1137// return result;
1138// }
1139
1140// /** Indicates whether some other object is "equal to" this Comparator. */
1141// public boolean equals(Object obj) {
1142// return compare(this, obj) == 0;
1143// }
1144// }
1145}
Note: See TracBrowser for help on using the repository browser.