Index: /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraCommons.java
===================================================================
--- /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraCommons.java	(revision 22299)
+++ /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraCommons.java	(revision 22300)
@@ -88,23 +88,31 @@
 	}
 	
-	/** Given an Element, this will return its String representation properly 
+	/** Given a DOM node, this will return its String representation properly 
 	 * indented for display.
-	 * @return a string representation of e, formatted for display. 
-	 * @param e is the element to be converted to its string representation.
+	 * @return a string representation of n, formatted for display. 
+	 * @param n is the DOM node to be converted to its string representation.
 	*/
-	public static String elementToFormattedString(Element e) 
-		throws TransformerException 
+	public static String displayAsString(Node n) 
 	{
-		DOMSource domSource = new DOMSource(e);
-		Transformer transformer = TransformerFactory.newInstance().newTransformer();
-		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-		//transformer.setOutputProperty(OutputKeys.METHOD, "xml");
-		//transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
-		transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+	    try {
+	    
+	    DOMSource domSource = new DOMSource(n);
+	    Transformer transformer = TransformerFactory.newInstance().newTransformer();
+	    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+	    //transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+	    //transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
+	    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+	    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+	    
+	    StringWriter sw = new StringWriter();
+	    transformer.transform(domSource, new StreamResult(sw));
+	    return sw.toString();
+	    } catch(Exception e) {
+		System.err.println("Couldn't display node as String.");
+		return "";
+	    }
+	    
+	}
 
-		StringWriter sw = new StringWriter();
-		transformer.transform(domSource, new StreamResult(sw));
-		return sw.toString();
-	}
+    
 }
Index: /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraConnection.java
===================================================================
--- /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraConnection.java	(revision 22299)
+++ /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraConnection.java	(revision 22300)
@@ -20,5 +20,5 @@
 
 package org.greenstone.fedora.services;
-
+import org.greenstone.gsdl3.util.GSXML;
 
 import fedora.client.utility.AutoFinder;
@@ -95,6 +95,4 @@
 	
 	/* Some fixed strings of known literals */
-	protected static final String TYPE = "type";
-	protected static final String INTERNAL_NODE = "internalNode";
 	protected static final String GET= "/get/";
 	
@@ -632,5 +630,5 @@
 	 * @see <a href="http://www.fedora.info/definitions/1/0/api/Fedora-API-A.html">Fedora access API, API-A for method findObjects</a>
 	 * @see <a href="http://www.fedora.info/definitions/1/0/types/&#035;complexType_FieldSearchQuery_Link031D7D80">XML type definition of FieldSearchQuery</a> 
-	 * @see <a href="http://www.fedora.info/download/2.2.1/javadocs/fedora/server/types/gen/FieldSearchQuery.html>Type definition of 2.2.1 FieldSearchQuery</a>
+	 * @see <a href="http://www.fedora.info/download/2.2.1/javadocs/fedora/server/types/gen/FieldSearchQuery.html">Type definition of 2.2.1 FieldSearchQuery</a>
 	 * @see <a href="http://www.fedora.info/download/2.1.1/userdocs/server/serverdocs/fedora/server/search/FieldSearchQuery.html">does not apply: type definition of 2.1.1 FieldSearchQuery</a>
 	 * @see <a href="http://john.drc-dev.ohiolink.edu/browser/drc-core/trunk/src/java/edu/ohiolink/drc/drcdl/BrowseController.java?rev=462">BrowseController.java for an example</a> 
@@ -1237,138 +1235,97 @@
 	}
 
-	/** @return the XML content of the TOC of just that portion of the TOC which   
-	 * contains the section denoted by sectionID and its direct child subsections. 
-	 * The children are returned in the order they are encountered, which 
-	 * happens to be in the required order of ascending sectionID. 
-	 * @param docPID - a fedora pid identifying a greenstone document object.
-	 * @param sectionID - identifyies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public Element getChildrenOfSectionXML(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException 
-	{
-		// Store just the number
-		String sectionNumber = removePrefix(sectionID, SECTION); 
-		// get the TOC XML datastream as a String 
-		String xmlTOC = getTOC(docPID);
-		
-		// convert it into a DOM document
-		InputSource source = new InputSource(new StringReader(xmlTOC));
-		Document doc = builder.parse(source);
-		// toplevel element docEl = <Section id="1"></Section>
-		Element docEl = doc.getDocumentElement();
-		
-		// check whether we're requested to return the toplevel element itself
-		if(sectionID.equals("") || // subSection of entire docPID is requested
-		   (docEl.hasAttribute(ID) && docEl.getAttribute(ID).equals(sectionNumber))) 
-			return getSubstructure(docEl, false);
-		
-		// Otherwise, get all <Section> elements and find the
-		// <Section id="sectionNumber"></Section> and return that and its
-		// children
-		NodeList sections = docEl.getElementsByTagName(SECTION_ELEMENT);
-		for(int i = 0; i < sections.getLength(); i++) {
-			Element e = (Element)sections.item(i);
-			if(e.hasAttribute(ID) 
-					&& e.getAttribute(ID).equals(sectionNumber)) 
-			{
-				//System.err.println("Found: " + e.getAttribute(ID));
-				return getSubstructure(e, false); // false: get just e and children
-			}
-		}
-		return null; // not found
-	}
-	
-	/** @return a string representing the XML content of the TOC of just
-	 * that portion of the TOC which contains the section denoted by sectionID  
-	 * and its direct child subsections. 
-	 * The children are returned in the order they are encountered, which 
-	 * happens to be in the required order of ascending sectionID. 
-	 * @param docPID - a fedora pid identifying a greenstone document object.
-	 * @param sectionID - identifyies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public String getChildrenOfSection(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException, TransformerException
-	{
-		Element children = getChildrenOfSectionXML(docPID, sectionID);
-		return (children == null) ? "" : FedoraCommons.elementToString(children);
-	}
-	
-	/** @return the part of the TOC XML file (which outlines doc structure)  
-	 * relating to the given section. This includes the section denoted by
-	 * sectionID as well as all descendent subsections thereof. 
-	 * @param docPID - a fedora pid identifying a greenstone document object.
-	 * @param sectionID - identifyies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public Element getSubsectionXML(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException 
-	{
-		// get the TableOfContents (TOC) XML datastream as a String 
-		String xmlTOC = getTOC(docPID);
-		
-		// convert it into a DOM document
-		InputSource source = new InputSource(new StringReader(xmlTOC));
-		Document doc = builder.parse(source);
-		// toplevel element docEl = <Section id="1"></Section>
-		Element docEl = doc.getDocumentElement();
-		
-		if(sectionID.equals("")) // subSection of entire docPID is requested 
-			return docEl;
-		
-		// Store just the number
-		String sectionNumber = removePrefix(sectionID, SECTION);
-		// Check whether we're requested to return the toplevel element itself
-		// If sectionNumber=1, then the top-level element/document element
-		// of the TOC XML is requested, so return the TOC as is.
-		if(sectionNumber.equals("1")) {
-			return docEl;
-		}
-		
-		// Get all <Section> elements and find the
-		// <Section id="sectionNumber"></Section> and return that
-		NodeList sections = docEl.getElementsByTagName(SECTION_ELEMENT);
-		for(int i = 0; i < sections.getLength(); i++) {
-			Element e = (Element)sections.item(i);
-			if(e.hasAttribute(ID) 
-					&& e.getAttribute(ID).equals(sectionNumber)) {
-				//System.err.println("Found: " + e.getAttribute(ID));
-				return getSubstructure(e, true); // true:get all descendents
-			}
-		}
-		return null; // not found
-	}
-	
-	/** @return a String representation of the part of the TOC XML file   
-	 * (which outlines doc structure) relating to the given section. This    
-	 * includes the section denoted by sectionID as well as all descendent  
-	 * subsections thereof.
-	 * @param docPID a fedora pid identifying a greenstone document object.
-	 * @param sectionID identifyies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public String getSubsection(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, SAXException,  
-			IOException, TransformerException
-	{
-		// Store just the number
-		String sectionNumber = removePrefix(sectionID, SECTION);
-		// get the TableOfContents (TOC) XML datastream as a String 
-		String xmlTOC = getTOC(docPID);
-		
-		// Check whether we're requested to return the toplevel element itself
-		// If sectionNumber=1, then the top-level element/document element
-		// of the TOC XML is requested, so return the TOC as is.
-		if(sectionNumber.equals("1")) 
-			return xmlTOC;
-		
-		// else
-		Element subsection = getSubsectionXML(docPID, sectionID);
-		return (subsection == null) ? "" : FedoraCommons.elementToString(subsection);
-	}
+    /** Given a documentNode element, adds the nodetype attribute to all of its
+     * docNode descendants. The nodetype is either Root, Internal or Leaf to indicate
+     * whether the docnode is a toplevel document Node, or has children or has none.
+     * @param e - the documentNode element whose descendants' nodetypes will be set
+     * at method's end. */
+    protected void addNodeTypeToDescendants(Element e) {
+	NodeList sections = e.getElementsByTagName(SECTION_ELEMENT);
+	for(int i = 0; i < sections.getLength(); i++) {
+	    Element section = (Element)sections.item(i);
+	    NodeList descendants = section.getElementsByTagName(SECTION_ELEMENT);
+	    if(descendants.getLength() > 0) { 
+		// if there are any descendants (which includes children) that are SECTIONS
+		section.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_INTERNAL);
+	    } else {
+		section.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_LEAF);
+	    }
+	}
+    }
+
+
+    /** @return the part of the TOC XML file (which outlines doc structure)  
+     * relating to the given section. This includes the section denoted by
+     * sectionID as well as all descendent subsections thereof. 
+     * @param docPID - a fedora pid identifying a greenstone document object.
+     * @param sectionID - identifyies the particular section in the
+     * document denoted by docPID, may be a section name or number. 
+     * @param structure can contain any combination of: ancestors, parent, 
+     * siblings, children, descendants, entire, specifying the portion of 
+     * the structure to retrieve.
+     * @param info can contain any combination of: siblingPosition, numSiblings, 
+     * numChildren, requesting additional information about the structure. */
+    public Element getSectionStructureXML(String docPID, String sectionID, String structure, String info)
+		throws RemoteException, UnsupportedEncodingException, SAXException, IOException 
+    {
+	// get the TableOfContents (TOC) XML datastream as a String 
+	String xmlTOC = getTOC(docPID);
+	
+	// convert it into a DOM document
+	InputSource source = new InputSource(new StringReader(xmlTOC));
+	Document doc = builder.parse(source);
+	// toplevel element docEl = <Section id="1"></Section>
+	Element docEl = doc.getDocumentElement();
+	addNodeTypeToDescendants(docEl);
+	docEl.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_ROOT);
+
+	if(structure.indexOf("entire") != -1) { // don't need to find the specific section, doc root is what's required
+	    docEl = getStructureInfo(docEl.getOwnerDocument(), docEl, info);
+	    return docEl;
+	}
+
+	if(sectionID.equals("")) {
+	    sectionID = "1";
+	}
+	
+	// Store just the number
+	String sectionNumber = removePrefix(sectionID, SECTION);
+	// Check whether we're requested to return the toplevel element itself
+	// If sectionNumber=1, then the top-level element/document element
+	// of the TOC XML is requested, so return the TOC as is.	
+	if(sectionNumber.equals("1") && structure.indexOf("descendants") != -1) { 
+	    docEl = getStructureInfo(docEl.getOwnerDocument(), docEl, info);
+	    return docEl;	    
+	}
+	
+	// if the root is the section required, return that
+	if(docEl.getTagName().equals(SECTION_ELEMENT) 
+	   && docEl.getAttribute(ID).equals(sectionNumber)) {
+	    Element substructure = getSubstructure(docEl, structure);
+	    return getStructureInfo(substructure.getOwnerDocument(), docEl, info);
+		//return docEl; 
+	}
+	
+
+	// Else, get all <Section> elements and find the
+	// <Section id="sectionNumber"></Section> and return that
+	NodeList sections = docEl.getElementsByTagName(SECTION_ELEMENT);
+	for(int i = 0; i < sections.getLength(); i++) {
+	    
+	    Element e = (Element)sections.item(i);
+	    if(e.hasAttribute(ID) && e.getAttribute(ID).equals(sectionNumber)) {
+		Element substructure = getSubstructure(e, structure);
+		return getStructureInfo(substructure.getOwnerDocument(), e, info);
+	    }
+	}
+
+	return null; // not found
+    }
+
 	
 	/** Implements browsing document titles of a greenstone collection stored in 
 	 * the fedora repository by letter. 
 	 * @return the document pids whose titles start with the given letter.
+	 * @param collName - the name of the collection.
 	 * @param letter - the starting letter to browse by.
 	 */ 
@@ -1435,5 +1392,5 @@
 		// We want to do the following kind of search (when written in Fedora's 
 		// REST format - see http://localhost:8080/fedora/search): 
-		// pid~greenstone:<colname>* title~<1st word of titleContents>
+		// pid~greenstone:<colname>-* title~<1st word of titleContents>
 		
 		// We don't need to normalise the word first (to search titles starting 
@@ -1452,5 +1409,5 @@
 		// only pids of those titles that contain the entire phrase titleContents
 		
-		final String pid = GREENSTONE_+collName+WILDCARD; 
+		final String pid = GREENSTONE_+collName+HYPHEN+WILDCARD; 
 		
 		int indexOfFirstSpace = titleContents.indexOf(' '); // check for space
@@ -1562,6 +1519,6 @@
 		throws RemoteException, FedoraVersionNotSupportedException
 	{
-		// Searching for pids of the form "greenstone:gs2mgdemo*";
-		final String pid = GREENSTONE_+collName+WILDCARD;
+		// Searching for pids of the form "greenstone:gs2mgdemo-*";
+		final String pid = GREENSTONE_+collName+HYPHEN+WILDCARD;
 		
 		Condition[] conditions = new Condition[2];
@@ -1614,59 +1571,207 @@
 		return collPID.substring(collPID.indexOf(':')+1, collPID.indexOf('-'));
 	}
-		
-	/** Convert the given Element to a String representing the same XML.
-	 * @return an element containing a copy element e with either only its child
-	 * elements or with all its descendents (depending on whether parameter
-	 * descendents is true or false).
-	 * @param e - the element to start copying from.
-	 * @param descendents - if true, e is copied with all its descendetns into the 
-	 * element that's returned. If false, only e and its direct children are copied  
-	 * @see <a href="http://forum.java.sun.com/thread.jspa?threadID=678472&tstart=30">Sun java thread on transforming a DOM XML to a String</a>
-	*/
-	protected Element getSubstructure(Element e, boolean descendents) 
-	{
-		Document doc = builder.newDocument();
-		Node n = doc.importNode(e, descendents); 
-				// descendents=true: import/copy descendents.
-				// Else, copy just current node e (later copy its direct children)
-		doc.appendChild(n); // need to put the copied node into a document
-			// else it won't have a parent doc (DOMSource can't work with it
-			// without it having a document parent).
-	
-		// if we are not recursively copying all descendents, then copy just 
-		// the childnodes:
-		if(!descendents) { // then copy just the children
-			// get e's children and copy them into the new document
-			NodeList children = e.getChildNodes();
-			for(int i = 0; i < children.getLength(); i++) {
-				// create copy
-				n = doc.importNode(children.item(i), false);
-				// attach it to parent
-				doc.getDocumentElement().appendChild(n);
-				
-				// Now we need to indicate whether this new node (child) is a leaf
-				// or not. (This is necessary for getChildrenOfSection(), else 
-				// it's hard to know if the children are leaves or have further 
-				// subsections.
-				if(n.getNodeName().equals(SECTION_ELEMENT)) {
-					// we're dealing only with section children
-					
-					// Check if the matching original had children:
-					Element originalsChild = (Element)children.item(i);
-					NodeList grandchildren = 
-						originalsChild.getElementsByTagName(SECTION_ELEMENT);
-					if(grandchildren.getLength() > 0) {
-						// original's child has children, so indicate this
-						// in the copied child:
-						Element child = (Element)n;
-						child.setAttribute(TYPE, INTERNAL_NODE);
-					}
-				}
+	
+    
+    /** Return the TOC substructure requested
+     * @return an element containing a copy if element e with either only its child
+     * elements or with all its descendants and/or its ancestors or only its parent 
+     * and/or its siblings (depending on what the parameter structure specifies).
+     * @param e - the element to start copying from and whose structure is requested.
+     * @param structure - a string containing any combination of the values:
+     * ancestors, parent, siblings, children, descendants,
+     * specifying the portion of the structure to retrieve.
+     * @see <a href="http://forum.java.sun.com/thread.jspa?threadID=678472&tstart=30">Sun java thread on transforming a DOM XML to a String</a>
+     */
+    protected Element getSubstructure(Element original, String structure) 
+    {
+	Document doc = builder.newDocument();
+	
+	boolean descendants = (structure.indexOf("descendants") != -1) ? true : false;
+	Node current = doc.importNode(original, descendants);
+
+	// descendants=true: import/copy descendants.
+	// Else, copy just current node original (later copy its direct children)	
+	
+	Node parentOfCurrent = null;
+	Node parentOfOriginal = original.getParentNode();
+	if(parentOfOriginal == original.getOwnerDocument()) { // don't want document node (original is docRoot)
+	    parentOfOriginal = null;
+	}
+	
+	if(parentOfOriginal == null) { // no parentNode, so current is the root node.
+	    // can't get ancestors/parent/siblings, since all these need parentNode
+	    doc.appendChild(current);
+	} else { // siblings, ancestors and parent requests all require parent node to exist
+	    // First check if we need to get ancestors, else for whether parent is required
+	    if(structure.indexOf("ancestors") != -1) {
+		parentOfCurrent = doc.importNode(parentOfOriginal, false);
+		
+		Node child = null;
+		Node parent = parentOfCurrent;      // the copy
+		Node n = parentOfOriginal.getParentNode(); // the doc to copy from
+		
+		while(n != null && n != original.getOwnerDocument()) {
+		    child = parent;
+		    parent = doc.importNode(n, false); // no descendants
+		    parent.appendChild(child);
+		    n = n.getParentNode();
+		}
+		
+		doc.appendChild(parent); // need to put the copied node into a document
+		// else it won't have a parent doc (DOMSource can't work with it
+		// without it having a document parent).
+		
+	    } else if(structure.indexOf("parent") != -1) {
+		parentOfCurrent = doc.importNode(parentOfOriginal, false);
+		//parentOfCurrent.appendChild(current);
+		doc.appendChild(parentOfCurrent);
+	    }
+	    
+	    // a request for siblings is independently tested for
+	    if(structure.indexOf("siblings") != -1) {
+		// only import parent if we didn't already import
+		// it for a request for ancestors or parent
+		if(parentOfCurrent == null) { 
+		    parentOfCurrent = doc.importNode(parentOfOriginal, false);
+		    doc.appendChild(parentOfCurrent);     // this becomes the root
+		}
+		// now the siblings of current (children of parentOfCurrent)
+		NodeList children = parentOfOriginal.getChildNodes();		    
+		for(int i = 0; i < children.getLength(); i++) {
+		    Node n = children.item(i);
+
+		    if(n.getNodeName().equals(SECTION_ELEMENT)) { 
+			if((Element)n != original) { // skip original which was already imported
+			    Node child = doc.importNode(n, false); // no descendants
+			    parentOfCurrent.appendChild(child);
+			} else { // already imported Current element, insert at this position			    
+			    parentOfCurrent.appendChild(current);
+			}			
+			
+		    }			
+		}
+	    } else if(parentOfCurrent != null) { // include current node for ancestors and parent requests
+		// (sibling request adds the current node into a particular position) 
+		parentOfCurrent.appendChild(current);
+		     // need to put the copied node into a document
+		     // else it won't have a parent doc (DOMSource can't work with it
+		     // without it having a document parent).
+	    } else { // when only children or descendants were requested, current becomes root document
+		doc.appendChild(current);
+	    }
+	}
+
+	// if we are not recursively copying all descendants, then copy just 
+	// the childnodes of current:
+	if(structure.indexOf("children") != -1 && !descendants) { // then copy just the children
+
+	    // get e's children and copy them into the new document
+	    NodeList children = original.getChildNodes();
+	    for(int i = 0; i < children.getLength(); i++) {
+		// create copy
+		Node n = doc.importNode(children.item(i), false);
+		// attach it to parent
+		current.appendChild(n);
+		
+		// Now we need to indicate whether this new node (child) is a leaf
+		// or not. (This is necessary for getChildrenOfSection(), else 
+		// it's hard to know if the children are leaves or have further 
+		// subsections.
+		if(n.getNodeName().equals(SECTION_ELEMENT)) {
+		    // we're dealing only with section children
+		    
+		    // Check if the matching original had children:
+		    Element originalsChild = (Element)children.item(i);
+		    NodeList grandchildren = originalsChild.getElementsByTagName(SECTION_ELEMENT);
+		    if(grandchildren.getLength() > 0) {
+			// original's child has children, so indicate this
+			// in the copied child:
+			Element child = (Element)current;			
+			//  child.setAttribute(TYPE, INTERNAL_NODE);
+			
+		    }
+		}
+	    }
+	}
+
+	return doc.getDocumentElement();
+    }    
+
+
+    /** Return the TOC substructure with the requested structural info.
+     * @return an element containing a copy if element e with either only its child
+     * elements or with all its descendants and/or its ancestors or only its parent 
+     * and/or its siblings (depending on what the parameter structure specifies).
+     * Returns null if the element, e, passed in is null.
+     * @param doc - the new document into whose root element the structural information
+     * will be inserted as attributes.
+     * @param e - the element to start copying from and whose structure is requested.
+     * @param info - a string containing any combination of the values: numChildren, 
+     * numSiblings, siblingPosition. The requested info gets added as attributes to
+     * the returned root element.
+     * @see <a href="http://forum.java.sun.com/thread.jspa?threadID=678472&tstart=30">Sun java thread on transforming a DOM XML to a String</a>
+     */
+    protected Element getStructureInfo(Document doc, Element e, String info) 
+    {
+	if(e == null) {
+	    return null;
+	}
+	
+	Element root = doc.getDocumentElement();
+
+	if(!info.equals("")) {   
+	    if(info.indexOf("numChildren") != -1) {
+		//int numChildren = e.getElementsByTagName(SECTION_ELEMENT).getLength();
+		int numChildren = 0;
+		
+		NodeList children = e.getChildNodes();
+		for(int i = 0; i < children.getLength(); i++) {
+		    Node n = children.item(i); 
+		    if(n.getNodeName().equals(SECTION_ELEMENT)) {
+			numChildren++;
+		    }
+		}
+		
+		root.setAttribute("numChildren", Integer.toString(numChildren));
+	    }
+	    
+	    if(info.indexOf("ibling") != -1) { // siblingPosition or numSiblings
+		int numSiblings = 0;
+		int siblingPosition = 0;
+			
+		Node parent = e.getParentNode();
+		if(parent == null) {
+		    numSiblings = 0;
+		    siblingPosition = 1;
+		} else {
+		    //numSiblings = parent.getChildNodes().getLength();
+		    NodeList siblings = parent.getChildNodes();
+		    
+		    for(int i = 0; i < siblings.getLength(); i++) {
+			Node n = siblings.item(i); 
+			if(n.getNodeName().equals(SECTION_ELEMENT)) {
+			    if(e == (Element)n) {
+				siblingPosition = numSiblings+1;
+			    } else { // count every sibling section element, except e itself
+				numSiblings++;
+			    }			    
 			}
-		}
-		return doc.getDocumentElement();
-	}
-	
-	
+		    }
+		}		
+		
+		if(info.indexOf("numSiblings") != -1) {
+		    root.setAttribute("numSiblings", Integer.toString(numSiblings));
+		}
+		
+		if(info.indexOf("siblingPosition") != -1) {
+		    root.setAttribute("siblingPosition", Integer.toString(siblingPosition));
+		}
+	    }
+	}
+	
+	return root;
+    }
+
+
 	/** 
 	 * Return a datastream of a document, given the document's id
@@ -1790,9 +1895,4 @@
 		 	String sectionID = "SECTION1"; //SECTION1.5
 		 	System.out.println("\n");
-		 	System.out.println(sectionID+ " - entire subsection:\n" 
-		 			+ fedoraCon.getSubsection(docPID, sectionID));
-		 	
-		 	System.out.println(sectionID + " and children:\n" 
-		 			+ fedoraCon.getChildrenOfSection(docPID, sectionID));
 		 			
 		 	System.out.println(
@@ -1816,5 +1916,5 @@
 			System.out.println("Unable to instantiate FedoraConnection\n" + e);
 			e.printStackTrace();
-			//LOG.error("Unable to instantiate FedoraConnection\n" + e);
+			//LOG.error("Unable to instantiate FedoraConnection\n" + e, e);
 		}
 	}
Index: /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3Connection.java
===================================================================
--- /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3Connection.java	(revision 22299)
+++ /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3Connection.java	(revision 22300)
@@ -90,12 +90,4 @@
 	 * then query services will not be offered */
 	protected String[] serviceNames;
-		
-	/** constant CHILDREN indicates that a DocumentStructureRetrieve is to
-	 * return only the child nodes of a section, not any further descendants */
-	protected static final int CHILDREN = 0;
-	
-	/** constant DESCENDANTS indicates that a DocumentStructureRetrieve is to
-	 * return all descendants of a section */
-	protected static final int DESCENDANTS = 1;
 	
 	/** The object used to connect to FedoraGenericSearch, which is used 
@@ -362,6 +354,6 @@
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
 	 * EX metadata for all the requested collections */
-	public String getCollectionMetadata(String[] collIDs) {
-		return getMetadata(collIDs);
+    public String getCollectionMetadata(String[] collIDs) {
+	return getMetadata(collIDs, new String[] {"all"});
 	}
 	
@@ -372,7 +364,8 @@
 	 * "&lt;pid&gt;-sectionNumber". 
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
-	 * EX, DC, DLS metadata for all the requested documents */
-	public String getDocumentMetadata(String[] docIDs) {
-		return getMetadata(docIDs);
+	 * EX, DC, DLS metadata for all the requested documents 
+	 * @param metadata is the list of metadata elements to be retrieved for each doc */
+	public String getDocumentMetadata(String[] docIDs, String[] metadata) {
+	    return getMetadata(docIDs, metadata);
 	}
 	
@@ -381,7 +374,8 @@
 	 * @param collID is a fedora pid identifying a collection in its repository
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
-	 * EX metadata for the requested collection */
+	 * EX metadata for the requested collection
+	 * @param metadata is the list of metadata elements to be retrieved for each doc */
 	public String getCollectionMetadata(String collID) {
-		return getMetadata(new String[] {collID});
+	    return getMetadata(new String[] {collID}, new String[] {"all"});
 	}
 	
@@ -393,6 +387,6 @@
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
 	 * EX, DC, DLS metadata for the requested document */
-	public String getDocumentMetadata(String docID)	{
-		return getMetadata(new String[] {docID});
+    public String getDocumentMetadata(String docID, String[] metadata)	{
+	return getMetadata(new String[] {docID}, metadata);
 	}
 
@@ -402,6 +396,7 @@
 	 * fedora pids for collections, or otherwise may be a document identifier.
 	 * In the last case, the document ID may consist of either
-	 * "documentPID-sectionNumber" or may just be just fedora documentPID */
-	public String getMetadata(String[] docIDsOrCollIDs)
+	 * "documentPID-sectionNumber" or may just be just fedora documentPID 
+	 * @param metadata is the list of metadata elements to be retrieved for each doc */
+    public String getMetadata(String[] docIDsOrCollIDs, String[] metadata)
 	{
 		Document doc = builder.newDocument();
@@ -415,5 +410,5 @@
 				// create the <documentNode> containing the metadata 
 				// for each document docID
-				Element docNode = getMetadata(doc, docIDsOrCollIDs[i]); 
+			    Element docNode = getMetadata(doc, docIDsOrCollIDs[i], metadata); 
 				docNodeList.appendChild(docNode);
 			}
@@ -426,5 +421,5 @@
 				GSXML.REQUEST_TYPE_PROCESS, "DocumentMetadataRetrieve");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		} catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -444,6 +439,7 @@
 	 * document given by parameter ID
 	 * @param id denotes a collection pid, a document pid or a docID of the  
-	 * form "documentpid-sectionNumber" */
-	protected Element getMetadata(Document doc, String id) 
+	 * form "documentpid-sectionNumber"
+	 * @param metadata is the list of metadata elements to be retrieved for each doc */
+    protected Element getMetadata(Document doc, String id, String[] metadata) 
 		throws RemoteException, UnsupportedEncodingException, 
 			SAXException, IOException 
@@ -500,4 +496,9 @@
 		}
 		
+		String metafields = "";
+		for(int i = 0; i < metadata.length; i++) {
+		    metafields = metafields + metadata[i] + "|";		    
+		}
+
 		// Adding in metadata sets in alphabetical order
 		// DC metadata for a top-level document is different from EX, DLS: 
@@ -506,5 +507,5 @@
 		if(!dc.equals("")) {
 			addMetadataWithNamespacedTagNames(doc, metadataList,
-					dc, DC);
+							  dc, DC, metafields);
 		}
 		
@@ -513,5 +514,5 @@
 		// in which case, dls and dc will be non-empty strings
 		if(!dls.equals("")) {
-			addMetadataWithFixedTagName(doc, metadataList, dls, DLS);
+		    addMetadataWithFixedTagName(doc, metadataList, dls, DLS, metafields);
 		}
 		
@@ -519,5 +520,5 @@
 		// collection object, top-level document object, 
 		// and document section item 
-		addMetadataWithFixedTagName(doc, metadataList, ex, EX);
+		addMetadataWithFixedTagName(doc, metadataList, ex, EX, metafields);
 		
 		// now the metadataList has been built up
@@ -539,9 +540,11 @@
 	 * Dublin Core metadata stored in the Fedora repository).
 	 * @param metadataSet is the constant datastream identifier, e.g. "DC".
-	 * At present this method only applies to the DC metadata as that's the only 
-	 * one where each tagname is different except for the constant dc: namespace.
+	 * At present this method applies to the DC metadata and any others like it
+	 * where each tagname is different except for the constant dc: namespace.
+	 * @param metafields is a | separated string containing the metadatafields to
+	 * extract or "all" if all fields are requested
 	*/
-	protected void addMetadataWithNamespacedTagNames(Document doc, 
-			Element metadataList, String metaDatastream, String metadataSet)
+	protected void addMetadataWithNamespacedTagNames(Document doc, Element metadataList, 
+							 String metaDatastream, String metadataSet, String metafields)
 		throws SAXException, IOException
 	{
@@ -551,5 +554,5 @@
 		// The following doesn't work for some reason: to retrieve all elements 
 		// whose namespace prefix starts with "dc", we pass "*" for localName
-		//NodeList dcMetaTags = src.getElementsByTagNameNS(DC.toLowerCase(), "*");
+		//NodeList dcMetaTags = src.getElementsByTagNameNS(metadataSet.toLowerCase(), "*");
 		
 		// Longer way: get the children of the root document
@@ -558,18 +561,26 @@
 		for(int i = 0; i < children.getLength(); i++) {
 			String nodeName = children.item(i).getNodeName();
-			// check that the nodename starts with the "dc" namespace,
+			// check that the nodename starts with the metadataSet ("dc") namespace,
 			// which simultaneously ensures that the node's an element:
-			if(nodeName.startsWith(DC.toLowerCase())) {
-				// need to have a period for Greenstone instead of Fedora's colon
-				nodeName = nodeName.replace(COLON, PERIOD);
+			if(nodeName.toLowerCase().startsWith(metadataSet.toLowerCase())) {
+			    // need to have a period for Greenstone instead of Fedora's colon
+			    nodeName = nodeName.replace(COLON, PERIOD);
+			    if(metadataSet.equals(DC)) { // dc:title -> dc.Title
+				nodeName = "dc" + PERIOD + Character.toString(Character.toUpperCase(nodeName.charAt(3)))
+				    + nodeName.substring(4);
+			    }
+
+			    // get the requested metadata fields
+			    if(metafields.indexOf("all") != -1 || metafields.indexOf(nodeName) != -1) {
 				Element metatag = (Element)children.item(i);
 				String value = FedoraCommons.getValue(metatag);
 				// <dc:tagname>value</dc:tagname>
-				// we're going to put use this in our metadata element as 
-				// <metadata name="dc:tagname">value</metadata>
+				// we're going to put this in our metadata element as 
+				// <metadata name="dc.Tagname">value</metadata>
 				
 				// create metadata of (name, value) pairs in target DOM (doc)
 				Element metadata = doc.createElement(GSXML.METADATA_ELEM);
 				Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
+				
 				attribute.setValue(nodeName);
 				metadata.setAttributeNode(attribute);
@@ -577,4 +588,5 @@
 				metadata.appendChild(content);
 				metadataList.appendChild(metadata);
+			    }
 			}
 		}		
@@ -586,6 +598,6 @@
 	 * is the name of the metadata (like author, title). For each element
 	 * it creates a corresponding new element of the form 
-	 * &lt;metadata name="namespace:metadataName"&gt;value&lt;/metadata&gt;. Each of these 
-	 * are then appended to the metadataList parameter.
+	 * &lt;metadata name="namespace:metadataName"&gt;value&lt;/metadata&gt;. 
+	 * Each of these are then appended to the metadataList parameter.
 	 * @param doc is the Document object using which the new metadata Elements
 	 * are to be constructed
@@ -599,7 +611,9 @@
 	 * At present this method applies to the DLS and EX metadata as they have
 	 * constant tagnames throughout.
+	 * @param metafields is a | separated string containing the metadatafields to
+	 * extract or "all" if all fields are requested.
 	*/
-	protected void addMetadataWithFixedTagName(Document doc, 
-			Element metadataList, String metaDatastream, String metadataSet) 
+	protected void addMetadataWithFixedTagName(Document doc, Element metadataList, 
+						   String metaDatastream, String metadataSet, String metafields) 
 		throws SAXException, IOException
 	{
@@ -630,16 +644,18 @@
 				name = name + HYPHEN + metatag.getAttribute(QUALIFIER);
 			}
-			String value = FedoraCommons.getValue(metatag);
-			
-			// create metadata of (name, value) pairs in target DOM (doc)
-			Element metadata = doc.createElement(GSXML.METADATA_ELEM);
-			Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
-			attribute.setValue(namespacePrefix + name);  
-									// prefix with namespace, if any
-			metadata.setAttributeNode(attribute);
-			Text content = doc.createTextNode(value);
-			metadata.appendChild(content);
-			
-			metadataList.appendChild(metadata);
+			name = namespacePrefix + name; // prefix with namespace, if any
+			if(metafields.indexOf("all") != -1 || metafields.indexOf(name) != -1) {
+			    String value = FedoraCommons.getValue(metatag);
+			    
+			    // create metadata of (name, value) pairs in target DOM (doc)
+			    Element metadata = doc.createElement(GSXML.METADATA_ELEM);
+			    Attr attribute = doc.createAttribute(GSXML.NAME_ATT);
+			    attribute.setValue(name); 
+			    metadata.setAttributeNode(attribute);
+			    Text content = doc.createTextNode(value);
+			    metadata.appendChild(content);
+			    
+			    metadataList.appendChild(metadata);
+			}
 		}
 	}
@@ -688,5 +704,5 @@
 				GSXML.REQUEST_TYPE_PROCESS, "DocumentMetadataRetrieve");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		} catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -747,63 +763,36 @@
 	} 
 	
-		
-	/** @return the documentStructure of the document or section given by docID. 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message. This method returns the entire
-	 * subSection of the docID (that is, all descendants included).
-	 * @param docID the identifier for the document whose structure is required.
-	 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"  
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the 
-	 * same response */
-	public String getDocumentStructure(String docID) {
-		return getStructure(new String[]{docID}, DESCENDANTS);
-	}
-	
-	/** @return a view of the structure of the document or section given by docID
-	 * which contains only the section and its direct children. This structure is 
-	 * returned in the XML format of a Greenstone3 DocumentStructureRetrieve 
-	 * response message. 
-	 * @param docID the identifier for the document whose structure is required.
-	 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"  
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the 
-	 * same response */
-	public String getChildren(String docID) {
-		return getStructure(new String[]{docID}, CHILDREN);
-	}
-	
-	/** @return the documentStructure of the documents or sections given by docIDs. 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message. This method returns the entire
-	 * subSection of each docID (that is, all descendants included).
-	 * @param docIDs is an array of identifiers for the documents whose structures
-	 * are required.
-	 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"  
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the 
-	 * same response */
-	public String getDocumentStructure(String[] docIDs) {
-		return getStructure(docIDs, DESCENDANTS);
-	}
-	
-	/** @return the documentStructure of the documents or sections given by docIDs
-	 * but only the sections and their children (not any further descendants). 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message.
-	 * @param docIDs the identifiers for the documents whose structures are 
-	 * required. The docids are of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectioNumber&gt;"  
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the 
-	 * same response */
-	public String getChildren(String[] docIDs) {
-		return getStructure(docIDs, CHILDREN);
-	}
-	
-	/** 
+    /** @return a String representing Greenstone3 DocumentMetadataRetrieve XML
+	 * containing the requested portion of the document structure of the documents 
+	 * indicated by docIDs: 
+	 * @param docID is the document identifier of the document whose hierarchical
+	 * structure is requested. The name of the collection is already included in the
+	 * docID for a Fedora DL.
+	 * @param structure - strings specifying the required structure of the document. 
+	 * It can be a combination of: ancestors, parent, siblings, children, descendants, entire.
+	 * @param info - strings specifying the required structural info of the document. 
+	 * It can be any combination of: siblingPosition, numSiblings, numChildren.
+	*/
+    public String getDocumentStructure(String docID, String[] structure, String[] info) {
+	return getStructure(new String[]{docID}, structure, info);
+    }
+    
+
+     /** @return a String representing Greenstone3 DocumentMetadataRetrieve XML
+	 * containing the requested portion of the document structure of the documents 
+	 * indicated by docIDs: 
+	 * @param docIDs is an array of document identifiers of documents whose
+	 * hierarchical structures are requested. The name of the collection is already
+	 * included in the docID for a Fedora DL.
+	 * @param structure - strings specifying the required structure of each document. 
+	 * It can be a combination of: ancestors, parent, siblings, children, descendants, entire.
+	 * @param info - strings specifying the required structural info of each document. 
+	 * It can be any combination of: siblingPosition, numSiblings, numChildren.
+	*/
+    public String getDocumentStructure(String[] docIDs, String[] structure, String[] info) {
+	return getStructure(docIDs, structure, info);
+    }
+
+    	/** 
 	 * Returns a greenstone3 DocumentStructureRetrieve XML response message 
 	 * containing the document structures for the given docIDs.
@@ -814,13 +803,12 @@
 	 * @param docIDs the documentIDs for which the section's structure is returned; 
 	 * where a docID is either a fedora pid &lt;docPID&gt; or &lt;docPID&gt;-&lt;sectionNumber&gt;.
-	 * @param levels - either CHILDREN or DESCENDANTS. 
-	 * CHILDREN returns only the first-level descendants (children) of the 
-	 * requested document sections indicated by docIDs.
-	 * DESCENDANTS returns all descendants of all the document-sections denoted by 
-	 * docIDs.
+	 * @param structure - the structure of the sections to return. Can be any combination of:
+	 * ancestors, parent, siblings, children, descendants, entire.
+	 * @param infos - strings containing any combination of the values: numChildren, numSiblings, 
+	 * siblingPosition. The requested info gets added as attributes to the returned root element.
 	 * @return a greenstone3 DocumentStructureRetrieve XML response message in
 	 * String format with the structure of the docIDs requested.
 	*/
-	protected String getStructure(String[] docIDs, int levels) 
+    protected String getStructure(String[] docIDs, String[] structure, String[] infos) 
 	{
 		Document doc = builder.newDocument();
@@ -833,5 +821,6 @@
 			// append the <documentNodes> for the docIDs
 			// to the docNodeList
-			getStructureElement(docNodeList, docIDs, levels); 
+			//getStructureElement(docNodeList, docIDs, levels);
+		    getStructureElement(docNodeList, docIDs, structure, infos);
 		} catch(Exception e) { 
 			ex = new FedoraGS3RunException(e);
@@ -842,5 +831,5 @@
 				GSXML.REQUEST_TYPE_PROCESS, "DocumentStructureRetrieve");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		} catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -848,6 +837,7 @@
 		}
 	}
-	
-	/** Given a &lt;documentNodeList&gt; portion of a greenstone3 
+
+
+    /** Given a &lt;documentNodeList&gt; portion of a greenstone3 
 	 * DocumentStructureRetrieve XML response message, this method will populate 
 	 * it with the &lt;documentNodes&gt; that represent the structure of the given docIDs.
@@ -856,36 +846,80 @@
 	 * @param docIDs the documentIDs for which the section's structure is returned; 
 	 * where a docID is either a fedora pid &lt;docPID&gt; or &lt;docPID&gt;-&lt;sectionNumber&gt;.
-	 * @param levels - either CHILDREN or DESCENDANTS. 
-	 * CHILDREN returns only the first-level descendants (children) of the 
-	 * requested document sections indicated by docIDs.
-	 * DESCENDANTS returns all descendants of all the document-sections denoted by 
-	 * docIDs.
+	 * @param structures - the structure of the sections to return. Can be any combination of:
+	 * ancestors, parent, siblings, children, descendants, entire.
+	 * @param infos - a string containing any combination of the values: numChildren, numSiblings, 
+	 * siblingPosition. The requested info gets added as attributes to the returned root element.
 	*/
-	protected void getStructureElement(Element docNodeList, 
-			String[] docIDs, int levels) 
+	protected void getStructureElement(Element docNodeList, String[] docIDs,
+					   String[] structures, String[] infos)
 		throws RemoteException, UnsupportedEncodingException, SAXException, 
 			IOException 
 	{
-		// process each docID
-		for(int i = 0; i < docIDs.length; i++) {
-			// work out the document's fedora PID and section ID
-			String sectionID = getSectionIDFromDocID(docIDs[i]);
-			String docPID = getDocPIDFromDocID(docIDs[i]);
-			
-			// get the required section, along with children or descendants
-			Element srcDocElement = null;
-			if(levels == CHILDREN) // get the requested section with its children 
-				srcDocElement = this.getChildrenOfSectionXML(docPID, sectionID);
-			else // levels == DESCENDANTS, get the section with all its descendants
-				srcDocElement = this.getSubsectionXML(docPID, sectionID);
-			
-			// copy-and-convert that structure into a structure format for GS3
-			Element docNode = getStructure(docNodeList.getOwnerDocument(), 
-					docIDs[i], docPID, srcDocElement);
-			
-			// add it to our list of documentNodes
-			docNodeList.appendChild(docNode);
-		}
-	}
+	    // Make one string out of requested structure components, and one string from info components
+	    String structure = "";
+	    String info = "";
+	    for(int i = 0; i < structures.length; i++) {
+		structure = structure + structures[i] + "|";
+	    }
+	    for(int i = 0; i < infos.length; i++) {
+		info = info + infos[i] + "|";
+	    }
+	    
+	    // process each docID
+	    for(int i = 0; i < docIDs.length; i++) {
+		// work out the document's fedora PID and section ID
+		String sectionID = getSectionIDFromDocID(docIDs[i]);
+		String docPID = getDocPIDFromDocID(docIDs[i]);
+		if(sectionID.equals("")) {
+		    sectionID = "1";
+		}
+
+		// get the required section, along with children or descendants
+		Element srcDocElement = getSectionStructureXML(docPID, sectionID, structure, info);
+		Document doc = docNodeList.getOwnerDocument();
+		
+		// copy-and-convert that structure into a structure format for GS3
+		Element docNode = getStructure(doc, docIDs[i], docPID, srcDocElement);
+		
+		if(!info.equals("")) {
+		    // <nodeStructureInfo>
+		    //    <info name="" value="" />
+		    //    <info name="" value="" />
+		    //    ...
+		    // </nodeStructureInfo>
+		    Element nodeStructureInfo = doc.createElement(GSXML.NODE_STRUCTURE_ELEM+GSXML.INFO_ATT);
+		    Element root = srcDocElement.getOwnerDocument().getDocumentElement();
+		    
+		    if(root.hasAttribute("numSiblings")) {
+			String numSiblings = root.getAttribute("numSiblings");
+			Element infoEl = doc.createElement(GSXML.INFO_ATT);
+			infoEl.setAttribute(GSXML.NAME_ATT, "numSiblings");
+			infoEl.setAttribute(GSXML.VALUE_ATT, numSiblings);
+			nodeStructureInfo.appendChild(infoEl);
+		    }
+		    
+		    if(root.hasAttribute("siblingPosition")) {
+			String siblingPosition = root.getAttribute("siblingPosition");
+			Element infoEl = doc.createElement(GSXML.INFO_ATT);
+			infoEl.setAttribute(GSXML.NAME_ATT, "siblingPosition");
+			infoEl.setAttribute(GSXML.VALUE_ATT, siblingPosition);
+			nodeStructureInfo.appendChild(infoEl);
+		    }
+		    
+		    if(root.hasAttribute("numChildren")) {
+			String numChildren = root.getAttribute("numChildren");
+			Element infoEl = doc.createElement(GSXML.INFO_ATT);		
+			infoEl.setAttribute(GSXML.NAME_ATT, "numChildren");
+			infoEl.setAttribute(GSXML.VALUE_ATT, numChildren);
+			nodeStructureInfo.appendChild(infoEl);
+		    }
+		    docNode.appendChild(nodeStructureInfo);
+		}
+		
+		// add it to our list of documentNodes
+		docNodeList.appendChild(docNode);
+	    }
+	}
+
 		
 	/** 
@@ -916,5 +950,5 @@
 		Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
 		attribute.setValue(requestingDocID); //requestingDocID.replace(HYPHEN+SECTION, "")
-		docNode.setAttributeNode(attribute);
+		docNode.setAttributeNode(attribute);		
 		
 		// <nodeStructure>
@@ -932,5 +966,6 @@
 		return docNode;		
 	}
-	
+
+
 	/** Recursive method that creates a documentStructure mirroring parameter
 	 * section, starting from parameter parent down to all descendants
@@ -983,20 +1018,18 @@
 		String sectionID = subSection.hasAttribute(ID) ?
 				subSection.getAttribute(ID) : "";
-		nodeID.setValue(docID + HYPHEN + sectionID);
+		if(sectionID.equals("1") 
+		   && subSection.getElementsByTagName(SECTION_ELEMENT).getLength() > 0) { // root, non-leaf case
+		    // reset the attribute without the section number
+		    nodeID.setValue(docID+ HYPHEN + sectionID); // maybe important for democlient?
+		} else {
+		    nodeID.setValue(docID + HYPHEN + sectionID);
+		}
+		//nodeID.setValue(docID + HYPHEN + sectionID);
 		docNode.setAttributeNode(nodeID);
 		
 		Attr nodeType = doc.createAttribute(GSXML.NODE_TYPE_ATT);
-		if(sectionID.equals("1")) { // root case
-			nodeType.setValue(GSXML.NODE_TYPE_ROOT);
-			// reset the attribute without the section number
-			docNode.setAttribute(GSXML.NODE_ID_ATT, docID);
-		}
-		else if(subSection.getElementsByTagName(SECTION_ELEMENT).getLength() > 0)
-			// this section has further <Section> children, so it's an internal node 
-			nodeType.setValue(GSXML.NODE_TYPE_INTERNAL);
-		else if(subSection.hasAttribute(TYPE)) 
-			nodeType.setValue(GSXML.NODE_TYPE_INTERNAL);
-		else // leaf
-			nodeType.setValue(GSXML.NODE_TYPE_LEAF);
+		if(subSection.hasAttribute(GSXML.NODE_TYPE_ATT)) {
+		    nodeType.setValue(subSection.getAttribute(GSXML.NODE_TYPE_ATT));
+		} 
 		docNode.setAttributeNode(nodeType);
 		return docNode;
@@ -1068,5 +1101,5 @@
 				GSXML.REQUEST_TYPE_PROCESS, "DocumentContentRetrieve");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		} catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1202,5 +1235,5 @@
 				GSXML.REQUEST_TYPE_DESCRIBE, "");
 		try {
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1247,5 +1280,5 @@
 				GSXML.REQUEST_TYPE_DESCRIBE, "");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1305,5 +1338,5 @@
 				GSXML.REQUEST_TYPE_DESCRIBE, collectionName);
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1337,5 +1370,5 @@
 				GSXML.REQUEST_TYPE_DESCRIBE, collectionName);
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1420,5 +1453,5 @@
 				GSXML.REQUEST_TYPE_DESCRIBE, from);
 		try{ 
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1694,119 +1727,273 @@
 	 * user to browse the titles of documents in the given collection by letter
 	 * and returning the results.
+	 * @param collectionName is the name of the collection whose documents 
+	 * starting with the given letter will be returned.
 	 * @param classifierIDs are the ids of the classifiers on which to browse. In
 	 * this case, the classifier indicates whether we browse titles by letter, or
 	 * browse (documents) by collection; and it is of the form &lt;CL(letter)&gt;.
-	 * @param collectionName is the name of the collection whose documents 
-	 * starting with the given letter will be returned.
-	 * @return a GS3 DocumentStructureRetrieve response message which lists all 
+	 * @param structures - the requested browse substructure. Can be any combination
+	 * of ancestors, parent, siblings, children, descendants.
+	 * @param infos - the requested structural info. Can be numSiblings, 
+	 * siblingPosition, numChildren.
+	 * @return a GS3 ClassifierBrowse response message which lists all 
 	 * the documents that start with the letter indicated by parameter classifier.
 	*/
-	public String browse(String collectionName, String[] classifierIDs)
+	public String browse(String collectionName, String[] classifierIDs, 
+			     String[] structures, String[] infos)
 	{
-		Document doc = builder.newDocument();
-		FedoraGS3RunException ex = null; //any RemoteException or UnsupportedEncodingException
-		
-		// <classifierNodeList>
-		Element classifierNodeList = doc.createElement(
-				GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
-		
-	for(int i = 0; i < classifierIDs.length; i++) {
-		// <classifierNode nodeID="classifierNum">
-		Element requestedClassifierNode = doc.createElement(
-				GSXML.CLASS_NODE_ELEM);
+	    // Construct one string from the structures and structural info arrays
+	    String structure = "";
+	    String info = "";
+	    for(int i = 0; i < structures.length; i++) {
+		structure = structure + structures[i] + "|";
+	    }
+	    for(int i = 0; i < infos.length; i++) {
+		info = info + infos[i] + "|";
+	    }
+	    
+	    Document doc = builder.newDocument();
+	    FedoraGS3RunException ex = null; //any RemoteException or UnsupportedEncodingException
+	    
+	    // <classifierNodeList>
+	    Element classifierNodeList = doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    
+	    for(int i = 0; i < classifierIDs.length; i++) {
+		if(classifierIDs[i].startsWith("CL1")) { // browse by titles
+		    browseTitlesByLetterClassifier(doc, classifierNodeList,
+						   collectionName, classifierIDs[i],
+						   structure, info);		    
+		}
+	    }
+
+	    Element responseMsg = createResponseMessage(doc, classifierNodeList, ex,
+				    GSXML.REQUEST_TYPE_DESCRIBE, /*collectionName+/ */"ClassifierBrowse");
+	    try {
+		return FedoraCommons.elementToString(responseMsg);
+	    } catch(TransformerException e) {
+		return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
+		    + " " + e;
+	    }
+	}
+
+    /** CL1 browsing classifier: browsing titles by starting letter. 
+     * The browsing structure is retrieved.
+     * @param doc - the document object that will contain the CL1 browsing structure.
+     * @param classifierNodeList - the classifiers will be added to this nodeList.
+     * @param collectionName - name of the collection through which we are browsing CL1.
+     * @param classifierID - the ID of the (sub)classifier. Can be CL1, CL1.x, where x is
+     * a letter.
+     * @param structure - the requested browse substructure. Can be any combination
+     * of ancestors, parent, siblings, children, descendants. siblings not yet implemented.
+     * @param info - the requested structural info. Can be numSiblings, siblingPosition,
+     * numChildren.
+     * @return the classifierNodeList with the CL1 classifier browse structure.
+     */
+    public Element browseTitlesByLetterClassifier(Document doc, Element classifierNodeList, 
+						 String collectionName, String classifierID, 
+						 String structure, String info)
+    {
+	FedoraGS3RunException ex = null; //any RemoteException or UnsupportedEncodingException
+
+	// TODO
+	if(structure.indexOf("siblings") != -1) {
+	    LOG.error("Structure: siblings. Not yet implemented\n");
+	}
+
+	if(structure.indexOf("entire") != -1) {
+	    structure = structure + "ancestors|descendants";
+	} 
+	
+	// Structure of ancestors and children only at this stage
+	int firstLevel = classifierID.indexOf('.');
+	int secondLevel = classifierID.lastIndexOf('.');
+	
+	// <nodeStructure>
+	Element nodeStructure = doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
+
+	// requested classifier node
+	Element classNode = doc.createElement(GSXML.CLASS_NODE_ELEM);
+	Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
+	attribute.setValue(classifierID);
+	classNode.setAttributeNode(attribute);
+
+	if(firstLevel == -1) { // CL1 - toplevel node	   
+	    Element root = (Element)classNode.cloneNode(true); // clone the node before appending children
+
+	    classifierNodeList.appendChild(classNode);
+	    classNode.appendChild(nodeStructure);
+	    
+	    nodeStructure.appendChild(root);
+	    if(structure.indexOf("descendants") != -1) {
+		getTitlesByLetterStructure(collectionName, root, classifierID, true);
+	    } else if(structure.indexOf("children") != -1) {
+		getTitlesByLetterStructure(collectionName, root, classifierID, false);
+	    }
+	} 
+	else if(firstLevel == secondLevel) { // CL1.x, where x is a number
+	    
+	    if(structure.indexOf("parent") != -1 || structure.indexOf("ancestors") != -1) {
+		String toplevelID = classifierID.substring(0, firstLevel);
+		Element toplevelNode = doc.createElement(GSXML.CLASS_NODE_ELEM);
+		attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
+		attribute.setValue(toplevelID);
+		toplevelNode.setAttributeNode(attribute);
+		Element node = (Element)toplevelNode.cloneNode(true); // clone nodes before appending children
+
+		classifierNodeList.appendChild(toplevelNode);
+		toplevelNode.appendChild(nodeStructure);		
+	       
+		nodeStructure.appendChild(node);
+		node.appendChild(classNode);
+	    } else {
+		Element node = (Element)classNode.cloneNode(true);
+		classifierNodeList.appendChild(node);
+		node.appendChild(nodeStructure);
+		nodeStructure.appendChild(classNode);
+	    }
+	    
+	    int num = Integer.parseInt(classifierID.substring(firstLevel+1)); // get x from CL1.x
+	    char ch = (char)(num - 1 + 'A');
+	    if(structure.indexOf("descendants") != -1) {
+		getTitlesForLetter(ch, collectionName, classNode, "descendants");
+	    } else if(structure.indexOf("children") != -1) {
+		getTitlesForLetter(ch, collectionName, classNode, "children");
+	    }
+	}
+	else { // ought to be a doc structure retrieve request, not classifierbrowse structure retrieve
+	    LOG.error("ClassifierID: " + classifierID + ". Shouldn't be in browse method");
+	}
+
+	return classifierNodeList;
+    }
+
+    /** Creates a (CL1) subclassifier element for the docs whose titles start with 
+     * the given letter.
+     * @param ch - the starting letter of the document titles to retrieve.
+     * @param collectionName - name of the collection through which we are browsing CL1.
+     * @param classifierNode - the docNodes found will be appended to this node.
+     * @param depthStructure - can be descendants or children. Specifies what to retrieve:
+     * gets descendants of any documents found, otherwise gets just the children.
+     * @return the given classifierNode which will have the child (or descendant) documents
+     * appended to it.
+     */
+    public Element getTitlesForLetter(char ch, String collectionName, 
+				      Element classifierNode, String depthStructure)
+    {
+	Document doc = classifierNode.getOwnerDocument();
+	FedoraGS3RunException ex = null; //any RemoteException or UnsupportedEncodingException
+
+	
+	// Retrieve the document structure for each subClassifierID: 
+	// all the documents that begin with its letter.
+	String letter = String.valueOf(ch);
+	try {
+	    String[] docPIDs = this.browseTitlesByLetter(collectionName, letter);
+	    if(docPIDs.length == 0) {
+		return classifierNode; // skip letters that don't have any kids
+	    }	    
+	    
+	    for(int i = 0; i < docPIDs.length; i++) {
+		// work out the document's fedora PID and section ID
+		String sectionID = getSectionIDFromDocID(docPIDs[i]);
+		String docPID = getDocPIDFromDocID(docPIDs[i]);
+		
+		// get the required section, along with children or descendants
+		Element section = getSectionStructureXML(docPID, sectionID, depthStructure, "");
+		
+		// <documentNode nodeID="docID" docType="hierarchy" nodeType="root">
+		Element docRootNode = createDocNodeFromSubsection(doc, section, docPID);	    
+		
+		// fills in the subtree of the rootNode in our nodeStructure element
+		createDocStructure(doc, section, docRootNode, docPID); //where section represents the root section
+		classifierNode.appendChild(docRootNode);
+	    }
+	} catch(Exception e) { 
+	    ex = new FedoraGS3RunException(e);
+	    ex.setSpecifics("requested portion of TOC file or trouble with fielded search ");
+	}
+
+	return classifierNode;
+    }
+
+
+    /** Creates all the subclassifiers (CL1.x) for CL1, the classifier to browse by the
+     * starting letter of the alphabet. X is each letter of the alphabet for which there
+     * are matching document titles.
+     * @param collectionName - name of the collection through which we are browsing CL1.
+     * @param classifierNode - the docNodes found will be appended to this node.
+     * @param classifierID - the ID of parent classifier, i.e. CL1, which is used to create
+     * the IDs for the subclassifiers (CL.x).
+     * @param getDescendants - if true, get descendants of any documents found, otherwise
+     * get just the children.
+     * @return the given classifierNode, with the CL.x subclassifiers for the letters of
+     * the alphabet that are represented in the document titles.
+     */
+    public Element getTitlesByLetterStructure(String collectionName, Element classifierNode,
+					       String classifierID, boolean getDescendants) 
+    {
+	Document doc = classifierNode.getOwnerDocument();
+	FedoraGS3RunException ex = null; // any RemoteException or UnsupportedEncodingException
+
+	// We're going to loop to the end of the alphabet
+	int count = 1;
+	for(char ch = 'A'; ch <= 'Z'; ch++, count++) {
+	    // Retrieve the document structure for each subClassifierID: 
+	    // all the documents that begin with its letter.
+	    String letter = String.valueOf(ch);
+	    try {
+		String[] docPIDs = this.browseTitlesByLetter(collectionName, letter);
+		if(docPIDs.length == 0) {
+		    continue; // skip letters that don't have any kids
+		}
+		
+		// <classifierNode nodeID="CL1.x">
+		Element subClassifier = doc.createElement(GSXML.CLASS_NODE_ELEM);
 		Attr attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
-		attribute.setValue(classifierIDs[i]);
-		requestedClassifierNode.setAttributeNode(attribute);
-		classifierNodeList.appendChild(requestedClassifierNode);
-		
-		// <nodeStructure>
-		Element nodeStructure = doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
-		requestedClassifierNode.appendChild(nodeStructure);
-		
-		// And one more time, the top level classifierNode:
-		Element classifierNode = doc.createElement(GSXML.CLASS_NODE_ELEM);
-		attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
-		attribute.setValue(classifierIDs[i]);
-		classifierNode.setAttributeNode(attribute);
-		nodeStructure.appendChild(classifierNode);
-		
-		// Work out what we're browsing base on the classifierID's number
-		// classifier CL1 = browse titles by letter;
-		// classifier CL2 = browse by collection;
-		// remove the CL prefix and decimal point to obtain the number from the id:
-		String classifier = classifierIDs[i].replace("CL", "");
-		int decimal = classifier.indexOf('.'); // look for decimal point
-		if(decimal != -1) {
-		    classifier = classifier.substring(0, decimal);
-		}
-		int classifierNum = Integer.parseInt(classifier);
-		switch(classifierNum) {
-			case 1:
-				// we're going to loop to the end of the alphabet
-				int num = 1;
-				for(char ch = 'A'; ch <= 'Z'; ch++, num++) {
-				    // Retrieve the document structure for each subClassifierID: 
-				    // all the documents that begin with its letter.
-				    String letter = String.valueOf(ch);
-				    try {
-					String[] docPIDs = this.browseTitlesByLetter(
-						     collectionName, letter);
-					if(docPIDs.length == 0) {
-					    continue; // skip letters that don't have any kids
-					}
-					
-					// <classifierNode nodeID="CL3.1">
-					Element subClassifier = doc.createElement(
-						  GSXML.CLASS_NODE_ELEM);
-					attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
-					attribute.setValue(classifierIDs[i]+"."+num);
-					subClassifier.setAttributeNode(attribute);
-					classifierNode.appendChild(subClassifier);
-					
-					// append the <docNodes> for the docPIDs found as children 
-					// of subclassifier 
-					getStructureElement(subClassifier, docPIDs, DESCENDANTS);
-					    //CHILDREN); // for testing
-				    } catch(Exception e) { 
-					ex = new FedoraGS3RunException(e);
-					ex.setSpecifics("requested portion of TOC file or "
-							+ "trouble with fielded search ");
-				    }
-				}
-				// No titles in this collection that start with a letter at all 
-				if(!classifierNode.hasChildNodes()) {
-					// <classifierNode nodeID="CL1.0"> which we will equate with A-Z
-					Element subClassifier = doc.createElement(
-							GSXML.CLASS_NODE_ELEM);
-					attribute = doc.createAttribute(GSXML.NODE_ID_ATT);
-					attribute.setValue(classifierIDs[i]+"."+0); //
-					subClassifier.setAttributeNode(attribute);
-					classifierNode.appendChild(subClassifier);
-				}
-				break;
-			case 2:
-				break;
-			default:
-				ex = new FedoraGS3RunException( // cause is regular exception
-					new Exception("Unknown classifier ID: " + classifierIDs[i]));
-		}
-	}
-		Element responseMsg = createResponseMessage(doc, classifierNodeList, ex,
-				    GSXML.REQUEST_TYPE_DESCRIBE, /*collectionName+*/"/ClassifierBrowse");
-		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
-		}catch(TransformerException e) {
-			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
-				+ " " + e;
-		}
-	}
+		attribute.setValue(classifierID+"."+count);
+		subClassifier.setAttributeNode(attribute);
+		classifierNode.appendChild(subClassifier);
+		
+		if(getDescendants) { // get the documents
+
+		    // append the <docNodes> for the docPIDs found as children 
+		    // of subclassifier 
+
+		    for(int i = 0; i < docPIDs.length; i++) {
+			// work out the document's fedora PID and section ID
+			String sectionID = getSectionIDFromDocID(docPIDs[i]);
+			String docPID = getDocPIDFromDocID(docPIDs[i]);
+		
+			// get the required section, along with children or descendants
+			Element section = getSectionStructureXML(docPID, sectionID, "descendants", "");
+
+			// <documentNode nodeID="docID" docType="hierarchy" nodeType="root">
+			Element rootNode = createDocNodeFromSubsection(doc, section, docPID);
+			
+			// fills in the subtree of the rootNode in our nodeStructure element
+			createDocStructure(doc, section, rootNode, docPID); //where section represents the root section
+			subClassifier.appendChild(rootNode);
+		    }
+		}
+	    } catch(Exception e) { 
+		ex = new FedoraGS3RunException(e);
+		ex.setSpecifics("requested portion of TOC file or "
+				+ "trouble with fielded search ");
+	    } 
+	}
+	return classifierNode;
+    }
+
 	
 	/** This method performs something equivalent to a greenstone3 
 	 * ClassifierBrowseMetadataRetrieve on the classifierNodeIDs
-	 * @param classNodeIDs array of classifierNode IDs of for which the metadata
+	 * @param classNodeIDs array of classifierNode IDs for which the metadata
 	 * needs to be returned.
+	 * @param metafields are the classifier metadata fields that are to be returned.
+	 * At present this method ignores them/pretends the requested metafields are 
+	 * "all" and always returns the Title meta for the requested classifier nodes 
+	 * (because that is all the metadata this Fedora classifier has at present).
 	 * @return a GS3 ClassifierBrowseMetadataRetrieve response message which 
 	 * lists the metadata for all the classifierNodes passed as parameter.*/
-	public String browseMetadataRetrieve(String[] classNodeIDs)
+	public String browseMetadataRetrieve(String[] classNodeIDs, String[] metafields)
 	{
 		Document doc = this.builder.newDocument();
@@ -1860,5 +2047,5 @@
 				"ClassifierBrowseMetadataRetrieve");
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -1895,6 +2082,5 @@
 		// now create the displayItem children for classifier:
 		// <displayItem name="name">#letter</displayItem>
-        // <displayItem name="description">
-		//Browse titles starting with #letter</displayItem>
+		// <displayItem name="description">Browse titles starting with #letter</displayItem>
 		Element displayItem = createNameValuePairElement(doc, 
 				GSXML.DISPLAY_TEXT_ELEM, GSXML.DISPLAY_TEXT_NAME, displayNameVal);
@@ -2013,5 +2199,5 @@
 	}
 	
-	/**	@return a String representing Greenstone3 XML for a query process
+	/** @return a String representing Greenstone3 XML for a query process
 	 * response returning the results for the query denoted by parameter
 	 * nameValParamsMap.
@@ -2040,5 +2226,5 @@
 		String pids[] = {};
 		// (2) for Textquery, we simply search ALL_FIELDS using FedoraGSearch
-		if(service.equals("TextQuery")) {
+		if(service.endsWith("TextQuery")) {
 			try {
 				// get the Query field:
@@ -2142,5 +2328,5 @@
 				GSXML.REQUEST_TYPE_PROCESS, service);
 		try{
-			return FedoraCommons.elementToFormattedString(responseMsg);
+			return FedoraCommons.elementToString(responseMsg);
 		}catch(TransformerException e) {
 			return FedoraGS3RunException.xmlToStringConversionFailureResponseMsg
@@ -2186,5 +2372,5 @@
 			// along with EX of the top-level document:
 			System.out.println("\nGET META for greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae:");
-			System.out.println(con.getDocumentMetadata(new String[]{"greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae"}));
+			System.out.println(con.getDocumentMetadata(new String[]{"greenstone:gs2mgdemo-HASH01d667303fe98545f03c14ae"}, new String[]{"all"}));
 			
 						
@@ -2197,5 +2383,5 @@
 			System.out.println("\nGET META:");
 			for(int i = 0; i < docIDs.length; i++) {
-				System.out.println(con.getDocumentMetadata(docIDs[i]));
+				System.out.println(con.getDocumentMetadata(docIDs[i], new String[]{"all"}));
 			}
 			
@@ -2211,5 +2397,5 @@
 			// their sections
 			for(int i = 0; i < getTitlesFor.length; i++) {
-				System.out.println(con.getDocumentMetadata(getTitlesFor[i]));
+			    System.out.println(con.getDocumentMetadata(getTitlesFor[i], new String[]{"all"}));
 			}
 			
@@ -2219,6 +2405,8 @@
 			System.out.println("\nGET STRUCTURE:");
 			for(int i = 0; i < docIDs.length; i++) {
-				System.out.println(con.getChildren(docIDs[i]));
-				System.out.println(con.getDocumentStructure(docIDs[i]));
+				System.out.println("Descendents and numChildren:\n"
+						   + con.getDocumentStructure(docIDs[i], new String[] {"descendants"}, new String[] {"numChildren"}));
+				System.out.println("Parent and numSiblings:\n"
+						   + con.getDocumentStructure(docIDs[i], new String[] {"parent"}, new String[] {"numSiblings"}));
 			}
 			
@@ -2229,10 +2417,10 @@
 			"greenstone:demo-pinky" };
 			System.out.println(con.getContent(errorCases));
-			System.out.println(con.getDocumentMetadata(errorCases));
-			System.out.println(con.getDocumentStructure(errorCases));
+			System.out.println(con.getDocumentMetadata(errorCases, new String[]{"all"}));
+						   System.out.println(con.getDocumentStructure(errorCases, new String[] {"descendants"}, new String[] {"numChildren"}));
 			
 			System.out.println("\nCLASSIFIER BROWSE");
 			System.out.println(con.browse("gs2mgdemo", //"ClassifierBrowse", 
-						      new String[]{"CL1"}));
+						      new String[]{"CL1"}, new String[] {""}, new String[] {""}));
 			
 			System.out.println("\nCLASSIFIER BROWSE METADATA RETRIEVE");
@@ -2243,5 +2431,5 @@
 			}
 			System.out.println(con.browseMetadataRetrieve(//"gs2mgdemo", 
-					classNodeIDs));
+								      classNodeIDs, new String[]{"all"}));
 			
 			System.out.println("Testing query services");
Index: /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3DL.java
===================================================================
--- /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3DL.java	(revision 22299)
+++ /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraGS3DL.java	(revision 22300)
@@ -331,47 +331,17 @@
 	/* METHODS FOR GETTING THE STRUCTURE OF DOCUMENTS */
 
-	/** @return the XML content of the TOC of just that portion of the TOC which   
-	 * contains the section denoted by sectionID and its direct child subsections. 
-	 * The children are returned in the order they are encountered, which 
-	 * happens to be in the required order of ascending sectionID. 
-	 * @param docPID is a fedora pid identifying a greenstone document object.
-	 * @param sectionID identifies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public Element getChildrenOfSectionXML(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException;
-
-	/** @return a string representing the XML content of the TOC of just
-	 * that portion of the TOC which contains the section denoted by sectionID  
-	 * and its direct child subsections. 
-	 * The children are returned in the order they are encountered, which 
-	 * happens to be in the required order of ascending sectionID. 
-	 * @param docPID is a fedora pid identifying a greenstone document object.
-	 * @param sectionID identifies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public String getChildrenOfSection(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException, TransformerException;
-
 	/** @return the part of the TOC XML file (which outlines doc structure)  
 	 * relating to the given section. This includes the section denoted by
 	 * sectionID as well as all descendent subsections thereof. 
-	 * @param docPID is a fedora pid identifying a greenstone document object.
-	 * @param sectionID identifies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public Element getSubsectionXML(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, 
-			SAXException, IOException;
-
-	/** @return a String representation of the part of the TOC XML file   
-	 * (which outlines doc structure) relating to the given section. This    
-	 * includes the section denoted by sectionID as well as all descendent  
-	 * subsections thereof.
-	 * @param docPID is a fedora pid identifying a greenstone document object.
-	 * @param sectionID identifies the particular section in the
-	 * document denoted by docPID, may be a section name or number. */
-	public String getSubsection(String docPID, String sectionID)
-		throws RemoteException, UnsupportedEncodingException, SAXException,  
-			IOException, TransformerException;
+	 * @param docPID - a fedora pid identifying a greenstone document object.
+	 * @param sectionID - identifies the particular section in the
+	 * document denoted by docPID, may be a section name or number. 
+	 * @param structure can contain any combination of: ancestors, parent, 
+	 * siblings, children, descendants, entire, specifying the portion of 
+	 * the structure to retrieve.
+	 * @param info can contain any combination of: siblingPosition, numSiblings, 
+	 * numChildren, requesting additional information about the structure. */
+	public Element getSectionStructureXML(String docPID, String sectionID, String structure, String info)
+		throws RemoteException, UnsupportedEncodingException, SAXException, IOException;
 
 	/* BROWSING */
Index: /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraToGS3Interface.java
===================================================================
--- /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraToGS3Interface.java	(revision 22299)
+++ /other-projects/gs3-webservices-java-client/trunk/src/GS3Fedora/org/greenstone/fedora/services/FedoraToGS3Interface.java	(revision 22300)
@@ -159,49 +159,33 @@
 	
 	/* RETRIEVE SERVICE: DOCUMENT STRUCTURE RETRIEVE */
-	
-	/** @return the documentStructure of the document or section given by docID. 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message. This method returns the entire
-	 * subSection of the docID (that is, all descendents included).
-	 * @param docID the identifier for the document whose structure is required.
-	 * This is either of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" 
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-"
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the same response */
-	public String getDocumentStructure(String docID);
-	
-	/** @return a view of the structure of the document or section given by docID
-	 * which contains only the section and its direct children. This structure is 
-	 * returned in the XML format of a Greenstone3 DocumentStructureRetrieve 
-	 * response message. 
-	 * @param docID the identifier for the document whose structure is required.
-	 * This is of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-"
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the same response */
-	public String getChildren(String docID);
-	
-	/** @return the documentStructure of the documents or sections given by docIDs. 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message. This method returns the entire
-	 * subSection of each docID (that is, all descendents included).
-	 * @param docIDs an array of document identifiers whose structures are requested
-	 * These are of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectionNumber&gt;"
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the same response */
-	public String getDocumentStructure(String[] docIDs);
-	
-	/** @return the documentStructure of the documents or sections given by docIDs
-	 * but only the sections and their children (not any further descendents). 
-	 * The structure is returned in the XML format of a Greenstone3 
-	 * DocumentStructureRetrieve response message.
-	 * @param docIDs an array of document identifiers whose structures are requested
-	 * These are of the format "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;"
-	 * OR "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-&lt;sectionNumber&gt;" 
-	 * where "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;-1" is the same as 
-	 * "greenstone:&lt;collectionName&gt;-&lt;docPID&gt;" and will return the same response */
-	public String getChildren(String[] docIDs);
-	
+
+    	/** @return a String representing Greenstone3 DocumentMetadataRetrieve XML
+	 * containing the requested portion of the document structure of the documents 
+	 * indicated by docIDs: 
+	 * @param collection is the name of the collection. It's already included in the
+	 * docID for a Fedora DL.
+	 * @param docID is the document identifier of the document whose hierarchical
+	 * structure is requested. The collection name is already included in the
+	 * docID for a Fedora DL.
+	 * @param structure - strings specifying the required structure of the document. 
+	 * Any combination of: ancestors, parent, siblings, children, descendants, entire.
+	 * @param info - strings specifying the required structural info of the document. 
+	 * It can be any combination of: siblingPosition, numSiblings, numChildren.
+	*/
+	public String getDocumentStructure(String docID, String[] structure, String[] info);
+
+	/** @return a String representing Greenstone3 DocumentMetadataRetrieve XML
+	 * containing the requested portion of the document structure of the documents 
+	 * indicated by docIDs:
+	 * @param docIDs is an array of document identifiers of documents whose
+	 * hierarchical structures are requested. The collection name is already included
+	 * in the docID for a Fedora DL. 
+	 * @param structure - strings specifying the required structure of each document. 
+	 * Any combination of: ancestors, parent, siblings, children, descendants, entire.
+	 * @param info - strings specifying the required structural info of each document. 
+	 * It can be any combination of: siblingPosition, numSiblings, numChildren.
+	*/
+	public String getDocumentStructure(String[] docIDs, String[] structure, String[] info);
+
 	
 	/* RETRIEVE SERVICE: DOCUMENT METADATA RETRIEVE */
@@ -221,5 +205,5 @@
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
 	 * EX, DC, DLS metadata for all the requested documents */
-	public String getDocumentMetadata(String[] docIDs);
+    public String getDocumentMetadata(String[] docIDs, String[] metadata);
 	
 	/** Given a collectionID, returns a GS3 DocumentMetadataRetrieve 
@@ -237,5 +221,5 @@
 	 * @return a GS3 DocumentMetadataRetrieve response message containing the
 	 * EX, DC, DLS metadata for all the requested document */
-	public String getDocumentMetadata(String docID);
+    public String getDocumentMetadata(String docID, String[] metadata);
 
 	/** @return a greenstone DocumentMetadataRetrieve response for the 
@@ -245,5 +229,5 @@
 	 * In the last case, the document ID may consist of either
 	 * "documentPID-sectionNumber" or may just be just fedora documentPID */
-	public String getMetadata(String[] docIDsOrCollIDs);
+    public String getMetadata(String[] docIDsOrCollIDs, String[] metadata);
 	
 	/** Given a document identifier, returns a GS3 DocumentMetadataRetrieve 
@@ -271,7 +255,8 @@
 	 * @param classNodeIDs are the IDs of the classifierNode for which the metadata
 	 * needs to be returned
+	 * @param metafields are the classifier metadata fields that are to be returned.
 	 * @return a GS3 ClassifierBrowseMetadataRetrieve response message which 
 	 * lists the metadata for all the classifierNodes passed as parameter.*/
-	public String browseMetadataRetrieve(String[] classNodeIDs);
+	public String browseMetadataRetrieve(String[] classNodeIDs, String[] metafields);
 		
 	/** This method performs the implemented browse operation: allowing the
@@ -283,8 +268,12 @@
 	 * @param collectionName is the name of the collection whose documents 
 	 * starting with the given letter will be returned.
+	 * @param structure - the requested browse substructure. Can be any combination
+	 * of ancestors, parent, siblings, children, descendants.
+	 * @param info - the requested structural info. Can be numSiblings, siblingPosition,
+	 * numChildren
 	 * @return a GS3 DocumentStructureRetrieve response message which lists all 
 	 * the documents that start with the letter indicated by parameter classifier.
 	*/
-	public String browse(String collectionName, String[] classifierIDs);
+	public String browse(String collectionName, String[] classifierIDs, String[] structures, String[] infos);
 	
 	/* @returns the document identifiers returned for a search on the titles of 
