Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptive.java	(revision 5945)
@@ -8,4 +8,5 @@
 
 import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.w3c.dom.Document;
@@ -35,92 +36,90 @@
 
 public class METSDescriptive
-{	MultiMap map;
-	String   ID;
-	String   name;
-
-	public METSDescriptive(String ID, String name)
-	{	this.map  = new MultiMap();
-		this.ID   = ID;
-		this.name = name;
-	}
-
-	public String getID()
-	{	return this.ID;
-	}
-
-	public String getName()
-	{	return this.name;
-	}
-
-	public void addNamespace(METSNamespace namespace)
-	{	this.map.put(namespace.getName(), namespace);
-	}
-
-	public METSNamespace getNamespace(String namespace)
-	{	return (METSNamespace) this.map.get(namespace);
-	}
-
-	/**
-	 *  Get the version of a metadata namespace that can be used for
-	 *  adding new values to the document.  Remember, each namespace may
-	 *  occur more than once, but only one of the occurrences can be 'open'.
-	 *
-	 *  @param <code>String</code> the name of the namespace
-	 */
-	public METSNamespace getOpenNamespace(String namespace)
-	{	if (this.map.getAll(namespace) == null)
-		{ return null;
-		}
-
-		Iterator namespaces = ((List) this.map.getAll(namespace)).iterator();
-
-		while (namespaces.hasNext())
-		{	METSNamespace namespaceData = (METSNamespace) namespaces.next();
-
-			if (namespaceData.isEditable())
-			{	return namespaceData;
-			}
-		}
-		return null;
-	}
-
-	/**
-	 *  Add a piece of metadata to this document.  Existing values are preserved.
-	 *
-	 *  @param <code>String</code> the namespace in which the metadata occurs
-	 *  @param <code>String</code> the label of the metadata
-
-	 *  @param <code>String</code> the value of the metadata
-	 */
-	public void addMetadata(String namespace, String label, String value)
-	{ METSNamespace namespaceData = this.getOpenNamespace(namespace);
-
-		if (namespaceData == null ||
-				namespaceData.isEditable() == false) 
-		{	namespaceData = NamespaceFactory.initNamespace(namespace);
-			this.addNamespace(namespaceData);
-		}
-		namespaceData.addMetadata(label, value);
-	}
-
-	/**
-	 *  Add a piece of metadata to this document.  Existing values in editable
-	 *  parts of the document's metadata are destroyed.
-	 *
-	 *  @param <code>String</code> the namespace in which the metadata occurs
-	 *  @param <code>String</code> the label of the metadata
-
-	 *  @param <code>String</code> the value of the metadata
-	 */
-	public void setMetadata(String namespace, String label, String value)
-	{ METSNamespace namespaceData = this.getOpenNamespace(namespace);
-
-		if (namespaceData == null ||
-				namespaceData.isEditable() == false) 
-		{	namespaceData = NamespaceFactory.initNamespace(namespace);
-			this.addNamespace(namespaceData);
-		}
-		namespaceData.setMetadata(label, value);
-	}
+{ MultiMap map;
+  String   ID;
+  String   name;
+
+  public METSDescriptive(String ID, String name)
+  { this.map  = new MultiMap();
+    this.ID   = ID;
+    this.name = name;
+  }
+
+  public String getID()
+  { return this.ID;
+  }
+
+  public String getName()
+  { return this.name;
+  }
+
+  public void addNamespace(METSNamespace namespace)
+  { this.map.put(namespace.getName(), namespace);
+  }
+
+  public METSNamespace getNamespace(String namespace)
+  { return (METSNamespace) this.map.get(namespace);
+  }
+
+  /**
+   *  Get the version of a metadata namespace that can be used for
+   *  adding new values to the document.  Remember, each namespace may
+   *  occur more than once, but only one of the occurrences can be 'open'.
+   *
+   *  @param <code>String</code> the name of the namespace
+   */
+  public METSNamespace getOpenNamespace(String namespace)
+  { if (this.map.getAll(namespace) == null)
+    { return null;
+    }
+
+    Iterator namespaces = ((List) this.map.getAll(namespace)).iterator();
+
+    while (namespaces.hasNext())
+    { METSNamespace namespaceData = (METSNamespace) namespaces.next();
+
+      if (namespaceData.isEditable())
+      {	return namespaceData;
+      }
+    }
+    return null;
+  }
+  
+  /**
+   *  Add a piece of metadata to this document.  Existing values are preserved.
+   *
+   *  @param <code>String</code> the namespace in which the metadata occurs
+   *  @param <code>String</code> the label of the metadata   
+   *  @param <code>String</code> the value of the metadata
+   */
+  public void addMetadata(String namespace, String label, String value)
+  { METSNamespace namespaceData = this.getOpenNamespace(namespace);
+  
+    if (namespaceData == null ||
+	namespaceData.isEditable() == false) 
+    { namespaceData = NamespaceFactory.initNamespace(namespace);
+      this.addNamespace(namespaceData);
+    }
+    namespaceData.addMetadata(label, value);
+  }
+
+  /**
+   *  Add a piece of metadata to this document.  Existing values in editable
+   *  parts of the document's metadata are destroyed.
+   *
+   *  @param <code>String</code> the namespace in which the metadata occurs
+   *  @param <code>String</code> the label of the metadata   
+   *  @param <code>String</code> the value of the metadata
+   */
+  public void setMetadata(String namespace, String label, String value)
+  { METSNamespace namespaceData = this.getOpenNamespace(namespace);
+  
+    if (namespaceData == null ||
+	namespaceData.isEditable() == false) 
+    { namespaceData = NamespaceFactory.initNamespace(namespace);
+      this.addNamespace(namespaceData);
+    }
+    namespaceData.setMetadata(label, value);
+  }
 
 	/**
@@ -238,7 +237,7 @@
   }
 
-  public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
+  public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
   { // check if this node is in the
-    int sqlId = 0;
+    int sqlId = -1;
 
     //    System.out.println("Writing " + connection.toString());
@@ -253,31 +252,51 @@
 
     connection.execute(select.toString());
+
     try {
-	if (connection.getResultSet() != null &&
-	    connection.getResultSet().next()) {
-	    // the node already exists - no need to do anything as such
-	}
-	else
-	{
-	    // It is a new node and needs writing
-	    GS3SQLInsert insert = new GS3SQLInsert("metadata");
-	    insert.addValue("DocID", document.getID().toString());
-	    insert.addValue("MetaID", this.ID);
+      GS3SQLAction action;
+
+      ResultSet resultSet = connection.getResultSet();
+
+      if (resultSet != null &&
+	  resultSet.first()) {
+	// the node already exists - no need to do anything as such
+	GS3SQLUpdate update = new GS3SQLUpdate("metadata");
+	update.setWhere(where);
+	action = update;
+      }
+      else
+      { // Set result set to null, just in case next() didn't work above...
+	resultSet = null;
+
+	// It is a new node and needs writing
+	action = new GS3SQLInsert("metadata");
+
+	action.addValue("DocID", document.getID().toString());
+	action.addValue("MetaID", this.ID);
+      }
+	
+      // always set the group identifier
+      action.addValue("GroupID", this.name);
 	    
-	    connection.execute(insert.toString());
-	    
-	    // now execute the select statement again to get the new identifier
-	    // 'MetadataRef'
-	    //	    System.out.println(select.toString());
-	    connection.execute(select.toString());
-	}
-
-	// get the reference for this item...	
-	connection.getResultSet().first();
-	sqlId = connection.getResultSet().getInt("MetadataRef");
+      // execute the action as required
+      connection.execute(action.toString());
+
+      // create a new resultset if necessary
+      if (resultSet == null) {
+	// now execute the select statement again to get the new identifier
+	// 'MetadataRef'
+	// System.out.println(select.toString());
+	connection.execute(select.toString());
+
+	resultSet = connection.getResultSet();
+	resultSet.first();
+      }
+
+      // get the reference for this item...
+      sqlId = resultSet.getInt("MetadataRef");
     }
     catch (SQLException sql)
-	{ System.out.println(sql);
-	}
+    { System.out.println(sql);
+    }
 
     Iterator keys = this.map.keySet().iterator();
@@ -299,7 +318,58 @@
       { METSNamespace namespace = (METSNamespace) namespaces.next();
       
-        namespace.writeSQL(sqlId, connection);
-      }
-    }
+        if (!namespace.writeSQL(sqlId, connection))
+        { return false;
+	}
+      }
+    }
+    return true;
+  }
+
+  public static METSDescriptive readSQL(DocumentInterface document, GS3SQLConnection connection,
+					ResultSet resultSet)
+  {
+    try {
+      String ID   = resultSet.getString("MetaID");
+      String name = resultSet.getString("GroupID");
+
+      // create the metadata block object
+      METSDescriptive descriptive = new METSDescriptive(ID, name);
+      
+      // get its metadata reference to retrieve namespaces
+      int metadataRef = resultSet.getInt("MetadataRef");
+
+      // query the database for matching namespaces for this metadata block
+      GS3SQLSelect select = new GS3SQLSelect("namespaces");
+      select.addField("*");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(metadataRef),
+						      GS3SQLField.INTEGER_TYPE);
+      GS3SQLWhere where = new GS3SQLWhere(whereItem);
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+
+      // parse through the namespaces, calling the namespace class to create instances
+      // as it will
+      ResultSet namespaceSet = connection.getResultSet();
+      if (namespaceSet != null && namespaceSet.first()) {
+	do {
+	  METSNamespace namespace = METSNamespace.readSQL(connection, namespaceSet);
+	  if (namespace != null) {
+	    descriptive.addNamespace(namespace);
+	  }
+	  else {
+	    System.out.println("Null namespace output");
+	  }
+	}
+	while (namespaceSet.next());
+      }
+
+      return descriptive;
+    }
+    catch (SQLException sqlEx)
+    { System.out.println(sqlEx);
+      System.exit(1);
+    }
+    return null;
   }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptiveSet.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptiveSet.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDescriptiveSet.java	(revision 5945)
@@ -7,4 +7,7 @@
 import java.util.Map;
 import java.util.Iterator;
+
+import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.w3c.dom.Document;
@@ -18,14 +21,16 @@
 import org.xml.sax.SAXParseException;
 
-
 import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
 
 import org.greenstone.gsdl3.gs3build.util.GS3SQLConnection;
+import org.greenstone.gsdl3.gs3build.database.*;
 
 public class METSDescriptiveSet
 { Map children;
+  Map childrenById;
 
   public METSDescriptiveSet()
   { this.children = new HashMap();
+    this.childrenById = new HashMap();
 
     METSDescriptive descriptive = new METSDescriptive("DM1", "default");
@@ -35,8 +40,13 @@
   public void addDescriptive(METSDescriptive metadata)
   { this.children.put(metadata.getName(), metadata);
+    this.childrenById.put(metadata.getID(), metadata);
   }
 
   public METSDescriptive getDescriptive(String name)
   { return (METSDescriptive) this.children.get(name);
+  }
+
+  public METSDescriptive getDescriptiveById(String id)
+  { return (METSDescriptive) this.childrenById.get(id);
   }
 
@@ -101,5 +111,5 @@
 
 
-  public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
+  public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
   { Iterator groups = this.children.values().iterator();
     
@@ -107,6 +117,9 @@
     { METSDescriptive group = (METSDescriptive) groups.next();
 
-      group.writeSQL(document, connection);
+      if (!group.writeSQL(document, connection))
+      { return false;
+      }
     }
+    return true;
   }
 
@@ -122,4 +135,36 @@
     return set;
   }
+
+  public static METSDescriptiveSet readSQL(DocumentInterface document, GS3SQLConnection connection)
+  {
+    METSDescriptiveSet set = new METSDescriptiveSet();
+
+    GS3SQLSelect select = new GS3SQLSelect("metadata");
+    select.addField("*");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+    select.setWhere(new GS3SQLWhere(whereItem));
+    connection.execute(select.toString());
+
+    // start going through the matching metadata blocks
+    try {
+      ResultSet resultSet = connection.getResultSet();
+      resultSet.first();
+      do {
+	METSDescriptive descriptive = METSDescriptive.readSQL(document, connection, resultSet);
+	if (descriptive != null) {
+	  set.addDescriptive(descriptive);
+	}
+	else {
+	  System.out.println("Null descriptive");
+	}
+      } while (resultSet.next());
+    }
+    catch (SQLException sqlEx) {
+      System.out.println(sqlEx);
+      System.exit(1);
+    }
+
+    return set;
+  }
 }
 
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDivision.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDivision.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSDivision.java	(revision 5945)
@@ -10,4 +10,5 @@
 
 import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.greenstone.gsdl3.gs3build.util.XMLTools;
@@ -18,5 +19,6 @@
 public class METSDivision
 {
-  String       ID;
+  String       ID;          // the unique identifier for this division (unique within the
+                            // document, not necessarily unique within the collection).
   String       order;       // see the METS documentation for the meaning of the different
   String       orderLabel;  // label types.
@@ -27,4 +29,7 @@
   List         fileRefs;
   Map          children;
+ 
+  public static final String STRUCTURE_PARENT = "Structure";
+  public static final String DIVISION_PARENT  = "Division";
 
   public METSDivision(String ID, String order, String orderLabel, String userLabel, String type)
@@ -43,228 +48,462 @@
   }
 
-	/**
-	 *  Add a new file reference to the structure
-	 *
-	 *  @param <code>METSFileRef</code> the file to be referenced.
-	 */
-	public void addFileReference(METSFileID fileRef)
-	{	this.fileRefs.add(fileRef);
+  /**
+   *  Find all the divisions that match a given list of file group
+   *  identifiers...
+   *
+   *  @param <code>List</code> the list of identifiers to find
+   *  @param <code>List</code> the list into which to place any
+   *         matching divisions.
+   */
+  public void findDivisionsForFiles(List listOfFileIdentifiers, List resultList)
+  { Iterator iterator = this.fileRefs.iterator();
+	
+    // get the references on this division, and mark if necessary
+    while (iterator.hasNext()) 
+    { String reference = iterator.next().toString();
+
+      Iterator fileIterator = listOfFileIdentifiers.iterator();
+      while (fileIterator.hasNext())
+      { String fileRef = fileIterator.next().toString();
+      
+        if (fileRef.equals(reference))
+	{ resultList.add(this);
 	}
-
-    /**
-     *  Add a new metadata reference to the structure
-     */
-    public void addMetadataReference(String metadataRef)
-    { // TODO: correct the type
-      this.metadataRefs.add(metadataRef);
-    }
-
-	/**
-	 *  Add a child division, or sub-division to the document.  For example,
-	 *  sections within a chapter.
-	 *
-	 *  @param <code>METSDivision</code> the child division.
-	 */
-	public void addSubDivision(METSDivision child)
-	{	this.children.put(child.getID(), child);
+      }
+    }
+    
+    // get the child groups, and check each in turn...
+    Iterator groups = this.children.values().iterator();
+    while (groups.hasNext())
+    { METSDivision group = (METSDivision) groups.next();
+
+      group.findDivisionsForFiles(listOfFileIdentifiers, resultList);
+    }    
+  }
+
+  /**
+   *  Get the namespace from the given set of descriptive blocks...
+   */
+  public METSNamespace findNamespace(String namespaceName, boolean isOpenNamespace, 
+				     METSDescriptiveSet descriptiveSet)
+  { METSNamespace namespace = null;
+
+    // Special case - no existing metadata references
+    if (this.metadataRefs.size() == 0) {
+      // Create new Descriptive and add it to the descriptive set
+      METSDescriptive descriptive = new METSDescriptive("DM"+this.ID, this.orderLabel);
+      descriptiveSet.addDescriptive(descriptive);
+
+      // Create the namespace and add it to the Descriptive
+      namespace = NamespaceFactory.initNamespace(namespaceName);
+      if (namespace != null)
+      { descriptive.addNamespace(namespace);
+      }
+
+      return namespace;
+    }
+
+    Iterator descriptiveIterator = this.metadataRefs.iterator();
+
+    while (descriptiveIterator.hasNext())
+    { String descriptiveRef = descriptiveIterator.next().toString();
+
+      METSDescriptive descriptive = descriptiveSet.getDescriptiveById(descriptiveRef);
+
+      if (isOpenNamespace) {
+	namespace = descriptive.getOpenNamespace(namespaceName);
+      }
+      else {
+	namespace = descriptive.getNamespace(namespaceName);
+      }
+    
+      if (namespace != null)
+	break;
+    }
+
+    // Special case - no such namespace in any descriptive list...
+    if (namespace == null)
+    { // take the first descriptive area...
+      METSDescriptive descriptive = descriptiveSet.getDescriptiveById(this.metadataRefs.get(0).toString());
+
+      // create the namespace, and add it to the METSDescriptive
+      namespace = NamespaceFactory.initNamespace(namespaceName);
+      if (namespace != null)
+      { descriptive.addNamespace(namespace);
+      }
+    }
+
+    return namespace;
+  }
+
+  /**
+   *  Add a new file reference to the structure
+   *
+   *  @param <code>METSFileRef</code> the file to be referenced.
+   */
+  public void addFileReference(METSFileID fileRef)
+  { this.fileRefs.add(fileRef);
+  }
+
+  /**
+   *  Add a new metadata reference to the structure
+   */
+  public void addMetadataReference(String metadataRef)
+  { // TODO: correct the type
+    this.metadataRefs.add(metadataRef);
+  }
+
+  /**
+   *  Add a child division, or sub-division to the document.  For example,
+   *  sections within a chapter.
+   *
+   *  @param <code>METSDivision</code> the child division.
+   */
+  public void addSubDivision(METSDivision child)
+  { this.children.put(child.getID(), child);
+  }
+
+  /**
+   *  Add a child division to a descendent of this division.
+   *
+   *  @param <code>String</code> the path to the division into which the
+   *         subdivision will be added.
+   *  @param <code>METSDivision</code> the division to be added
+   */
+  public void addSubDivision(String divisionID, METSDivision division)
+  { String topDivision = METSDivision.getTopDivisionName(divisionID);
+
+    METSDivision child = (METSDivision) this.children.get(topDivision);
+    if (child == null)
+    { return;
+    }
+
+    String subDivisionID = METSDivision.getSubDivisionName(divisionID);
+    if (subDivisionID == null)
+    { child.addSubDivision(division);
+    }
+    else
+    { child.addSubDivision(subDivisionID, division);
+    }
+  }
+
+  public METSDivision getDivision(String divisionID)
+  { String topDivision = METSDivision.getTopDivisionName(divisionID);
+
+    METSDivision child = (METSDivision) this.children.get(topDivision);
+    if (child == null)
+    { return null;
+    }
+
+    String subDivision = METSDivision.getSubDivisionName(divisionID);
+    if (subDivision != null)
+    { child = child.getDivision(subDivision);
+    }
+    
+    return child;
+  }
+
+  public static String getSubDivisionName(String divisionName)
+  { int at = divisionName.indexOf('.');
+
+    if (at >= 0)
+    { return divisionName.substring(at+1);
+    }
+    else
+    { return null;
+    }
+  }
+
+  public static String getTopDivisionName(String divisionName)
+  { int at = divisionName.indexOf('.');
+
+    if (at >= 0)
+    { return divisionName.substring(0, at);
+    }
+    else
+    {	return divisionName;
+    }
+  }
+
+  /**
+   *  Write the METS file in an XML to a text-output sink
+   *
+   *  @param <code>PrintWriter</code> the destination of the output
+   */
+  public void write(PrintWriter writer)
+  { String tag = XMLTools.getOpenTag("mets", "div");
+    tag = XMLTools.addAttribute(tag, "ID", this.ID.toString());
+    tag = XMLTools.addAttribute(tag, "TYPE", this.type);
+    tag = XMLTools.addAttribute(tag, "ORDER", this.order);
+    if (this.orderLabel != null)
+    { tag = XMLTools.addAttribute(tag, "ORDERLABEL", this.orderLabel);
+    }
+    if (this.userLabel != null)
+    { tag = XMLTools.addAttribute(tag, "LABEL", this.userLabel);
+    }
+    writer.println(tag);
+
+    // write the list of file pointers for this structural element
+    if (this.fileRefs.size() > 0)
+    { tag = XMLTools.getOpenTag("mets", "fptr");
+      
+      String fileList = this.writeList(this.fileRefs);
+
+      tag = XMLTools.addAttribute(tag, "FILEID", fileList);
+      
+      tag = XMLTools.makeSingleton(tag);
+      writer.println(tag);
+    }
+
+    // ..and then the metadata - this is the same code at present,
+    // but is replicated here in case of future amendment.
+    if (this.metadataRefs.size() > 0)
+    { tag = XMLTools.getOpenTag("mets", "mptr");
+
+      String metaList = this.writeList(this.metadataRefs);
+      tag = XMLTools.addAttribute(tag, "METAID", metaList);
+      tag = XMLTools.makeSingleton(tag);
+      writer.println(tag);
+    }
+      
+    // close the div element
+    writer.println(XMLTools.getCloseTag("mets", "div"));
+  }
+
+  private String writeList(List list)
+  { StringBuffer listString = new StringBuffer();
+      
+    Iterator iterator = list.iterator();
+    while (iterator.hasNext())
+    { String item = iterator.next().toString();
+      if (listString.length() > 0)
+      { listString.append(" ");
+      }
+      listString.append(item);
+    }
+    return listString.toString();
+  }
+
+  public boolean writeSQL(int parentRef, boolean parentIsStructure, GS3SQLConnection connection)
+  { int sqlRef = -1;
+
+    // set the "where" to find the reference for this division
+    GS3SQLSelect select = new GS3SQLSelect("divisions");
+    select.addField("divisionRef");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(parentRef), GS3SQLField.INTEGER_TYPE);
+    GS3SQLWhereItem parentItem = new GS3SQLWhereItem("ParentType", "=", parentIsStructure ? "Structure" : "Division");
+    GS3SQLWhereItem item = new GS3SQLWhereItem("SectionID", "=", this.ID.toString());
+    GS3SQLWhere where = new GS3SQLWhere(whereItem);    
+    where.add(parentItem);
+    where.add(item);
+    select.setWhere(where);
+
+    connection.execute(select.toString());
+
+    // Do the actual writing
+    GS3SQLAction action;
+
+    ResultSet resultSet = connection.getResultSet();
+    try {
+      if (resultSet == null ||
+	  !resultSet.first())
+      { resultSet = null;
+
+        GS3SQLInsert insert = new GS3SQLInsert("divisions");
+	insert.addValue("SectionID", this.ID.toString());
+	insert.addValue("ParentRef", Integer.toString(parentRef));
+	insert.addValue("ParentType", parentIsStructure == true ? STRUCTURE_PARENT : DIVISION_PARENT);
+	
+	action = insert;
+      }
+      else {
+	sqlRef = resultSet.getInt("divisionRef");
+	
+	GS3SQLUpdate update = new GS3SQLUpdate("divisions");
+	GS3SQLWhere  updateWhere = 
+	  new GS3SQLWhere(new GS3SQLWhereItem("divisionRef", "=", Integer.toString(sqlRef), 
+					      GS3SQLField.INTEGER_TYPE));
+	update.setWhere(updateWhere);
+	action = update;
+      }
+    }
+    catch (SQLException sql) {
+      System.err.println(sql);
+      return false;
+    }
+      
+    action.addValue("Type", this.type.toString());
+    action.addValue("LabelOrder", this.order);
+    action.addValue("ShortLabel", this.orderLabel);
+    action.addValue("UserLabel", this.userLabel);
+
+    if (!connection.execute(action.toString()))
+    { return false;
+    }
+
+    // if doing a fresh item, get the new structure reference...
+    if (resultSet == null)
+    { // get the new structure reference
+      connection.execute(select.toString());
+
+      // get the sql reference for the division
+      try {
+	// read in the structure reference
+	resultSet = connection.getResultSet();
+	if (resultSet == null) {
+	  return false;
 	}
-
-	/**
-	 *  Add a child division to a descendent of this division.
-	 *
-	 *  @param <code>String</code> the path to the division into which the
-	 *         subdivision will be added.
-	 *  @param <code>METSDivision</code> the division to be added
-	 */
-	public void addSubDivision(String divisionID, METSDivision division)
-	{	String topDivision = METSDivision.getTopDivisionName(divisionID);
-
-		METSDivision child = (METSDivision) this.children.get(topDivision);
-		if (child == null)
-		{	return;
-		}
-
-		String subDivisionID = METSDivision.getSubDivisionName(divisionID);
-		if (subDivisionID == null)
-		{ child.addSubDivision(division);
-		}
-		else
-		{	child.addSubDivision(subDivisionID, division);
-		}
+	resultSet.first();
+	sqlRef = resultSet.getInt("divisionRef");
+	resultSet.close();
+	resultSet = null;
+      }
+      catch (SQLException sqlex) {
+	System.err.println("Unable to retrieve reference for Division " + sqlex);
+	return false;
+      }
+    }
+    // close the open resultSet, as we don't need it any longer...
+    else {
+      try {
+	resultSet.close();
+      }
+      catch (SQLException sql) {
+	System.err.println(sql);
+      }
+    }
+
+    // delete the old file/metadata references
+    GS3SQLWhere referenceWhere = 
+      new GS3SQLWhere(new GS3SQLWhereItem("divisionRef", "=", Integer.toString(sqlRef), 
+					  GS3SQLField.INTEGER_TYPE));
+
+    GS3SQLDelete delete = new GS3SQLDelete("divisionfilerefs");
+    delete.setWhere(referenceWhere);
+    connection.execute(delete.toString());
+
+    delete = new GS3SQLDelete("divisionmetarefs");
+    delete.setWhere(referenceWhere);
+    connection.execute(delete.toString());
+
+    // write the new file references
+    if (this.fileRefs.size() > 0)
+    { Iterator iterator = this.fileRefs.iterator();
+	
+      while (iterator.hasNext()) 
+      { GS3SQLInsert fileinsert = new GS3SQLInsert("divisionfilerefs");
+        fileinsert.addValue("divisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
+	fileinsert.addValue("Type", "Group");
+	fileinsert.addValue("fileRef", iterator.next().toString());
+	connection.execute(fileinsert.toString());
+      }
+    }
+
+    // write the metadata references
+    if (this.metadataRefs.size() > 0)
+    { Iterator iterator = this.metadataRefs.iterator();
+	
+      while (iterator.hasNext()) 
+      { GS3SQLInsert metainsert = new GS3SQLInsert("divisionmetarefs");
+        metainsert.addValue("divisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
+	metainsert.addValue("Type", "Group");
+	metainsert.addValue("metadataRef", iterator.next().toString());
+	connection.execute(metainsert.toString());
+      }
+    }
+
+    // write out any children in turn
+    Iterator groups = this.children.values().iterator();
+
+    while (groups.hasNext())
+    { METSDivision group = (METSDivision) groups.next();
+    
+      if (!group.writeSQL(sqlRef, false, connection)) {
+	return false;
+      }
+    }
+    return true;
+  }
+
+  public static METSDivision readSQL(GS3SQLConnection connection, ResultSet resultSet)
+  {
+    METSLocation metsLocation = null;
+    
+    try {
+      // read the basic information
+      String ID   = resultSet.getString("SectionID");
+      String type = resultSet.getString("Type");
+      String order = resultSet.getString("LabelOrder");
+      String orderLabel = resultSet.getString("ShortLabel");
+      String userLabel  = resultSet.getString("UserLabel");
+      
+      // construct the division object
+      METSDivision division = new METSDivision(ID, order, orderLabel, userLabel, type);
+      
+      // obtain a list of child divisions
+      int divisionRef = resultSet.getInt("DivisionRef");
+
+      GS3SQLSelect select = new GS3SQLSelect("divisions");
+      select.addField("*");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(divisionRef),
+						      GS3SQLField.INTEGER_TYPE);
+      GS3SQLWhere where = new GS3SQLWhere(whereItem);
+      whereItem = new GS3SQLWhereItem("ParentType", "=", DIVISION_PARENT);
+      where.add(whereItem);
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+      
+      // circulate through to obtain further children
+      ResultSet childSet = connection.getResultSet();
+      if (childSet.first())
+      {
+	do {
+	  METSDivision childDivision = METSDivision.readSQL(connection, childSet);
+	  division.addSubDivision(childDivision);
 	}
-
-	public METSDivision getDivision(String divisionID)
-	{	String topDivision = METSDivision.getTopDivisionName(divisionID);
-
-		METSDivision child = (METSDivision) this.children.get(topDivision);
-		if (child == null)
-		{	return null;
-		}
-
-		String subDivision = METSDivision.getSubDivisionName(divisionID);
-		if (subDivision != null)
-		{	child = child.getDivision(subDivision);
-		}
-
-		return child;
+	while (childSet.next());
+      }
+
+      select = new GS3SQLSelect("divisionfilerefs");
+      select.addField("*");
+      where = new GS3SQLWhere(new GS3SQLWhereItem("divisionRef", "=", Integer.toString(divisionRef), 
+						  GS3SQLField.INTEGER_TYPE));
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+
+      ResultSet fileSet = connection.getResultSet();
+      if (fileSet != null && fileSet.first())
+      { do 
+	{ String reference = fileSet.getString("fileRef");
+	  division.fileRefs.add(reference);
 	}
-
-	public static String getSubDivisionName(String divisionName)
-	{	int at = divisionName.indexOf('.');
-
-		if (at >= 0)
-		{	return divisionName.substring(at+1);
-		}
-		else
-		{	return null;
-		}
+	while (fileSet.next());  
+      }
+
+      select = new GS3SQLSelect("divisionmetarefs");
+      select.addField("*");
+      where = new GS3SQLWhere(new GS3SQLWhereItem("divisionRef", "=", Integer.toString(divisionRef), 
+						  GS3SQLField.INTEGER_TYPE));
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+
+      ResultSet metaSet = connection.getResultSet();
+      if (metaSet != null && metaSet.first())
+      { do 
+	{ String reference = metaSet.getString("metadataRef");
+	  division.metadataRefs.add(reference);
 	}
-
-	public static String getTopDivisionName(String divisionName)
-	{	int at = divisionName.indexOf('.');
-
-		if (at >= 0)
-		{	return divisionName.substring(0, at);
-		}
-		else
-		{	return divisionName;
-		}
-	}
-
-    /**
-     *  Write the METS file in an XML to a text-output sink
-     *
-     *  @param <code>PrintWriter</code> the destination of the output
-     */
-    public void write(PrintWriter writer)
-    { String tag = XMLTools.getOpenTag("mets", "div");
-      tag = XMLTools.addAttribute(tag, "ID", this.ID.toString());
-      tag = XMLTools.addAttribute(tag, "TYPE", this.type);
-      tag = XMLTools.addAttribute(tag, "ORDER", this.order);
-      if (this.orderLabel != null)
-      { tag = XMLTools.addAttribute(tag, "ORDERLABEL", this.orderLabel);
-      }
-      if (this.userLabel != null)
-      { tag = XMLTools.addAttribute(tag, "LABEL", this.userLabel);
-      }
-      writer.println(tag);
-
-      // write the list of file pointers for this structural element
-      if (this.fileRefs.size() > 0)
-      {	tag = XMLTools.getOpenTag("mets", "fptr");
-      
-        String fileList = this.writeList(this.fileRefs);
-
-	tag = XMLTools.addAttribute(tag, "FILEID", fileList);
-
-	tag = XMLTools.makeSingleton(tag);
-	writer.println(tag);
-      }
-
-      // ..and then the metadata - this is the same code at present,
-      // but is replicated here in case of future amendment.
-      if (this.metadataRefs.size() > 0)
-      { tag = XMLTools.getOpenTag("mets", "mptr");
-
-        String metaList = this.writeList(this.metadataRefs);
-        tag = XMLTools.addAttribute(tag, "METAID", metaList);
-	tag = XMLTools.makeSingleton(tag);
-	writer.println(tag);
-      }
-      
-      // close the div element
-      writer.println(XMLTools.getCloseTag("mets", "div"));
-    }
-
-    private String writeList(List list)
-    { StringBuffer listString = new StringBuffer();
-      
-      Iterator iterator = list.iterator();
-      while (iterator.hasNext())
-      { String item = iterator.next().toString();
-	if (listString.length() > 0)
-	{ listString.append(" ");
-	}
-	listString.append(item);
-      }
-      return listString.toString();
-    }
-
-    public void writeSQL(int parentRef, boolean parentIsStructure, GS3SQLConnection connection)
-    { Iterator groups = this.children.values().iterator();
-
-      GS3SQLInsert insert = new GS3SQLInsert("divisions");
-      insert.addValue("SectionID", this.ID.toString());
-      insert.addValue("Type", this.type.toString());
-      insert.addValue("LabelOrder", this.order);
-      insert.addValue("ShortLabel", this.orderLabel);
-      insert.addValue("UserLabel", this.userLabel);
-      insert.addValue("ParentRef", Integer.toString(parentRef));
-      insert.addValue("ParentType", parentIsStructure == true ? "Structure" : "Division");
-      
-      System.out.println(insert.toString());
-      connection.execute(insert.toString());
-
-      // TODO: write metadata references
-      // TODO: write file references
-      
-      // get the new structure reference
-      GS3SQLSelect select = new GS3SQLSelect("divisions");
-      select.addField("divisionRef");
-      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(parentRef), GS3SQLField.INTEGER_TYPE);
-      GS3SQLWhereItem parentItem = new GS3SQLWhereItem("ParentType", "=", parentIsStructure ? "Structure" : "Division");
-      GS3SQLWhereItem item = new GS3SQLWhereItem("SectionID", "=", this.ID.toString());
-      GS3SQLWhere where = new GS3SQLWhere(whereItem);
-      where.add(parentItem);
-      where.add(item);
-      select.setWhere(where);
-      connection.execute(select.toString());
-
-      // get the sql reference for the division
-      int sqlRef;
-
-      try {
-        // read in the structure reference
-	connection.getResultSet().first();
-	sqlRef = connection.getResultSet().getInt("divisionRef");
-      }
-      catch (SQLException sqlex) {
-	  System.out.println("Unable to retrieve reference for Division " + sqlex);
-	  return;
+	while (metaSet.next());  
       }
         
-      // write the file references
-      if (this.fileRefs.size() > 0)
-      { Iterator iterator = this.fileRefs.iterator();
-	
-        while (iterator.hasNext()) 
-	{ GS3SQLInsert fileinsert = new GS3SQLInsert("divisionfilerefs");
-	  fileinsert.addValue("divisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
-	  fileinsert.addValue("Type", "Group");
-	  fileinsert.addValue("fileRef", iterator.next().toString());
-	  connection.execute(fileinsert.toString());
-	}
-      }
-        
-      // write the metadata references
-      if (this.metadataRefs.size() > 0)
-      { Iterator iterator = this.metadataRefs.iterator();
-	
-        while (iterator.hasNext()) 
-	{ GS3SQLInsert metainsert = new GS3SQLInsert("divisionmetarefs");
-	  metainsert.addValue("divisionRef", Integer.toString(sqlRef), GS3SQLField.INTEGER_TYPE);
-	  metainsert.addValue("Type", "Group");
-	  metainsert.addValue("metadataRef", iterator.next().toString());
-	  connection.execute(metainsert.toString());
-	}
-      }
-
-      // write out any children in turn
-      while (groups.hasNext())
-      { METSDivision group = (METSDivision) groups.next();
-
-        group.writeSQL(sqlRef, false, connection);
-      }
-    }
-
+      return division;
+    }
+    catch (SQLException sqlEx)
+    { System.out.println(sqlEx);
+    }    
+    return null;
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFile.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFile.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFile.java	(revision 5945)
@@ -8,4 +8,7 @@
 import java.net.URL;
 import java.net.URLConnection;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
 
 import org.w3c.dom.Document;
@@ -29,208 +32,268 @@
 public class METSFile
 {
-	METSFileID    id;
-	METSFilePos   location;
-	String        MIMEType;
-	int           sequenceNo;
-	long          size;
-	METSDate      created;
-	long          checkSum;
-	List          adminRefs;
-	List          describeRefs;
-	METSFileGroup group;
-
-	/**
-	 *  Create a new METSFile object, with the given properties.  The remaining
-	 *  fields are filled in with default values.
-	 *
-	 *  @param <code>String</code> the id of the file
-	 *  @param <code>METSFilePos</code> the location of the file
-	 *  @param <code>String</code> the MIME type of the file
-	 */
-	public METSFile(METSFileID id, METSFilePos location, String mimeType)
-	{	this.id           = id;        // required
-		this.location     = location;  // the location
-		this.MIMEType     = mimeType;  // the MIME type;
-		this.sequenceNo   = -1;       // -1 indicates unset
-		this.size         = -1;        // -1 indicates unset
-		this.checkSum     = -1;        // -1 indicates unset
-		this.created      = null;
-		this.adminRefs    = new ArrayList();
-		this.describeRefs = new ArrayList();
-		this.group        = null;
+  METSFileID    id;
+  METSFilePos   location;
+  String        MIMEType;
+  int           sequenceNo;
+  long          size;
+  METSDate      created;
+  long          checkSum;
+  List          adminRefs;
+  List          describeRefs;
+  METSFileGroup group;
+
+  /**
+   *  Create a new METSFile object, with the given properties.  The remaining
+   *  fields are filled in with default values.
+   *
+   *  @param <code>String</code> the id of the file
+   *  @param <code>METSFilePos</code> the location of the file
+   *  @param <code>String</code> the MIME type of the file
+   */
+  public METSFile(METSFileID id, METSFilePos location, String mimeType)
+  { this.id           = id;        // required
+    this.location     = location;  // the location
+    this.MIMEType     = mimeType;  // the MIME type;
+    this.sequenceNo   = -1;       // -1 indicates unset
+    this.size         = -1;        // -1 indicates unset
+    this.checkSum     = -1;        // -1 indicates unset
+    this.created      = null;
+    this.adminRefs    = new ArrayList();
+    this.describeRefs = new ArrayList();
+    this.group        = null;
+  }
+
+  public boolean equals(URL url)
+  { return this.location.equals(url);
+  }
+
+  /**
+   *  Set the parent group
+   *
+   *  @param <code>METSFileGroup</code> the new holding file group
+   */
+  public void setGroup(METSFileGroup group)
+  { this.group = group;
+  }
+
+  /**
+   *  Get the parent group of this file
+   *
+   *  @return <code>METSFileGroup</code> the holding file group
+   */
+  public METSFileGroup getGroup()
+  { return this.group;
+  }
+
+  /**
+   *  Get the identifier of this file
+   *
+   *  @return <code>METSFileID</code> the file identifier
+   */
+  public METSFileID getID()
+  { return this.id;
+  }
+  
+  /**
+   *  Set the identifier of this file
+   *
+   *  @param <code>METSFileID</code> the file identifier
+   */
+  public void setID(METSFileID id)
+  { this.id = id;
+  }
+
+  /**
+   *  @return <code>String</code> the MIME (content) type of the file
+   */
+  public String getMIMEType()
+  { return this.MIMEType;
+  }
+
+  /**
+   *  @return <code>URL</code> the location of the file.  This will often be in
+   *          "file://" form.
+   */
+  public URL getLocation()
+  { return this.location.getLocation();
+  }
+
+  /**
+   *  Take a url and make a METSFile object out of it - works out
+   *  details such as the Mime type, identifiers and other necessary
+   *  information to call the constructor for METSFile
+   *
+   *  @param <code>URL</code> the url of the object - this may be a 
+   *                          reference to a file on the local filestore
+   *
+   *  @return <code>METSFile</code> the METS file object for the corresponding
+   *                                document component.
+   */
+  public static METSFile makeMETSFile(URL url, String mimeType)
+  {	
+    METSFile reply = new METSFile(new METSFileID(), new METSFilePos(url), mimeType);
+    return reply;
+  }
+		
+  public static METSFile makeMETSFile(URL url)
+  { String mimeType;
+  
+    if (url.toString().startsWith("file://"))
+    { // TODO: Work out the MIME type
+      mimeType = URLConnection.getFileNameMap().getContentTypeFor(url.toString().substring(7));
+      if (mimeType == null) 
+      { mimeType = "text/plain";
+      }
+    }
+    else
+    { // TODO: look up the MIME type through the pertinent connection
+      mimeType = HTTPTools.getMIMEType(url);
+    }
+    // TODO: make the identifier...
+    
+    return makeMETSFile(url, mimeType);
+  }
+
+  /**
+   *  Write the METS file in an XML to a text-output sink
+   *
+   *  @param <code>PrintWriter</code> the destination of the output
+   */
+  public void write(PrintWriter writer)
+  { String tag = XMLTools.getOpenTag("mets", "file");
+    tag = XMLTools.addAttribute(tag, "MIMETYPE", this.MIMEType);
+    tag = XMLTools.addAttribute(tag, "ID", this.id.toString());
+    writer.println(tag);
+    
+    tag = XMLTools.getOpenTag("mets", "FLocat");
+    tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
+    tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
+    tag = XMLTools.addAttribute(tag, "ID", this.id.toString());
+    tag = XMLTools.makeSingleton(tag);
+    writer.println(tag);
+    
+    writer.println(XMLTools.getCloseTag("mets", "file"));
+  }
+
+    
+  public boolean writeSQL(int groupReference, GS3SQLConnection connection)
+  { // check if this file is in the table already...
+    GS3SQLAction action;
+
+    GS3SQLSelect select = new GS3SQLSelect("files");
+    select.addField("*");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("FileGroupRef", "=", Integer.toString(groupReference),
+						    GS3SQLField.INTEGER_TYPE);
+    GS3SQLWhere  where  = new GS3SQLWhere(whereItem);
+    whereItem = new GS3SQLWhereItem("ID","=", this.id.toString());
+    where.add(whereItem);
+    select.setWhere(where);
+    connection.execute(select.toString());
+
+    // if not, then make an insert action
+    try {
+      ResultSet results = connection.getResultSet();
+      if (results == null ||
+	  !results.first())
+      { GS3SQLInsert insert = new GS3SQLInsert("files");
+
+        insert.addValue("FileGroupRef", Integer.toString(groupReference), GS3SQLField.INTEGER_TYPE);
+	insert.addValue("ID", this.id.toString());
+	
+	action = insert;
+	
+      }
+      else {
+	GS3SQLUpdate update = new GS3SQLUpdate("files");
+
+	update.setWhere(where);
+	action = update;
+      }
+    }
+    catch (SQLException ex)
+    { System.err.println(ex);
+      return false;
+    }
+    action.addValue("FileLocType", this.location.getType());
+    action.addValue("FileLocation", this.location.getLocation().toString());
+    action.addValue("MIMEType", this.MIMEType);
+
+    return connection.execute(action.toString());
+  }
+
+  public static METSFile readSQL(GS3SQLConnection connection, ResultSet parentSet)
+  { 
+    try {
+      String locType = parentSet.getString("FileLocType");
+      String location = parentSet.getString("FileLocation");
+      String mimeType = parentSet.getString("MIMEType");
+      String id = parentSet.getString("ID");
+
+      METSFileID metsID = new METSFileID(id);
+      METSFilePos metsFilePos = new METSFilePos(locType, location);
+      
+      METSFile reply = new METSFile(metsID, metsFilePos, mimeType);
+      return reply;
+    }
+    catch (SQLException ex)
+    { System.out.println(ex);
+    }
+    catch (java.net.MalformedURLException urlEx)
+    { System.out.println(urlEx);
+    }
+    return null;
+  }
+    
+  /**
+   *  Parse an XML Element as a METS File
+   */
+  public static METSFile parseXML(Element element, METSFileGroup parentGroup)
+  { METSFile file = null;
+    NodeList children = element.getChildNodes();
+		
+    for (int c = 0; c < children.getLength(); c ++)
+    { if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
+        continue;
+      }
+    
+      Element childElement = (Element) children.item(c);
+      if (childElement.getNodeName().equals("mets:FLocat"))
+      { METSFilePos filePos;
+    
+        // get most of the information from the child FLocat node
+        String locationType = childElement.getAttribute("LOCTYPE");
+	String href = childElement.getAttribute("xlink:href");
+	String id   = childElement.getAttribute("ID");
+      
+	// some more data from the parent node
+	String mimeType = element.getAttribute("MIMETYPE");
+
+	try 
+	{ filePos = new METSFilePos(href, locationType);
 	}
-
-	/**
-	 *  Set the parent group
-	 *
-	 *  @param <code>METSFileGroup</code> the new holding file group
-	 */
-	public void setGroup(METSFileGroup group)
-	{	this.group = group;
+	catch (java.net.MalformedURLException ex)
+	{ // TODO: raise error
+	  continue;
 	}
-
-	/**
-	 *  Get the parent group of this file
-	 *
-	 *  @return <code>METSFileGroup</code> the holding file group
-	 */
-	public METSFileGroup getGroup()
-	{	return this.group;
-	}
-
-	/**
-	 *  Get the identifier of this file
-	 *
-	 *  @return <code>METSFileID</code> the file identifier
-	 */
-	public METSFileID getID()
-	{	return this.id;
-	}
-
-	/**
-	 *  Set the identifier of this file
-	 *
-	 *  @param <code>METSFileID</code> the file identifier
-	 */
-	public void setID(METSFileID id)
-	{ this.id = id;
-	}
-
-	/**
-	 *  @return <code>String</code> the MIME (content) type of the file
-	 */
-	public String getMIMEType()
-	{	return this.MIMEType;
-	}
-
-	/**
-	 *  @return <code>URL</code> the location of the file.  This will often be in
-	 *          "file://" form.
-	 */
-	public URL getLocation()
-	{	return this.location.getLocation();
-	}
-
-	/**
-	 *  Take a url and make a METSFile object out of it - works out
-	 *  details such as the Mime type, identifiers and other necessary
-	 *  information to call the constructor for METSFile
-	 *
-	 *  @param <code>URL</code> the url of the object - this may be a 
-	 *                          reference to a file on the local filestore
-	 *
-	 *  @return <code>METSFile</code> the METS file object for the corresponding
-	 *                                document component.
-	 */
-	public static METSFile makeMETSFile(URL url, String mimeType)
-	{	
-		METSFile reply = new METSFile(new METSFileID(), new METSFilePos(url), mimeType);
-		return reply;
-	}
-		
-	public static METSFile makeMETSFile(URL url)
-	{ String mimeType;
-
-	  if (url.toString().startsWith("file://"))
-		{ // TODO: Work out the MIME type
-			mimeType = URLConnection.getFileNameMap().getContentTypeFor(url.toString().substring(7));
-			if (mimeType == null) 
-			{ mimeType = "text/plain";
-			}
-		}
-		else
-		{ // TODO: look up the MIME type through the pertinent connection
-			mimeType = HTTPTools.getMIMEType(url);
-		}
-		// TODO: make the identifier...
-
-		return makeMETSFile(url, mimeType);
-	}
-
-	/**
-	 *  Write the METS file in an XML to a text-output sink
-	 *
-	 *  @param <code>PrintWriter</code> the destination of the output
-	 */
-	public void write(PrintWriter writer)
-	{ String tag = XMLTools.getOpenTag("mets", "file");
-		tag = XMLTools.addAttribute(tag, "MIMETYPE", this.MIMEType);
-		tag = XMLTools.addAttribute(tag, "ID", this.id.toString());
-		writer.println(tag);
-
-		tag = XMLTools.getOpenTag("mets", "FLocat");
-		tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
-		tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
-		tag = XMLTools.addAttribute(tag, "ID", this.id.toString());
-		tag = XMLTools.makeSingleton(tag);
-		writer.println(tag);
-
-		writer.println(XMLTools.getCloseTag("mets", "file"));
-	}
-
-    
-    public void writeSQL(GS3SQLConnection connection)
-    { // check if this node is in the
-	GS3SQLInsert insert = new GS3SQLInsert("files");
-
-	insert.addValue("FileLocType", this.location.getType());
-	insert.addValue("FileLocation", this.location.getLocation().toString());
-	insert.addValue("MIMEType", this.MIMEType);
-	insert.addValue("ID", this.id.toString());
-
-	connection.execute(insert.toString());	
-    }
-    
-	/**
-	 *  Parse an XML Element as a METS File
-	 */
-	public static METSFile parseXML(Element element, METSFileGroup parentGroup)
-	{	METSFile file = null;
-		NodeList children = element.getChildNodes();
-		
-		for (int c = 0; c < children.getLength(); c ++)
-		{ if (children.item(c).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
-				continue;
-			}
-
-			Element childElement = (Element) children.item(c);
-			if (childElement.getNodeName().equals("mets:FLocat"))
-			{	METSFilePos filePos;
-
-				// get most of the information from the child FLocat node
-				String locationType = childElement.getAttribute("LOCTYPE");
-				String href = childElement.getAttribute("xlink:href");
-				String id   = childElement.getAttribute("ID");
-
-				// some more data from the parent node
-				String mimeType = element.getAttribute("MIMETYPE");
-
-				try 
-				{ filePos = new METSFilePos(href, locationType);
-				}
-				catch (java.net.MalformedURLException ex)
-				{ // TODO: raise error
-					continue;
-				}
-				file = new METSFile(new METSFileID(id), filePos, mimeType);
-			}
-			else if (childElement.getNodeName().equals("mets:FContent"))
-			{
-			}
-			else
-			{	// TODO: raise an error!
-			}
-		}
-		return file;
-	}
-
-
-	/**
-	 *  Overridden <code>toString</code> for convenience - returns the location of the file.
-	 *
-	 *  @return <code>String</code> the location of the file as a string
-	 */
-	public String toString()
-	{	return this.location.toString();
-	}
+	file = new METSFile(new METSFileID(id), filePos, mimeType);
+      }
+      else if (childElement.getNodeName().equals("mets:FContent"))
+      {
+      }
+      else
+      { // TODO: raise an error!
+      }
+    }
+    return file;
+  }
+
+
+  /**
+   *  Overridden <code>toString</code> for convenience - returns the location of the file.
+   *
+   *  @return <code>String</code> the location of the file as a string
+   */
+  public String toString()
+  { return this.location.toString();
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileGroup.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileGroup.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileGroup.java	(revision 5945)
@@ -5,4 +5,9 @@
 import java.util.Iterator;
 
+import java.net.URL;
+
+import java.sql.SQLException;
+import java.sql.ResultSet;
+
 import java.io.PrintWriter;
 
@@ -13,4 +18,8 @@
 import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
 
+/**
+ *  Child groups are indicated by colons.  E.g. Chapter1:Section1 would indicate
+ *  the group "Section1" inside the "Chapter1" group...
+ */
 
 public class METSFileGroup
@@ -19,4 +28,7 @@
   String id;
 
+  public static final String SECTION_PARENT = "Section";
+  public static final String GROUP_PARENT = "Group";
+
   public METSFileGroup(String id)
   { this.children = new ArrayList();
@@ -25,78 +37,140 @@
   }
 
-	/**
-	 *  Add a filegroup to this group of files.
-	 *
-	 *	@param <code>METSFileGroup</code> the filegroup.
-	 */
-	public void addGroup(METSFileGroup group)
-	{	this.childGroups.add(group);
-	}
-
-	/**
-	 *  Add a file to this group of files.
-	 *
-	 *	@param <code>METSFile</code> the file in a METS File object.
-	 */
-	public void addFile(METSFile file)
-	{	this.children.add(file);
-		file.setGroup(this);
-		if (!file.getID().isDefined())
-		{ file.setID(new METSFileID(this.id + Integer.toString(this.children.size())));
-		}
-	}
-
-	/**
-	 *  Get the nth child of the group
-	 *
-	 *  @param <code>int</code> the index into the group
-	 *  @return <code>METSFile</code> the corresponding child.  This may be <code>null</code>
-	 *          particularly if the index given falls outside of the valid range of child
-	 *          indexes.
-	 */
-	public METSFile getFile(int index)
-	{ if (index < 0 || index >= this.children.size())
-		{	return null;
-		}
-
-		return (METSFile) this.children.get(index);
-	}
-
-	/**
-	 *  Get all the files in the group as a <code>List</code>
-	 */
-	public List getFiles()
-	{	return this.children;
-	}
-
-	/**
-	 *  Get all the subgroups as a <code>List</code>
-	 */
-	public List getSubgroups()
-	{	return this.childGroups;
-	}
-
-	/**
-	 *  Get the number of files in the group
-	 *
-	 *  @return <code>int</code> the count
-	 */
-	public int noOfFiles()
-	{	return this.children.size();
-	}
-
-	/**
-	 *  Get the number of subgroups.
-	 */
-	public int noOfSubgroups()
-	{	return this.childGroups.size();
-	}
-
-	/**
-	 *  @return <code>String</code> the name of this group
-	 */
-	public String getName()
-	{	return this.id;
-	}
+  /**
+   *  Find all the occurrences of a given file, and place them
+   *  in a <code>List</code>.
+   */
+  public void findGroups(URL findFile, List resultList)
+  { 
+    // find in this particular group
+    Iterator childIter = children.iterator();
+    while (childIter.hasNext())
+    { METSFile file = (METSFile) childIter.next();
+      if (file.equals(findFile))
+      { resultList.add(this.id);
+      }
+    }
+
+    // iterate over the child groups
+    childIter = childGroups.iterator();
+    while (childIter.hasNext())
+    { METSFileGroup fileGroup = (METSFileGroup) childIter.next();
+
+      fileGroup.findGroups(findFile, resultList);
+    }
+  }
+
+  /**
+   *  Get a sub group of this METSFileGroup.
+   *
+   *  @param <code>String</code> the name of the subgroup
+   *  @return <code>METSFileGroup</code> the child group, which will
+   *          be <code>null</code> if the group is not known.
+   */
+  public METSFileGroup getSubgroup(String id)
+  { String childId;
+  
+    int dotAt = id.indexOf(':');
+    if (dotAt == -1)
+    { childId = null;
+    }
+    else
+    { childId = id.substring(dotAt+1);
+      id = id.substring(0, dotAt);
+    }
+    
+    // iterate over the child groups
+    Iterator childIter = childGroups.iterator();
+    while (childIter.hasNext())
+    { METSFileGroup group = (METSFileGroup) childIter.next();
+    
+      if (group.id.equals(id)) {
+	if (childId == null) {
+	  return group;
+	}
+	else {
+	  return group.getSubgroup(childId);
+	}
+      }
+    }
+    return null;
+  }
+
+  /**
+   *  Add a filegroup to this group of files.
+   *
+   *	@param <code>METSFileGroup</code> the filegroup.
+   */
+  public void addGroup(METSFileGroup group)
+  { this.childGroups.add(group);
+  }
+
+  /**
+   *  Add a file to this group of files.
+   *
+   *	@param <code>METSFile</code> the file in a METS File object.
+   */
+  public void addFile(METSFile file)
+  { this.children.add(file);
+    file.setGroup(this);
+    if (!file.getID().isDefined())
+    { file.setID(new METSFileID(this.id + Integer.toString(this.children.size())));
+    }
+  }
+
+  /**
+   *  Get the nth child of the group
+   *
+   *  @param <code>int</code> the index into the group
+   *  @return <code>METSFile</code> the corresponding child.  This may be <code>null</code>
+   *          particularly if the index given falls outside of the valid range of child
+   *          indexes.
+   */
+  public METSFile getFile(int index)
+  { if (index < 0 || index >= this.children.size())
+    { return null;
+    }
+  
+    return (METSFile) this.children.get(index);
+  }
+
+  /**
+   *  Get all the files in the group as a <code>List</code>
+   *
+   *  @return <code>List</code> the file childen of the group.
+   */
+  public List getFiles()
+  { return this.children;
+  }
+
+  /**
+   *  Get all the subgroups as a <code>List</code>
+   */
+  public List getSubgroups()
+  { return this.childGroups;
+  }
+
+  /**
+   *  Get the number of files in the group
+   *
+   *  @return <code>int</code> the count
+   */
+  public int noOfFiles()
+  { return this.children.size();
+  }
+
+  /**
+   *  Get the number of subgroups.
+   */
+  public int noOfSubgroups()
+  { return this.childGroups.size();
+  }
+
+  /**
+   *  @return <code>String</code> the name of this group
+   */
+  public String getName()
+  { return this.id;
+  }
 
   /**
@@ -118,6 +192,9 @@
   }
 
-  public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
-  { // check if this node is in the
+  public boolean writeSQL(DocumentInterface document, String parentRef, boolean parentIsSection, 
+			  GS3SQLConnection connection)
+  { int sqlId = -1;
+
+    // check if this node is in the database already
     GS3SQLSelect select = new GS3SQLSelect("filegroups");
     select.addField("*");
@@ -128,21 +205,135 @@
     select.setWhere(where);
 
-    System.out.println(select.toString());
     connection.execute(select.toString());
 
-    GS3SQLInsert insert = new GS3SQLInsert("filegroups");
-    insert.addValue("DocID", document.getID().toString());
-    insert.addValue("FileGroupID", this.id);
-    insert.addValue("ParentGroup", "");
-    System.out.println("filegroup done");
-    connection.execute(insert.toString());
+    ResultSet selectResult = connection.getResultSet();
+
+    try {
+      if (selectResult == null ||
+	  !selectResult.first()) {
+	GS3SQLInsert insert = new GS3SQLInsert("filegroups");
+
+	insert.addValue("DocID", document.getID().toString());
+	insert.addValue("FileGroupID", this.id);
+	insert.addValue("ParentRef", parentRef, GS3SQLField.INTEGER_TYPE);
+	insert.addValue("ParentType", parentIsSection ? SECTION_PARENT : GROUP_PARENT);
+	
+	if (!connection.execute(insert.toString())) {
+	  return false;
+	}
+      }
+      else {
+	// TODO: update the data for this file group...
+      }
+    }
+    catch (SQLException ex)
+    { System.err.println(ex);
+      return false;
+    }
 		
-    System.out.println("filegroup done");
-
-    Iterator childIter = children.iterator();
+    // get the filegroup reference now
+    connection.execute(select.toString());
+    
+    try {
+      ResultSet results = connection.getResultSet();
+      if (results == null) {
+	return false;
+      }
+      results.first();
+      sqlId = results.getInt("FileGroupRef");
+    }
+    catch (SQLException sqlex) {
+      System.out.println(sqlex);
+      return false;
+    }
+
+    // iterate over the child groups
+    Iterator childIter = childGroups.iterator();
+    while (childIter.hasNext())
+    { METSFileGroup fileGroup = (METSFileGroup) childIter.next();
+
+      if (!fileGroup.writeSQL(document, Integer.toString(sqlId), false, connection))
+      { return false;
+      }
+    }
+
+    // iterate over the child files
+    childIter = children.iterator();
     while (childIter.hasNext())
     { METSFile file = (METSFile) childIter.next();
-      file.writeSQL(connection);
-    }
+    
+      if (!file.writeSQL(sqlId, connection))
+      { return false;
+      }
+    }
+
+    return true;
+  }
+
+  public static METSFileGroup readSQL(DocumentInterface document, GS3SQLConnection connection,
+				      ResultSet resultSet)
+  {
+    try {
+      String ID         = resultSet.getString("FileGroupID");
+      String parentType = resultSet.getString("ParentType");
+      String parentRef  = resultSet.getString("ParentRef");
+
+      // create the metadata block object
+      METSFileGroup group = new METSFileGroup(ID);
+      
+      // get its metadata reference to retrieve divisions
+      int groupRef = resultSet.getInt("FileGroupRef");
+
+      // query the database for matching groups which are children of this one
+      GS3SQLSelect select = new GS3SQLSelect("filegroups");
+      select.addField("*");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(groupRef),
+						      GS3SQLField.INTEGER_TYPE);
+      GS3SQLWhere where = new GS3SQLWhere(whereItem);
+      whereItem = new GS3SQLWhereItem("ParentType", "=", METSFileGroup.GROUP_PARENT);
+      where.add(whereItem);
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+
+      // parse through the child groups
+      ResultSet childSet = connection.getResultSet();
+      if (childSet.first()) {
+	do {
+	  METSFileGroup fileGroup = METSFileGroup.readSQL(document, connection, childSet);
+	  if (fileGroup != null) {
+	    group.addGroup(fileGroup);
+	  }
+	}
+	while (childSet.next());
+      }
+
+      // now scan for file members
+      select = new GS3SQLSelect("files");
+      select.addField("*");
+      whereItem = new GS3SQLWhereItem("FileGroupRef", "=", Integer.toString(groupRef),
+				      GS3SQLField.INTEGER_TYPE);
+      where = new GS3SQLWhere(whereItem);
+      select.setWhere(where);
+      connection.execute(select.toString());
+
+      ResultSet childFileSet = connection.getResultSet();
+      if (childFileSet != null && childFileSet.first()) {
+	do {
+	  METSFile file = METSFile.readSQL(connection, childFileSet);
+	  if (file != null) {
+	    group.addFile(file);
+	  }
+	}
+	while (childFileSet.next());
+      }
+
+      return group;
+    }
+    catch (SQLException sqlEx)
+    { System.out.println(sqlEx);
+      System.exit(1);
+    }
+    return null;
   }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFilePos.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFilePos.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFilePos.java	(revision 5945)
@@ -6,28 +6,32 @@
 public class METSFilePos
 {
-	METSLocation location;
+  METSLocation location;
 
-	public METSFilePos(File file) throws java.net.MalformedURLException
-	{	this.location = new METSLocation(file);
-	}
+  public METSFilePos(File file) throws java.net.MalformedURLException
+  { this.location = new METSLocation(file);
+  }
 
-	public METSFilePos(URL url)
-	{	this.location = new METSLocation(url);
-	}
+  public METSFilePos(URL url)
+  { this.location = new METSLocation(url);
+  }
 
-	public METSFilePos(String location, String locationType) throws java.net.MalformedURLException
-	{	this.location = new METSLocation(location, locationType);
-	}
+  public METSFilePos(String locationType, String location) throws java.net.MalformedURLException
+  { this.location = new METSLocation(locationType, location);
+  }
+  
+  public URL getLocation()
+  { return this.location.getLocation();
+  }
 
-	public URL getLocation()
-	{	return this.location.getLocation();
-	}
+  public String getType()
+  { return this.location.getType();
+  }
 
-	public String getType()
-	{	return this.location.getType();
-	}
+  public String toString()
+  { return this.location.getLocation().toString();
+  }
 
-	public String toString()
-	{	return this.location.getLocation().toString();
-	}
+  public boolean equals(URL filePos)
+  { return this.location.equals(filePos);
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileSet.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileSet.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSFileSet.java	(revision 5945)
@@ -8,8 +8,14 @@
 import java.util.Map;
 import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.Iterator;
 
 import java.io.File;
 import java.io.PrintWriter;
+
+import java.sql.SQLException;
+import java.sql.ResultSet;
+
 import java.net.URL;
 
@@ -20,11 +26,20 @@
 
 public class METSFileSet
-{ Map fileGroups;
+{ Map    fileGroups;
+  String reference;
 
   public METSFileSet()
   { this.fileGroups = new HashMap();
     this.fileGroups.put("default", new METSFileGroup("default"));
-  }
-
+    this.reference = null;
+  }
+  
+  /**
+   *  Get the group that corresponds to the given name...
+   *
+   *  @param <code>String</code> the name of the group.
+   *  @return <code>METSFileGroup</code> the group object - this will be
+   *          <code>null</code> if the group is not found
+   */
   public METSFileGroup getGroup(String name)
   { if (!this.fileGroups.containsKey(name))
@@ -34,4 +49,10 @@
   }
 
+  /**
+   *  Get the Nth file from the default group...
+   *
+   *  @param <code>int</code> the index into the default group to use...
+   *  @return <code>METSFile</code> the file.
+   */
   public METSFile getFile(int index)
   { METSFileGroup group = this.getGroup("default");
@@ -70,6 +91,30 @@
   }
 
+  /**
+   *  Add a group at the top level of the METS File set.
+   *
+   *  @param <code>METSFileGroup</code> the file group to add.
+   */
   public void addGroup(METSFileGroup group)
   { this.fileGroups.put(group.getName(), group);
+  }
+
+  /**
+   *  Get all the groups that contain a given URL/file.
+   *
+   *  @param <code>URL</code> the location of the file.
+   *  @return <code>List</code> the list of group references that contain the file.
+   */
+  public List findGroups(URL file)
+  { List resultList = new ArrayList();
+
+    Iterator groups = this.fileGroups.values().iterator();
+
+    while (groups.hasNext())
+    { METSFileGroup group = (METSFileGroup) groups.next();
+      
+      group.findGroups(file, resultList);
+    }
+    return resultList;
   }
 
@@ -86,18 +131,109 @@
   }
 
-  public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
+  public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
   { Iterator groups = this.fileGroups.values().iterator();
 
-    GS3SQLInsert insert = new GS3SQLInsert("filesection");
-    insert.addValue("DocID", document.getID().toString());
-    insert.addValue("FileSecID", "test"); // TODO: remove magic string
-
-    connection.execute(insert.toString());
+    // write the set if the reference does not already exist...
+    if (this.reference == null)
+    { // Insert the file section into the database
+      GS3SQLInsert insert = new GS3SQLInsert("filesection");
+      insert.addValue("DocID", document.getID().toString());
+      insert.addValue("FileSecID", "test"); // TODO: remove magic string
+
+      if (!connection.execute(insert.toString()))
+      { return false;
+      }
+
+      // find the file section number
+      GS3SQLSelect select = new GS3SQLSelect("filesection");
+      select.addField("*");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("FileSecID", "=", "test");
+      GS3SQLWhereItem whereDoc  = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+      GS3SQLWhere where = new GS3SQLWhere(whereItem);
+      where.add(whereDoc);
+      select.setWhere(where);
+
+      try {
+	connection.execute(select.toString());
+	
+	ResultSet set = connection.getResultSet();
+	set.first();
+	int sectionRef = set.getInt("FileSectionRef");
+
+	this.reference = Integer.toString(sectionRef);
+      }
+      catch (SQLException ex)
+      { System.out.println(ex);
+        return false;
+      }
+    }
     
+    // write out the children
     while (groups.hasNext())
     { METSFileGroup group = (METSFileGroup) groups.next();
-
-      group.writeSQL(document, connection);
-    }
-  }
+      
+      if (!group.writeSQL(document, this.reference, true, connection))
+      { return false;
+      }
+    }
+
+    return true;
+  }
+
+  public static METSFileSet readSQL(DocumentInterface document, GS3SQLConnection connection)
+  { 
+    METSFileSet set = new METSFileSet();    
+
+    // Get file sections from the filesection table (currently redundant)
+    GS3SQLSelect select = new GS3SQLSelect("filesection");
+    select.addField("*");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+    select.setWhere(new GS3SQLWhere(whereItem));
+    connection.execute(select.toString());
+    
+    // Get the identifier for this file set, etc.
+    ResultSet sections = connection.getResultSet();
+    int fileSetRef;
+    try {
+      sections.first();
+      fileSetRef     = sections.getInt("FileSectionRef");
+      set.reference = Integer.toString(fileSetRef);
+    }
+    catch (SQLException ex)
+    { System.out.println(ex);
+      return null;
+    }
+    
+    // Get child file groups
+    select = new GS3SQLSelect("filegroups");
+    select.addField("*");
+    whereItem = new GS3SQLWhereItem("DocID", "=", document.getID().toString());    
+    GS3SQLWhere where = new GS3SQLWhere(whereItem);
+    whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(fileSetRef), 
+				    GS3SQLField.INTEGER_TYPE);
+    where.add(whereItem);
+    whereItem = new GS3SQLWhereItem("ParentType", "=", METSFileGroup.SECTION_PARENT);
+    where.add(whereItem);
+    select.setWhere(where);
+    connection.execute(select.toString());
+
+    // start going through the matching file groups
+    try {
+      ResultSet resultSet = connection.getResultSet();
+      resultSet.first();
+      do {
+	METSFileGroup filegroup = METSFileGroup.readSQL(document, connection, resultSet);
+	if (filegroup != null) {
+	  set.addGroup(filegroup);
+	}
+      } while (resultSet.next());
+    }
+    catch (SQLException sqlEx) {
+      System.out.println(sqlEx);
+      System.exit(1);
+    }
+
+    return set;
+  }
+
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSLocation.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSLocation.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSLocation.java	(revision 5945)
@@ -6,28 +6,32 @@
 public class METSLocation
 {
-	String type;
-	URL    location;
+  String type;
+  URL    location;
 
-	public METSLocation(String type, String location) throws java.net.MalformedURLException
-	{	this.type = type;
-	 	this.location = new URL(location);
-	}
+  public METSLocation(String type, String location) throws java.net.MalformedURLException
+  { this.type = type;
+    this.location = new URL(location);
+  }
 
-	public METSLocation(URL url)
-	{	this.type = "URL";
-		this.location = url;
-	}
+  public METSLocation(URL url)
+  { this.type = "URL";
+    this.location = url;
+  }
 
-	public METSLocation(File file) throws java.net.MalformedURLException
-	{ this.type = "URL";
-		this.location = new URL("file://" + file.toString());
-	}
+  public METSLocation(File file) throws java.net.MalformedURLException
+  { this.type = "URL";
+    this.location = new URL("file://" + file.toString());
+  }
 
-	public URL getLocation()
-	{	return this.location;
-	}
+  public boolean equals(URL url)
+  { return this.location.equals(url);
+  }
 
-	public String getType()
-	{	return this.type;
-	}
+  public URL getLocation()
+  { return this.location;
+  }
+
+  public String getType()
+  { return this.type;
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSNamespace.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSNamespace.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSNamespace.java	(revision 5945)
@@ -4,4 +4,7 @@
 
 import java.util.List;
+
+import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.greenstone.gsdl3.gs3build.util.GS3SQLConnection;
@@ -36,48 +39,48 @@
   }
 
-	/**
-	 *  Get the name of the namespace...
-	 *
-	 *  @return <code>String</code> the name of the namespace
-	 */
-	public String getName()
-	{	return this.name;
-	}
-
-	/**
-	 *  Get the group of namespaces to which this namespace belongs.
-	 *
-	 *  @return <code>String</code> the name of the namespace group
-	 */
-	public String getGroup()
-	{	return this.group;
-	}
+  /**
+   *  Get the name of the namespace...
+   *
+   *  @return <code>String</code> the name of the namespace
+   */
+  public String getName()
+  { return this.name;
+  }
+
+  /**
+   *  Get the group of namespaces to which this namespace belongs.
+   *
+   *  @return <code>String</code> the name of the namespace group
+   */
+  public String getGroup()
+  { return this.group;
+  }
 	
-	/**
-	 *  Set the group of namespaces to which this namespace belongs.
-	 *
-	 *  @param <code>String</code> the name of the namespace group
-	 */
-	public void setGroup(String group)
-	{	this.group = group;
-	}
-
-	/**
-	 *  Get the ID for this namespace.
-	 *
-	 *  @return <code>String</code> the id of the namespace
-	 */
-	public String getID()
-	{ return this.id;
-	}
-
-	/**
-	 *  Set the id of this namespace.
-	 *
-	 *  @param <code>String</code> the name of the namespace group
-	 */
-	public void setID(String id)
-	{	this.id = id;
-	}
+  /**
+   *  Set the group of namespaces to which this namespace belongs.
+   *
+   *  @param <code>String</code> the name of the namespace group
+   */
+  public void setGroup(String group)
+  { this.group = group;
+  }
+
+  /**
+   *  Get the ID for this namespace.
+   *
+   *  @return <code>String</code> the id of the namespace
+   */
+  public String getID()
+  { return this.id;
+  }
+
+  /**
+   *  Set the id of this namespace.
+   *
+   *  @param <code>String</code> the name of the namespace group
+   */
+  public void setID(String id)
+  { this.id = id;
+  }
 
   /**
@@ -107,24 +110,108 @@
   public boolean writeSQL(int parentId, GS3SQLConnection connection)
   { 
-    GS3SQLInsert insert = new GS3SQLInsert("namespaces");
-
+    GS3SQLAction action;
+
+    // If the namespace is not null, then set it...
     if (this.id != null) {
-	insert.addValue("NamespaceID", this.id);
+      // use an update action in this case...
+      GS3SQLUpdate update = new GS3SQLUpdate("namespaces");
+      update.addValue("NamespaceID", this.id);
+
+      // set up the where clause
+      GS3SQLWhere where = 
+	new GS3SQLWhere(new GS3SQLWhereItem("NamespaceRef", "=", this.id, 
+					    GS3SQLField.INTEGER_TYPE));
+      update.setWhere(where);
+      action = update;
+    }
+    else {
+      GS3SQLInsert insert = new GS3SQLInsert("namespaces");
+      action = insert;
     }
 
     if (this.location != null) {
-      insert.addValue("fileLoc", this.location.getLocation().toString());
-      insert.addValue("fileType", "URL");
+      action.addValue("fileLoc", this.location.getLocation().toString());
+      action.addValue("fileType", "URL");
     }
     else {
       // no location stuff
     }
-    insert.addValue("MetadataRef", Integer.toString(parentId), GS3SQLField.INTEGER_TYPE);
-    insert.addValue("NamespaceType", this.name);
-
-    //    System.out.println(insert.toString());
-    connection.execute(insert.toString());
+    action.addValue("MetadataRef", Integer.toString(parentId), GS3SQLField.INTEGER_TYPE);
+    action.addValue("NamespaceType", this.name);
+
+    // Execute the action
+    connection.execute(action.toString());
+
+    // then get the namespace reference number if needsbe...
+    if (this.id == null) {
+      GS3SQLSelect select = new GS3SQLSelect("namespaces");
+      select.addField("NamespaceRef");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(parentId), GS3SQLField.INTEGER_TYPE);
+      GS3SQLWhere where = new GS3SQLWhere(whereItem);
+      whereItem = new GS3SQLWhereItem("NamespaceType", "=", this.name);
+      where.add(where);
+      try {
+	connection.execute(select.toString());
+      
+	ResultSet result = connection.getResultSet();
+	result.last();
+	this.id = Integer.toString(result.getInt("NamespaceRef"));
+      }
+      catch (SQLException sqlex)
+      { this.id = null;
+        System.err.println(sqlex);
+	return false;
+      }
+    }
 
     return true;
   }
+
+  public static METSNamespace readSQL(GS3SQLConnection connection, ResultSet resultSet)
+  {
+    METSLocation metsLocation = null;
+    
+    try {
+      String name = resultSet.getString("NamespaceType");
+      String id = resultSet.getString("NamespaceRef");
+      String location = resultSet.getString("fileLoc");
+      String type = resultSet.getString("fileType");
+      if (location != null && type != null) {
+	metsLocation = new METSLocation(type, location);
+      }
+
+      METSNamespace namespace = NamespaceFactory.initNamespace(name, metsLocation);
+      namespace.id = id;
+
+      int namespaceRef = resultSet.getInt("NamespaceRef");
+      
+      GS3SQLSelect select = new GS3SQLSelect("mdvalues");
+      select.addField("*");
+      GS3SQLWhere where = new GS3SQLWhere(new GS3SQLWhereItem("NamespaceRef", "=", Integer.toString(namespaceRef),
+							      GS3SQLField.INTEGER_TYPE));
+      select.setWhere(where);
+
+      connection.execute(select.toString());
+      
+      ResultSet valuesSet = connection.getResultSet();
+      if (valuesSet != null && valuesSet.first()) {
+	do {
+	  String label = valuesSet.getString("label");
+	  String value = valuesSet.getString("value");
+
+	  namespace.addMetadata(label, value);
+	}
+	while (valuesSet.next());
+      }
+
+      return namespace;
+    }
+    catch (java.net.MalformedURLException urlEx)
+    { System.out.println(urlEx);
+    }
+    catch (SQLException sqlEx)
+    { System.out.println(sqlEx);
+    }    
+    return null;
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructure.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructure.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructure.java	(revision 5945)
@@ -10,4 +10,5 @@
 
 import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
@@ -19,112 +20,245 @@
 public class METSStructure
 {
-	Map children;
-	String ID;
-	String label;
-	String type;
-
-	public METSStructure(String id, String label, String type)
-	{	this.children = new HashMap();
-		this.ID       = id;
-		this.label    = label;
-		this.type     = type;
-	}
-
-	public String getID()
-	{	return this.ID;
-	}
-
-	public void addDivision(METSDivision division)
-	{	this.children.put(division.getID(), division);
-	}
-
-	public void addSubDivision(String divisionID, METSDivision division)
-	{	String topDivision = METSDivision.getTopDivisionName(divisionID);
-
-		METSDivision child = (METSDivision) this.children.get(topDivision);
-		if (child == null)
-		{	return;
-		}
-
-		String subDivisionID = METSDivision.getSubDivisionName(divisionID);
-		if (subDivisionID == null)
-		{ child.addSubDivision(division);
-		}
-		else
-		{	child.addSubDivision(subDivisionID, division);
-		}
-	}
-
-	public METSDivision getDivision(String divisionID)
-	{	String topDivision = METSDivision.getTopDivisionName(divisionID);
-
-		METSDivision child = (METSDivision) this.children.get(topDivision);
-		if (child == null)
-		{	return null;
-		}
-
-		String subDivision = METSDivision.getSubDivisionName(divisionID);
-		if (subDivision != null)
-		{	child = child.getDivision(subDivision);
-		}
-
-		return child;
-	}
-
-	public void write(PrintWriter writer)
-	{ Iterator groups = this.children.values().iterator();
-
-		String tag = XMLTools.getOpenTag("mets", "structMap");
-		tag = XMLTools.addAttribute(tag, "ID", this.ID.toString());
-		tag = XMLTools.addAttribute(tag, "TYPE", this.type.toString());
-		tag = XMLTools.addAttribute(tag, "LABEL", this.label.toString());
+  Map children;
+  String ID;
+  String label;
+  String type;
+  
+  public METSStructure(String id, String label, String type)
+  { this.children = new HashMap();
+    this.ID       = id;
+    this.label    = label;
+    this.type     = type;
+  }
+  
+  /**
+   *  Get the identifer of this structure
+   *
+   *  @param <code>String</code> the identifier.
+   */
+  public String getID()
+  { return this.ID;
+  }
+
+  /**
+   *  Find all the divisions that match a given list of file group
+   *  identifiers...
+   *
+   *  @param <code>List</code> the list of identifiers to find
+   *  @param <code>List</code> the list into which to place any
+   *         matching identifiers.
+   */
+  public void findDivisionsForFiles(List listOfFileIdentifiers, List resultList)
+  { Iterator groups = this.children.values().iterator();
+    while (groups.hasNext())
+    { METSDivision group = (METSDivision) groups.next();
+
+      group.findDivisionsForFiles(listOfFileIdentifiers, resultList);
+    }    
+  }
+
+  /**
+   *  Add a division directly underneath this structure.
+   *
+   *  @param <code>METSDivision</code> the division to add.
+   */
+  public void addDivision(METSDivision division)
+  { this.children.put(division.getID(), division);
+  }
+
+  /**
+   *  Add a division further into this structure.
+   *
+   *  @param <code>String</code> the identifier for the division
+   *         within which the division is to be added.
+   *  @param <code>METSDivision</code> the division to add.   
+   */
+  public void addSubDivision(String divisionID, METSDivision division)
+  { String topDivision = METSDivision.getTopDivisionName(divisionID);
+
+    METSDivision child = (METSDivision) this.children.get(topDivision);
+    if (child == null)
+    { return;
+    }
+
+    String subDivisionID = METSDivision.getSubDivisionName(divisionID);
+    if (subDivisionID == null)
+    { child.addSubDivision(division);
+    }
+    else
+    { child.addSubDivision(subDivisionID, division);
+    }
+  }
+
+  /**
+   *  Get a subdivision of a given identifier...
+   * 
+   *  @param <code>String</code> the identifier of the division
+   *  @return <code>METSDivision</code> the division, which will be
+   *          <code>null</code> if it is not found.
+   */
+  public METSDivision getDivision(String divisionID)
+  { String topDivision = METSDivision.getTopDivisionName(divisionID);
+
+    METSDivision child = (METSDivision) this.children.get(topDivision);
+    if (child == null)
+    { return null;
+    }
+
+    String subDivision = METSDivision.getSubDivisionName(divisionID);
+    if (subDivision != null)
+    { child = child.getDivision(subDivision);
+    }
+
+    return child;
+  }
+
+  public void write(PrintWriter writer)
+  { Iterator groups = this.children.values().iterator();
+
+    String tag = XMLTools.getOpenTag("mets", "structMap");
+    tag = XMLTools.addAttribute(tag, "ID", this.ID.toString());
+    tag = XMLTools.addAttribute(tag, "TYPE", this.type);
+    tag = XMLTools.addAttribute(tag, "LABEL", this.label);
 		
-		writer.println(tag);
-		while (groups.hasNext())
-		{	METSDivision group = (METSDivision) groups.next();
-
-			group.write(writer);
-		}
-		writer.println("</mets:structMap>");
-	}
-
-
-    public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
-    { Iterator groups = this.children.values().iterator();
-
+    writer.println(tag);
+    while (groups.hasNext())
+    { METSDivision group = (METSDivision) groups.next();
+
+      group.write(writer);
+    }
+    writer.println("</mets:structMap>");
+  }
+
+
+  /**
+   *  Write this METSStructure to an SQL database....
+   *
+   *  @param <code>DocumentInterface</code> the enclosing document.
+   *  @param <code>GS3SQLConnection</code> the SQL database connection.
+   */
+  public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
+  { int sqlRef = -1;
+    ResultSet results;
+
+    // Prepare query to see if this structure has already been written
+    GS3SQLSelect select = new GS3SQLSelect("structure");
+    select.addField("StructureRef");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+    GS3SQLWhereItem item = new GS3SQLWhereItem("StructureID", "=", this.ID.toString());
+    GS3SQLWhere where = new GS3SQLWhere(whereItem);
+    where.add(item);
+    select.setWhere(where);
+
+    // attempt to execute the query & get the current structure's reference
+    try {
+      connection.execute(select.toString());
+      results = connection.getResultSet();
+      if (results != null &&
+	  results.first())
+      { sqlRef = results.getInt("structureRef");
+      }
+      else 
+      { results = null;
+      }
+    }
+    catch (SQLException sqlEx) {
+      System.err.print(sqlEx);
+      return false;
+    }
+
+    // insert a new structure if it wasn't there previously
+    if (results == null) {
       GS3SQLInsert insert = new GS3SQLInsert("structure");
       insert.addValue("DocID", document.getID().toString());
       insert.addValue("StructureID", this.ID.toString());
-      insert.addValue("Type", this.type.toString());
-      insert.addValue("Label", this.label.toString());
+      insert.addValue("Type", this.type);
+      insert.addValue("Label", this.label);
       
-      System.out.println(insert.toString());
-      connection.execute(insert.toString());
+      if (!connection.execute(insert.toString())) {
+	return false;
+      }
+
+      // get the new structure reference by re-running the original select object
+      connection.execute(select.toString());
+
+      try {
+	results = connection.getResultSet();
+	results.first();
+	sqlRef = results.getInt("StructureRef");
+      }
+      catch (SQLException sql) {
+	System.err.println(sql);
+	return false;
+      }
+    }
+    else {
+      GS3SQLUpdate update = new GS3SQLUpdate("structure");
+      update.setWhere(where);
+
+      update.addValue("Type", this.type);
+      update.addValue("Label", this.label);
+
+      connection.execute(update.toString());
+    }
       
-      // get the new structure reference
-      GS3SQLSelect select = new GS3SQLSelect("structure");
-      select.addField("StructureRef");
-      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("StructureID", "=", this.ID);
-      GS3SQLWhereItem item = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+    // write out the child groups (Divisions) now...    
+    Iterator groups = this.children.values().iterator();
+
+    while (groups.hasNext())
+    { METSDivision group = (METSDivision) groups.next();
+
+      if (!group.writeSQL(sqlRef, true, connection))
+      { return false;
+      }
+    }
+    return true;
+  }
+
+
+  public static METSStructure readSQL(DocumentInterface document, GS3SQLConnection connection,
+				      ResultSet resultSet)
+  {
+    try {
+      String ID    = resultSet.getString("StructureID");
+      String type  = resultSet.getString("Type");
+      String label = resultSet.getString("Label");
+
+      // create the metadata block object
+      METSStructure structure = new METSStructure(ID, label, type);
+      
+      // get its metadata reference to retrieve divisions
+      int structureRef = resultSet.getInt("StructureRef");
+
+      // query the database for matching division for this structure block
+      GS3SQLSelect select = new GS3SQLSelect("divisions");
+      select.addField("*");
+      GS3SQLWhereItem whereItem = new GS3SQLWhereItem("ParentRef", "=", Integer.toString(structureRef),
+						      GS3SQLField.INTEGER_TYPE);
       GS3SQLWhere where = new GS3SQLWhere(whereItem);
-      where.add(item);
+      whereItem = new GS3SQLWhereItem("ParentType", "=", METSDivision.STRUCTURE_PARENT);
+      where.add(whereItem);
       select.setWhere(where);
-      System.out.println(select.toString());
+
       connection.execute(select.toString());
 
-      try {
-        // read in the structure reference
-        connection.getResultSet().first();
-	int sqlRef = connection.getResultSet().getInt("StructureRef");
-        
-	while (groups.hasNext())
-	{ METSDivision group = (METSDivision) groups.next();
-
-          group.writeSQL(sqlRef, true, connection);
+      // parse through the divisions
+      ResultSet divisionSet = connection.getResultSet();
+      divisionSet.first();
+      do {
+	METSDivision division = METSDivision.readSQL(connection, divisionSet);
+	if (division != null) {
+	  structure.addDivision(division);
 	}
       }
-      catch (SQLException sql) {
-	  System.out.println(sql);
-      }
-    }
+      while (divisionSet.next());
+
+      return structure;
+    }
+    catch (SQLException sqlEx)
+    { System.out.println(sqlEx);
+      System.exit(1);
+    }
+    return null;
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructureSet.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructureSet.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/METSStructureSet.java	(revision 5945)
@@ -5,69 +5,141 @@
 import java.util.HashMap;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.Iterator;
+
+import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.greenstone.gsdl3.gs3build.doctypes.DocumentInterface;
 
 import org.greenstone.gsdl3.gs3build.util.GS3SQLConnection;
+import org.greenstone.gsdl3.gs3build.database.*;
 
 public class METSStructureSet
-{	Map children;
+{ Map children;
 
-	public METSStructureSet()
-	{	this.children = new HashMap();
-	}
+  public METSStructureSet()
+  { this.children = new HashMap();
+  }
 
-	public void addStructure(METSStructure structure)
-	{	this.children.put(structure.getID(), structure);
-	}
+  public void addStructure(METSStructure structure)
+  { this.children.put(structure.getID(), structure);
+  }
 
-	public METSStructure getStructure(String name)
-	{	return (METSStructure) this.children.get(name);
-	}
+  public METSStructure getStructure(String name)
+  { return (METSStructure) this.children.get(name);
+  }
 
-	public void addDivision(String structureName, METSDivision division)
-	{	METSStructure structure = (METSStructure) this.children.get(structureName);
+  /**
+   *  Find the divisions that contain a list of given files
+   *
+   *  @param <code>List</code> the list of files to find...
+   *  @return <code>List</code> the matching divisions.
+   */
+  public List findDivisionsForFiles(List listOfFileIdentifiers)
+  { List reply = new ArrayList();
 
-		if (structure != null)
-		{ structure.addDivision(division);
-		}
-	}
+    // iterate across all the children...
+    Iterator structures = this.children.values().iterator();
+    
+    while (structures.hasNext())
+    { METSStructure structure = (METSStructure) structures.next();
 
-	public void addSubDivision(String structureName, String divisionID, METSDivision division)
-	{	METSStructure structure = (METSStructure) this.children.get(structureName);
+      structure.findDivisionsForFiles(listOfFileIdentifiers, reply);      
+    }    
+    return reply;
+  }
 
-		if (structure != null)
-		{ structure.addSubDivision(divisionID, division);
-		}
-	}
+  /**
+   *  Add a division to an indicated structure.
+   *
+   *  @param <code>String</code> the structure identifier
+   *  @param <code>METSDivision</code> the division to be added.
+   */
+  public void addDivision(String structureName, METSDivision division)
+  { METSStructure structure = (METSStructure) this.children.get(structureName);
 
-	public METSDivision getDivision(String structureName, String divisionID)
-	{	METSStructure structure = (METSStructure) this.children.get(structureName);
-
-		if (structure != null)
-		{ return structure.getDivision(divisionID);
-		}
-		return null;
-	}
-
-	public void write(PrintWriter writer)
-	{ Iterator groups = this.children.values().iterator();
-
-		while (groups.hasNext())
-		{	METSStructure group = (METSStructure) groups.next();
-
-			group.write(writer);
-		}
-	}
-
-  public void writeSQL(DocumentInterface document, GS3SQLConnection connection)
-  { Iterator groups = this.children.values().iterator();
-    
-    while (groups.hasNext())
-    { METSStructure group = (METSStructure) groups.next();
-
-      group.writeSQL(document, connection);
+    if (structure != null)
+    { structure.addDivision(division);
     }
   }
 
+  /**
+   *  Add a division to an indicated division within structure.
+   *
+   *  @param <code>String</code> the structure identifier
+   *  @param <code>String</code> the division identifer, within which the division
+   *         is to be placed.
+   *  @param <code>METSDivision</code> the division to be added.
+   */
+  public void addSubDivision(String structureName, String divisionID, METSDivision division)
+  { METSStructure structure = (METSStructure) this.children.get(structureName);
+
+    if (structure != null)
+    { structure.addSubDivision(divisionID, division);
+    }
+  }
+
+  public METSDivision getDivision(String structureName, String divisionID)
+  { METSStructure structure = (METSStructure) this.children.get(structureName);
+
+    if (structure != null)
+    { return structure.getDivision(divisionID);
+    }
+    return null;
+  }
+
+  public void write(PrintWriter writer)
+  { Iterator structures = this.children.values().iterator();
+
+    while (structures.hasNext())
+    { METSStructure group = (METSStructure) structures.next();
+
+      group.write(writer);
+    }
+  }
+
+  public boolean writeSQL(DocumentInterface document, GS3SQLConnection connection)
+  { Iterator structures = this.children.values().iterator();
+    
+    while (structures.hasNext())
+    { METSStructure group = (METSStructure) structures.next();
+
+      if (!group.writeSQL(document, connection))
+      { return false;
+      }
+    }
+    return true;
+  }
+
+  public static METSStructureSet readSQL(DocumentInterface document, GS3SQLConnection connection)
+  { 
+    METSStructureSet set = new METSStructureSet();
+
+    GS3SQLSelect select = new GS3SQLSelect("structure");
+    select.addField("*");
+    GS3SQLWhereItem whereItem = new GS3SQLWhereItem("DocID", "=", document.getID().toString());
+    select.setWhere(new GS3SQLWhere(whereItem));
+    connection.execute(select.toString());
+
+    // start going through the matching metadata blocks
+    try {
+      ResultSet resultSet = connection.getResultSet();
+      resultSet.first();
+      do {
+	METSStructure structure = METSStructure.readSQL(document, connection, resultSet);
+	if (structure != null) {
+	  set.addStructure(structure);
+	}
+      } while (resultSet.next());
+    }
+    catch (SQLException sqlEx) {
+      System.out.println(sqlEx);
+      System.exit(1);
+    }
+
+    return set;
+  }
+
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/OrderedNamespace.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/OrderedNamespace.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/OrderedNamespace.java	(revision 5945)
@@ -19,208 +19,214 @@
 public class OrderedNamespace extends METSNamespace
 {
-	String  name;
-	List metadataList;
-
-	public OrderedNamespace(String name)
-	{ super(name);
-		this.metadataList = new ArrayList();
-	}
-
-	public OrderedNamespace(String name, METSLocation location)
-	{ super(name, location);
-		this.metadataList = new ArrayList();
-	}
-
-	public boolean validate(String field, String value)
-	{	return true;
-	}
-
-	/**
-	 *  Add a metadata item.  Whether the field and value validate for this
-	 *  schema will also be tested.
-	 *
-	 *  @param <code>String</code> the name of the field to be given the value
-	 *  @param <code>String</code> the value to be assigned
-	 *
-	 *  @return <code>boolean</code> whether the field value was added.  This
-	 *          would return <code>false</code> if the values did not validate,
-	 *          for example.
-	 */
-	public boolean addMetadata(String label, String value)
-	{	if (!this.validate(label, value)) {
-			return false;
-		}
-
-		this.metadataList.add(new NamespaceItem(label, value));
-		return true;
-	}
-
-	/**
-	 *  Assign a metadata item.  Whether the field and value validate for this
-	 *  schema will also be tested.  Any existing metadata for that field will
-	 *  be destroyed if the new value validates.
-	 *
-	 *  @param <code>String</code> the name of the field to be given the value
-	 *  @param <code>String</code> the value to be assigned
-	 *
-	 *  @return <code>boolean</code> whether the field value was added.  This
-	 *          would return <code>false</code> if the values did not validate,
-	 *          for example.
-	 */
-	public boolean setMetadata(String label, String value)
-	{ if (!this.validate(label, value))
-		{ return false;
-		}
-
-// TODO:		this.metadataMap.setOnly(label, value);
-	  int itemNo = this.findItem(label);
-		if (itemNo >= 0)
-		{	this.metadataList.set(itemNo, new NamespaceItem(label, value));
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 *  Remove all metadata values for a given field name
-	 *
-	 *  @param <code>String</code> the field to delete
-	 *
-	 *  @return <code>boolean</code> whether the field was actually deleted; 
-	 *          will return <code>true</code> if the field was already empty.
-	 */
-	public boolean removeMetadata(String label)
-	{ int itemNo;
-
-		itemNo = this.findItem(label);
-		while (itemNo >= 0)
-		{	this.metadataList.remove(itemNo);
-			itemNo = this.findItem(label);
-		}
-		return true;
-	}
-
-	/**
-	 *  Remove a particular incidence of a given metadata field for a document.
-	 *  If an exact match for the given value is not found, nothing changes.
-	 *  N.B. if a value occurs twice, only the first incidence of it will be
-	 *  deleted from the list.
-	 *
-	 *  @param <code>String</code> the field to have the value removed
-	 *  @param <code>String</code> the value to be removed from a given field
-	 *
-	 *  @return <code>boolean</code> <code>true</code> if an actual metadata text
-	 *          is matched against the given value and is thus deleted.
-	 */
-	public boolean removeMetadata(String label, String value)
-	{ int itemNo;
-
-		itemNo = this.findItem(label);
-		if (itemNo >= 0)
-		{	this.metadataList.remove(itemNo);
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 *  Get the metadata items for a particular label
-	 *
-	 *  @param <code>String</code> the label to fetch values for - must be devoid
-	 *                             of namespace prologue (i.e. "title" rather than
-	 *                             e.g. "dc:title").
-	 *  
-	 *  @return <code>List</code> the list of corresponding values.  May be
-	 *          <code>null</code> if no values are found for the metadata
-	 */
-	public List getMetadata(String label)
-	{	List resultList = new ArrayList();
-
-		for (int i = 0; i < this.metadataList.size(); i ++)
-		{	NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
-
-			if (item.getLabel().equals(label))
-			{	resultList.add(item.getValue());
-			}
-		}
-		if (resultList.size() > 0)
-		{	return resultList;
-		}
-		return null;
-	}
-
-	private int findItem(String label)
-	{	for (int i = 0; i < this.metadataList.size(); i ++)
-		{	if (((NamespaceItem) this.metadataList.get(i)).getLabel().equals(label))
-			{ return i;
-			}
-		}
-		return -1;
-	}
-
-	private int findItem(String label, String value)
-	{	for (int i = 0; i < this.metadataList.size(); i ++)
-		{	NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
-			if (item.getLabel().equals(label) && item.getValue().equals(value))
-			{ return i;
-			}
-		}
-		return -1;
-	}
-
-	/**
-	 *  Write out the metadata to an XML file through a <code>PrintWriter</code>.
-	 *
-	 *  @param <code>PrintWriter</code> the writer to use.
-	 */
-	public boolean write(PrintWriter writer)
-	{ // if this is a non-file block of metadata, write it out in long hand
-		if (this.location == null)
-		{	String tag = XMLTools.getOpenTag("mets", "mdWrap");
-			tag = XMLTools.addAttribute(tag, "MDType", this.name);
-			writer.println(tag);
-			Iterator items = this.metadataList.iterator();
-
-			while (items.hasNext())
-			{	NamespaceItem item = (NamespaceItem) items.next();
-				this.writeItem(writer, item);
-			}
-			writer.println("</mets:mdWrap>");
-		}
-		// otherwise, drop the metadata out in a simplified file-reference
-		// form only
-		else
-		{	String tag = XMLTools.getOpenTag("mets", "mdRef");
-			tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
-			tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
-			tag = XMLTools.addAttribute(tag, "MDTYPE", this.getName());
-			tag = XMLTools.makeSingleton(tag);
-		}
-		return true;
-	}
-
-	/**
-	 *  Write out a single element - this may be overloaded to provide for the
-	 *  appropriate formatting for this metadata.
-	 */
-	protected boolean writeItem(PrintWriter writer, NamespaceItem item)
-	{	// Do some default sillinesses
-		writer.write(XMLTools.getOpenTag(this.name, item.getLabel()));
-
-		writer.write(item.getValue());
-
-		writer.write(XMLTools.getCloseTag(this.name, item.getLabel()));
-		return true;
-	}
-
-	/**
-	 *  <p>Indicate whether this metadata is open to being changed or not.</p>
-	 *  <p>Metadata which is created from a distinct file cannot be changed,
-	 *  only those which have no associated file can be modified.
-	 *
-	 *	@return <code>boolean</code> whether this namespace can be altered.
-	 */
-	public boolean isEditable()
-	{	return (this.location == null);
-	}
+  List metadataList;
+
+  public OrderedNamespace(String name)
+  { super(name);
+    this.metadataList = new ArrayList();
+  }
+
+  public OrderedNamespace(String name, METSLocation location)
+  { super(name, location);
+    this.metadataList = new ArrayList();
+  }
+
+  public boolean validate(String field, String value)
+  { return true;
+  }
+
+  /**
+   *  Add a metadata item.  Whether the field and value validate for this
+   *  schema will also be tested.
+   *
+   *  @param <code>String</code> the name of the field to be given the value
+   *  @param <code>String</code> the value to be assigned
+   *
+   *  @return <code>boolean</code> whether the field value was added.  This
+   *          would return <code>false</code> if the values did not validate,
+   *          for example.
+   */
+  public boolean addMetadata(String label, String value)
+  { if (!this.validate(label, value)) {
+      return false;
+    }
+
+    this.metadataList.add(new NamespaceItem(label, value));
+    return true;
+  }
+
+  /**
+   *  Assign a metadata item.  Whether the field and value validate for this
+   *  schema will also be tested.  Any existing metadata for that field will
+   *  be destroyed if the new value validates.
+   *
+   *  @param <code>String</code> the name of the field to be given the value
+   *  @param <code>String</code> the value to be assigned
+   *
+   *  @return <code>boolean</code> whether the field value was added.  This
+   *          would return <code>false</code> if the values did not validate,
+   *          for example.
+   */
+  public boolean setMetadata(String label, String value)
+  { if (!this.validate(label, value))
+    { return false;
+    }
+
+    // TODO:		this.metadataMap.setOnly(label, value);
+    int itemNo = this.findItem(label);
+    if (itemNo >= 0)
+    { this.metadataList.set(itemNo, new NamespaceItem(label, value));
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   *  Remove all metadata values for a given field name
+   *
+   *  @param <code>String</code> the field to delete
+   *
+   *  @return <code>boolean</code> whether the field was actually deleted; 
+   *          will return <code>true</code> if the field was already empty.
+   */
+  public boolean removeMetadata(String label)
+  { int itemNo;
+
+    itemNo = this.findItem(label);
+    while (itemNo >= 0)
+    { this.metadataList.remove(itemNo);
+      itemNo = this.findItem(label);
+    }
+    return true;
+  }
+
+  /**
+   *  Remove a particular incidence of a given metadata field for a document.
+   *  If an exact match for the given value is not found, nothing changes.
+   *  N.B. if a value occurs twice, only the first incidence of it will be
+   *  deleted from the list.
+   *
+   *  @param <code>String</code> the field to have the value removed
+   *  @param <code>String</code> the value to be removed from a given field
+   *
+   *  @return <code>boolean</code> <code>true</code> if an actual metadata text
+   *          is matched against the given value and is thus deleted.
+   */
+  public boolean removeMetadata(String label, String value)
+  { int itemNo;
+
+    itemNo = this.findItem(label);
+    if (itemNo >= 0)
+    { this.metadataList.remove(itemNo);
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   *  Get the metadata items for a particular label
+   *
+   *  @param <code>String</code> the label to fetch values for - must be devoid
+   *                             of namespace prologue (i.e. "title" rather than
+   *                             e.g. "dc:title").
+   *  
+   *  @return <code>List</code> the list of corresponding values.  May be
+   *          <code>null</code> if no values are found for the metadata
+   */
+  public List getMetadata(String label)
+  { List resultList = new ArrayList();
+
+    for (int i = 0; i < this.metadataList.size(); i ++)
+    { NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
+
+      if (item.getLabel().equals(label))
+      { resultList.add(item.getValue());
+      }
+    }
+    if (resultList.size() > 0)
+    { return resultList;
+    }
+    return null;
+  }
+
+  private int findItem(String label)
+  { for (int i = 0; i < this.metadataList.size(); i ++)
+    { if (((NamespaceItem) this.metadataList.get(i)).getLabel().equals(label))
+      { return i;
+      }
+    }
+    return -1;
+  }
+
+  private int findItem(String label, String value)
+  { for (int i = 0; i < this.metadataList.size(); i ++)
+    { NamespaceItem item = (NamespaceItem) this.metadataList.get(i);
+      if (item.getLabel().equals(label) && item.getValue().equals(value))
+      { return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   *  Write out the metadata to an XML file through a <code>PrintWriter</code>.
+   *
+   *  @param <code>PrintWriter</code> the writer to use.
+   */
+  public boolean write(PrintWriter writer)
+  { // if this is a non-file block of metadata, write it out in long hand
+    if (this.location == null)
+    { String tag = XMLTools.getOpenTag("mets", "mdWrap");
+      tag = XMLTools.addAttribute(tag, "MDType", this.name);
+      if (this.id != null) {
+	tag = XMLTools.addAttribute(tag, "ID", this.id);
+      }
+      writer.println(tag);
+
+      Iterator items = this.metadataList.iterator();
+      
+      while (items.hasNext())
+      { NamespaceItem item = (NamespaceItem) items.next();
+        this.writeItem(writer, item);
+      }
+      writer.println("</mets:mdWrap>");
+    }
+    // otherwise, drop the metadata out in a simplified file-reference
+    // form only
+    else
+    { String tag = XMLTools.getOpenTag("mets", "mdRef");
+      tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
+      tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
+      tag = XMLTools.addAttribute(tag, "MDTYPE", this.name);
+      if (this.id != null) {
+	tag = XMLTools.addAttribute(tag, "ID", this.id);
+      }
+      tag = XMLTools.makeSingleton(tag);
+    }
+    return true;
+  }
+
+  /**
+   *  Write out a single element - this may be overloaded to provide for the
+   *  appropriate formatting for this metadata.
+   */
+  protected boolean writeItem(PrintWriter writer, NamespaceItem item)
+  { // Do some default sillinesses
+    writer.write(XMLTools.getOpenTag(this.name, item.getLabel()));
+    
+    writer.write(item.getValue());
+    
+    writer.write(XMLTools.getCloseTag(this.name, item.getLabel()));
+    return true;
+  }
+  
+  /**
+   *  <p>Indicate whether this metadata is open to being changed or not.</p>
+   *  <p>Metadata which is created from a distinct file cannot be changed,
+   *  only those which have no associated file can be modified.
+   *
+   *	@return <code>boolean</code> whether this namespace can be altered.
+   */
+  public boolean isEditable()
+  { return (this.location == null);
+  }
 }
Index: /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/SimpleNamespace.java
===================================================================
--- /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/SimpleNamespace.java	(revision 5944)
+++ /trunk/gsdl3/src/java/org/greenstone/gsdl3/gs3build/metadata/SimpleNamespace.java	(revision 5945)
@@ -9,4 +9,5 @@
 
 import java.sql.SQLException;
+import java.sql.ResultSet;
 
 import org.w3c.dom.Document;
@@ -30,137 +31,137 @@
 public class SimpleNamespace extends METSNamespace
 {
-	MultiMap metadataMap;
-
-	public SimpleNamespace(String name)
-	{ super(name);
-		this.metadataMap = new MultiMap();
-		System.out.println("Namespace " + name);
+  MultiMap metadataMap;
+
+  public SimpleNamespace(String name)
+  { super(name);
+    this.metadataMap = new MultiMap();
+    System.out.println("Namespace " + name);
+  }
+
+  public SimpleNamespace(String name, METSLocation location)
+  { super(name, location);
+    this.metadataMap = new MultiMap();
+  }
+
+  public SimpleNamespace(String name, Element mdWrapTag)
+  { super(name);
+    this.metadataMap = new MultiMap();
+    
+    NodeList childNodes = mdWrapTag.getChildNodes();
+    for (int c = 0; c < childNodes.getLength(); c ++)
+    { // a metadata node
+      if (childNodes.item(c).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
+      { // get the name of the metadata from the node
+	String metadataLabel = childNodes.item(c).getNodeName();
+
+	// skip blank labels
+	// TODO: raise an error: metadata item without metadata label set
+	if (metadataLabel == null || metadataLabel.length() == 0)
+	{ continue;
 	}
 
-	public SimpleNamespace(String name, METSLocation location)
-	{ super(name, location);
-		this.metadataMap = new MultiMap();
+	// build the value
+	String metadataValue = "";
+
+	Element childElement = (Element) childNodes.item(c);
+	for (int i = 0; i < childElement.getChildNodes().getLength(); i ++)
+	{ metadataValue = metadataValue + childElement.getChildNodes().item(i).toString();
 	}
 
-	public SimpleNamespace(String name, Element mdWrapTag)
-	{	super(name);
-		this.metadataMap = new MultiMap();
-
-		NodeList childNodes = mdWrapTag.getChildNodes();
-		for (int c = 0; c < childNodes.getLength(); c ++)
-		{	// a metadata node
-			if (childNodes.item(c).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
-			{	// get the name of the metadata from the node
-				String metadataLabel = childNodes.item(c).getNodeName();
-
-				// skip blank labels
-				// TODO: raise an error: metadata item without metadata label set
-				if (metadataLabel == null || metadataLabel.length() == 0)
-				{	continue;
-				}
-
-				// build the value
-				String metadataValue = "";
-
-				Element childElement = (Element) childNodes.item(c);
-				for (int i = 0; i < childElement.getChildNodes().getLength(); i ++)
-				{	metadataValue = metadataValue + childElement.getChildNodes().item(i).toString();
-				}
-
-				// trim any leading namespace identifiers in "namespace:label" metadata
-				if (metadataLabel.startsWith(this.name + ":"))
-				{	metadataLabel = metadataLabel.substring(this.name.length() + 1);
-				}
-
-				this.addMetadata(metadataLabel, metadataValue);
-			}
-		}
+	// trim any leading namespace identifiers in "namespace:label" metadata
+	if (metadataLabel.startsWith(this.name + ":"))
+	{ metadataLabel = metadataLabel.substring(this.name.length() + 1);
 	}
 
-	public boolean validate(String field, String value)
-	{	return true;
-	}
-
-	/**
-	 *  Add a metadata item.  Whether the field and value validate for this
-	 *  schema will also be tested.
-	 *
-	 *  @param <code>String</code> the name of the field to be given the value
-	 *  @param <code>String</code> the value to be assigned
-	 *
-	 *  @return <code>boolean</code> whether the field value was added.  This
-	 *          would return <code>false</code> if the values did not validate,
-	 *          for example.
-	 */
-	public boolean addMetadata(String label, String value)
-	{	if (!this.validate(label, value)) {
-			return false;
-		}
-
-		this.metadataMap.put(label, value);
-		return true;
-	}
-
-	/**
-	 *  Assign a metadata item.  Whether the field and value validate for this
-	 *  schema will also be tested.  Any existing metadata for that field will
-	 *  be destroyed if the new value validates.
-	 *
-	 *  @param <code>String</code> the name of the field to be given the value
-	 *  @param <code>String</code> the value to be assigned
-	 *
-	 *  @return <code>boolean</code> whether the field value was added.  This
-	 *          would return <code>false</code> if the values did not validate,
-	 *          for example.
-	 */
-	public boolean setMetadata(String label, String value)
-	{ if (!this.validate(label, value))
-		{ return false;
-		}
-
-		this.metadataMap.setOnly(label, value);
-		return true;
-	}
-
-	/**
-	 *  Remove all metadata values for a given field name
-	 *
-	 *  @param <code>String</code> the field to delete
-	 *
-	 *  @return <code>boolean</code> whether the field was actually deleted; 
-	 *          will return <code>true</code> if the field was already empty.
-	 */
-	public boolean removeMetadata(String label)
-	{ this.metadataMap.remove(label);
-		return true;
-	}
-
-	/**
-	 *  Remove a particular incidence of a given metadata field for a document.
-	 *  If an exact match for the given value is not found, nothing changes.
-	 *  N.B. if a value occurs twice, only the first incidence of it will be
-	 *  deleted from the list.
-	 *
-	 *  @param <code>String</code> the field to have the value removed
-	 *  @param <code>String</code> the value to be removed from a given field
-	 *
-	 *  @return <code>boolean</code> <code>true</code> if an actual metadata text
-	 *          is matched against the given value and is thus deleted.
-	 */
-	public boolean removeMetadata(String label, String value)
-	{ return this.metadataMap.remove(label, value);
-	}
-
-	/**
-	 *  Get the metadata items for a particular label
-	 *
-	 *  @param <code>String</code> the label to fetch values for
-	 *  
-	 *  @return <code>List</code> the list of corresponding values.  May be
-	 *          <code>null</code>
-	 */
-	public List getMetadata(String label)
-	{	return (List) this.metadataMap.get(label);
-	}
+	this.addMetadata(metadataLabel, metadataValue);
+      }
+    }
+  }
+
+  public boolean validate(String field, String value)
+  { return true;
+  }
+
+  /**
+   *  Add a metadata item.  Whether the field and value validate for this
+   *  schema will also be tested.
+   *
+   *  @param <code>String</code> the name of the field to be given the value
+   *  @param <code>String</code> the value to be assigned
+   *
+   *  @return <code>boolean</code> whether the field value was added.  This
+   *          would return <code>false</code> if the values did not validate,
+   *          for example.
+   */
+  public boolean addMetadata(String label, String value)
+  { if (!this.validate(label, value)) {
+      return false;
+    }
+
+    this.metadataMap.put(label, value);
+    return true;
+  }
+
+  /**
+   *  Assign a metadata item.  Whether the field and value validate for this
+   *  schema will also be tested.  Any existing metadata for that field will
+   *  be destroyed if the new value validates.
+   *
+   *  @param <code>String</code> the name of the field to be given the value
+   *  @param <code>String</code> the value to be assigned
+   *
+   *  @return <code>boolean</code> whether the field value was added.  This
+   *          would return <code>false</code> if the values did not validate,
+   *          for example.
+   */
+  public boolean setMetadata(String label, String value)
+  { if (!this.validate(label, value))
+    { return false;
+    }
+
+    this.metadataMap.setOnly(label, value);
+    return true;
+  }
+
+  /**
+   *  Remove all metadata values for a given field name
+   *
+   *  @param <code>String</code> the field to delete
+   *
+   *  @return <code>boolean</code> whether the field was actually deleted; 
+   *          will return <code>true</code> if the field was already empty.
+   */
+  public boolean removeMetadata(String label)
+  { this.metadataMap.remove(label);
+    return true;
+  }
+
+  /**
+   *  Remove a particular incidence of a given metadata field for a document.
+   *  If an exact match for the given value is not found, nothing changes.
+   *  N.B. if a value occurs twice, only the first incidence of it will be
+   *  deleted from the list.
+   *
+   *  @param <code>String</code> the field to have the value removed
+   *  @param <code>String</code> the value to be removed from a given field
+   *
+   *  @return <code>boolean</code> <code>true</code> if an actual metadata text
+   *          is matched against the given value and is thus deleted.
+   */
+  public boolean removeMetadata(String label, String value)
+  { return this.metadataMap.remove(label, value);
+  }
+
+  /**
+   *  Get the metadata items for a particular label
+   *
+   *  @param <code>String</code> the label to fetch values for
+   *  
+   *  @return <code>List</code> the list of corresponding values.  May be
+   *          <code>null</code>
+   */
+  public List getMetadata(String label)
+  { return this.metadataMap.getAll(label);
+  }
 
   /**
@@ -175,4 +176,7 @@
       
       tag = XMLTools.addAttribute(tag, "MDType", this.name);
+      if (this.id != null) {
+	tag = XMLTools.addAttribute(tag, "ID", this.id);
+      }
       writer.println(tag);
 			
@@ -197,4 +201,7 @@
       tag = XMLTools.addAttribute(tag, "xlink:href", location.getLocation().toString());
       tag = XMLTools.addAttribute(tag, "MDType", this.name);
+      if (this.id != null) {
+	tag = XMLTools.addAttribute(tag, "ID", this.id);
+      }
       writer.println(tag);
 
@@ -204,33 +211,33 @@
   }
 
-	/**
-	 *  Write out a single element - this may be overloaded to provide for the
-	 *  appropriate formatting for this metadata.
-	 */
-	protected boolean writeItem(PrintWriter writer, String label)
-	{	if (this.location == null)
-		{ // just place the metadata in a simple wrapper
-			Iterator values = this.metadataMap.getAll(label).iterator();
-
-			while (values.hasNext())
-			{	String value = values.next().toString();
-
-				writer.write(XMLTools.getOpenTag(this.name, label));
-
-				writer.write(value);
-
-				writer.println(XMLTools.getCloseTag(this.name, label));
-			}
-		}
-		else
-		{	String tag = XMLTools.getOpenTag("mets", "mdRef");
-			tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
-			tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
-			tag = XMLTools.addAttribute(tag, "MDTYPE", this.getName());
-			tag = XMLTools.makeSingleton(tag);
-			writer.println(tag);
-		}
-		return true;
-	}
+  /**
+   *  Write out a single element - this may be overloaded to provide for the
+   *  appropriate formatting for this metadata.
+   */
+  protected boolean writeItem(PrintWriter writer, String label)
+  { if (this.location == null)
+    { // just place the metadata in a simple wrapper
+      Iterator values = this.metadataMap.getAll(label).iterator();
+
+      while (values.hasNext())
+      { String value = values.next().toString();
+
+        writer.write(XMLTools.getOpenTag(this.name, label));
+	
+	writer.write(value);
+	
+	writer.println(XMLTools.getCloseTag(this.name, label));
+      }
+    }
+    else
+    { String tag = XMLTools.getOpenTag("mets", "mdRef");
+      tag = XMLTools.addAttribute(tag, "LOCTYPE", this.location.getType());
+      tag = XMLTools.addAttribute(tag, "xlink:href", this.location.getLocation().toString());
+      tag = XMLTools.addAttribute(tag, "MDTYPE", this.getName());
+      tag = XMLTools.makeSingleton(tag);
+      writer.println(tag);
+    }
+    return true;
+  }
 
   /**
@@ -241,53 +248,65 @@
   public boolean writeSQL(int parentId, GS3SQLConnection connection)
   { // write the general stuff
-    int sqlId;
-    super.writeSQL(parentId, connection);
+    String sqlId;
+
+    if (!super.writeSQL(parentId, connection)) {
+      return false;
+    }
 
     try {
-
+      if (this.id == null) {
 	GS3SQLSelect select = new GS3SQLSelect("namespaces");
 	select.setWhere(new GS3SQLWhere(new GS3SQLWhereItem("MetadataRef", "=", Integer.toString(parentId), GS3SQLField.INTEGER_TYPE)));
 	select.addField("NamespaceRef");
-	System.out.println(select.toString());
 	connection.execute(select.toString());
 	
-	connection.getResultSet().first();
-	sqlId = connection.getResultSet().getInt("NamespaceRef");
-
-	Iterator keys = this.metadataMap.keySet().iterator();
-	while (keys.hasNext())
-	{ String thisKey = keys.next().toString();
+	ResultSet results = connection.getResultSet();
+	results.first();
+	sqlId = Integer.toString(results.getInt("NamespaceRef"));
+      }
+      else {
+	sqlId = this.id;
+      }
+
+      // clear all the existing metadata items for this namespace
+      GS3SQLDelete delete = new GS3SQLDelete("mdvalues");
+      GS3SQLWhere where = new GS3SQLWhere(new GS3SQLWhereItem("NamespaceRef", "=", sqlId, GS3SQLField.INTEGER_TYPE));
+      delete.setWhere(where);
+      connection.execute(delete.toString());
+
+      // write out the metadata for this namespace
+      Iterator keys = this.metadataMap.keySet().iterator();
+      while (keys.hasNext())
+      { String thisKey = keys.next().toString();
     
-	  Iterator values = this.metadataMap.getAll(thisKey).iterator();
+        Iterator values = this.metadataMap.getAll(thisKey).iterator();
 	  
-	  while (values.hasNext())
-	  { String value = values.next().toString();
+	while (values.hasNext())
+	{ String value = values.next().toString();
       
-
-	    GS3SQLInsert insert = new GS3SQLInsert("mdvalues");
-	    insert.addValue("NamespaceRef", Integer.toString(sqlId), GS3SQLField.INTEGER_TYPE);
-	    insert.addValue("label", thisKey);
-	    insert.addValue("value", value);
-	    System.out.println(insert.toString());
-	    connection.execute(insert.toString());
-	  }
+	  GS3SQLInsert insert = new GS3SQLInsert("mdvalues");
+	  insert.addValue("NamespaceRef", sqlId, GS3SQLField.INTEGER_TYPE);
+	  insert.addValue("label", thisKey);
+	  insert.addValue("value", value);
+	  connection.execute(insert.toString());
 	}
+      }
     }
     catch (SQLException sql) {
-	System.out.println(sql);
-    }
-	return true;
-    }
-
-
-	/**
-	 *  <p>Indicate whether this metadata is open to being changed or not.</p>
-	 *  <p>Metadata which is created from a distinct file cannot be changed,
-	 *  only those which have no associated file can be modified.
-	 *
-	 *	@return <code>boolean</code> whether this namespace can be altered.
-	 */
-	public boolean isEditable()
-	{	return (this.location == null);
-	}
+      System.out.println(sql);
+    }
+    return true;
+  }
+
+
+  /**
+   *  <p>Indicate whether this metadata is open to being changed or not.</p>
+   *  <p>Metadata which is created from a distinct file cannot be changed,
+   *  only those which have no associated file can be modified.
+   *
+   *	@return <code>boolean</code> whether this namespace can be altered.
+   */
+  public boolean isEditable()
+  { return (this.location == null);
+  }
 }
