Index: trunk/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java
===================================================================
--- trunk/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java	(revision 9525)
+++ trunk/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java	(revision 9856)
@@ -69,22 +69,18 @@
 
 	// Form a regular expression that specifies the scope of the metadata
-	String file_path_regexp = file_relative_path;
-	if (file_path_regexp.equals("")) {
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
 	    file_path_regexp = DIRECTORY_FILENAME;
 	}
 	else {
 	    // Convert the file path into a regular expression that will match it
-	    file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\.");
-	    file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\(");
-	    file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)");
-	    file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\[");
-	    file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]");
-	    file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{");
-	    file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}");
-	    file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+");
-	}
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Remove any characters that are invalid in XML
+	String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue());
 
 	// Square brackets need to be escaped because they are a special character in Greenstone
-	String metadata_value_string = metadata_value.getFullValue();
 	metadata_value_string = metadata_value_string.replaceAll("\\[", "&#091;");
 	metadata_value_string = metadata_value_string.replaceAll("\\]", "&#093;");
@@ -313,25 +309,21 @@
 
 	// Form a regular expression that specifies the scope of the metadata
-	String file_path_regexp = file_relative_path;
-	if (file_path_regexp.equals("")) {
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
 	    file_path_regexp = DIRECTORY_FILENAME;
 	}
 	else {
 	    // Convert the file path into a regular expression that will match it
-	    file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\.");
-	    file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\(");
-	    file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)");
-	    file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\[");
-	    file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]");
-	    file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{");
-	    file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}");
-	    file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+");
-	}
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Remove any characters that are invalid in XML
+	String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue());
 
 	// Square brackets need to be escaped because they are a special character in Greenstone
-	String metadata_value_string = metadata_value.getFullValue();
 	metadata_value_string = metadata_value_string.replaceAll("\\[", "&#091;");
 	metadata_value_string = metadata_value_string.replaceAll("\\]", "&#093;");
-	
+
 	// Read all the FileSet elements in the file
 	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
@@ -378,4 +370,108 @@
 		// Remove this Metadata element
 		current_metadata_element.getParentNode().removeChild(current_metadata_element);
+	    }
+	}
+
+	// Rewrite the metadata.xml file
+	XMLTools.writeXMLFile(this, document);
+    }
+
+
+    public void replaceMetadata(File file, MetadataValue old_metadata_value, MetadataValue new_metadata_value)
+    {
+	// Parse the metadata.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Determine the file's path relative to the location of the metadata.xml file
+	File metadata_xml_file_directory = getParentFile();
+	String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory.getAbsolutePath().length());
+	if (file_relative_path.startsWith(File.separator)) {
+	    file_relative_path = file_relative_path.substring(File.separator.length());
+	}
+
+	// Form a regular expression that specifies the scope of the metadata
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
+	    file_path_regexp = DIRECTORY_FILENAME;
+	}
+	else {
+	    // Convert the file path into a regular expression that will match it
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Remove any characters that are invalid in XML
+	String old_metadata_value_string = XMLTools.removeInvalidCharacters(old_metadata_value.getFullValue());
+	String new_metadata_value_string = XMLTools.removeInvalidCharacters(new_metadata_value.getFullValue());
+
+	// Square brackets need to be escaped because they are a special character in Greenstone
+	old_metadata_value_string = old_metadata_value_string.replaceAll("\\[", "&#091;");
+	old_metadata_value_string = old_metadata_value_string.replaceAll("\\]", "&#093;");
+	new_metadata_value_string = new_metadata_value_string.replaceAll("\\[", "&#091;");
+	new_metadata_value_string = new_metadata_value_string.replaceAll("\\]", "&#093;");
+
+	// Read all the FileSet elements in the file
+	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
+	for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) {
+	    Element current_fileset_element = (Element) fileset_elements_nodelist.item(i);
+	    boolean current_fileset_matches = false;
+
+	    // Check the FileName elements of the FileSet to see if we have a match
+	    NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT);
+	    for (int j = 0; j < filename_elements_nodelist.getLength(); j++) {
+		Element current_filename_element = (Element) filename_elements_nodelist.item(j);
+		String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element);
+
+		// Only exact matches can be edited
+		if (current_filename_element_value.equals(file_path_regexp)) {
+		    current_fileset_matches = true;
+		    break;
+		}
+	    }
+
+	    // The FileSet doesn't apply, so move onto the next one
+	    if (current_fileset_matches == false) {
+		continue;
+	    }
+
+	    // Each metadata value is only allowed to be assigned once
+	    boolean new_metadata_value_already_exists = false;
+	    Element metadata_element_to_edit = null;
+
+	    // Find the Metadata element to replace in the fileset
+	    String metadata_element_name_full = old_metadata_value.getMetadataElement().getFullName();
+	    NodeList metadata_elements_nodelist = current_fileset_element.getElementsByTagName(METADATA_ELEMENT);
+	    for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) {
+		Element current_metadata_element = (Element) metadata_elements_nodelist.item(k);
+
+		// Check the metadata element name matches
+		String current_metadata_element_name_full = current_metadata_element.getAttribute("name");
+		if (!current_metadata_element_name_full.equals(metadata_element_name_full)) {
+		    continue;
+		}
+
+		// Check the new metadata value doesn't already exist
+		String current_metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+		if (current_metadata_value_string.equals(new_metadata_value_string)) {
+		    new_metadata_value_already_exists = true;
+		}
+
+		// Check the metadata element value matches
+		if (current_metadata_value_string.equals(old_metadata_value_string)) {
+		    metadata_element_to_edit = current_metadata_element;
+		}
+	    }
+
+	    // If the new metadata value already existed, remove the original value
+	    if (new_metadata_value_already_exists) {
+		metadata_element_to_edit.getParentNode().removeChild(metadata_element_to_edit);
+	    }
+	    // Otherwise replace the old value with the new value
+	    else {
+		XMLTools.setElementTextValue(metadata_element_to_edit, new_metadata_value_string);
 	    }
 	}
