Index: /trunk/gli/src/org/greenstone/gatherer/util/XMLTools.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/util/XMLTools.java	(revision 14052)
+++ /trunk/gli/src/org/greenstone/gatherer/util/XMLTools.java	(revision 14053)
@@ -11,77 +11,234 @@
 import org.xml.sax.*;
 
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+// SAX
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.InputSource;
+
+// JAXP
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 
 /** This class is a static class containing useful XML functions */
-public class XMLTools
-{
+public class XMLTools {
+    /** extracts the text out of a node */
+    public static Node getNodeTextNode (Element param) {
+        param.normalize ();
+        Node n = param.getFirstChild ();
+        while (n!=null && n.getNodeType () !=Node.TEXT_NODE) {
+            n=n.getNextSibling ();
+        }
+        return n;
+    }
+    
+    /** extracts the text out of a node */
+    public static String getNodeText (Element param) {
+        Node text_node = getNodeTextNode (param);
+        if (text_node == null) {
+            return "";
+        }
+        return text_node.getNodeValue ();
+    }
+    public static void setNodeText (Element elem, String text) {
+        Node old_text_node = getNodeTextNode (elem);
+        if (old_text_node != null) {
+            elem.removeChild (old_text_node);
+        }
+        Text t = elem.getOwnerDocument ().createTextNode (text);
+        elem.appendChild (t);
+    }
+    /** returns the (first) child element with the given name */
+    public static Node getChildByTagName (Node n, String name) {
+        
+        Node child = n.getFirstChild ();
+        while (child!=null) {
+            if (child.getNodeName ().equals (name)) {
+                return child;
+            }
+            child = child.getNextSibling ();
+        }
+        return null; //not found
+    }
+    
+    /** returns the (nth) child element with the given name
+     * index numbers start at 0 */
+    public static Node getChildByTagNameIndexed (Node n, String name, int index) {
+        if (index == -1) {
+            return getChildByTagName (n, name);
+        }
+        int count = 0;
+        Node child = n.getFirstChild ();
+        while (child!=null) {
+            if (child.getNodeName ().equals (name)) {
+                if (count == index) {
+                    return child;
+                } else {
+                    count++;
+                }
+            }
+            child = child.getNextSibling ();
+        }
+        return null; //not found
+    }
+    
+    /** returns the element parent/node_name[@attribute_name='attribute_value']
+     */
+    public static Element getNamedElement (Element parent, String node_name,
+    String attribute_name,
+    String attribute_value) {
+        
+        NodeList children = parent.getChildNodes ();
+        for (int i=0; i<children.getLength (); i++) {
+            Node child = children.item (i);
+            //logger.debug("getnamed elem, node nmae="+child.getNodeName());
+            if (child.getNodeName ().equals (node_name)) {
+                if (((Element)child).getAttribute (attribute_name).equals (attribute_value))
+                    return (Element)child;
+            }
+        }
+        // not found
+        return null;
+    }
+    /** returns a list of elements parent/node_name[@attribute_name='attribute_value']
+     */
+    public static ArrayList getNamedElementList (Element parent, String node_name,
+    String attribute_name,
+    String attribute_value) {
+        ArrayList elements = new ArrayList ();
+        NodeList children = parent.getChildNodes ();
+        for (int i=0; i<children.getLength (); i++) {
+            //System.out.println("getNamedElementList");
+            Node child = children.item (i);
+            //logger.debug("getnamed elem, node nmae="+child.getNodeName());
+            if (child.getNodeName ().equals (node_name)) {
+                if (((Element)child).getAttribute (attribute_name).equals (attribute_value))
+                    elements.add ((Element)child);
+            }
+        }
+        // not found
+        if (elements.size () == 0) {
+            elements = null;
+        }
+        return elements;
+    }
+    public static void copyAllChildren (Element to, Element from) {
+        
+        Document to_doc = to.getOwnerDocument ();
+        Node child = from.getFirstChild ();
+        while (child != null) {
+            to.appendChild (to_doc.importNode (child, true));
+            child = child.getNextSibling ();
+        }
+    }
+    /** Duplicates an element */
+    public static Element duplicateElement (Document owner, Element element, boolean with_attributes) {
+        return duplicateElementNS (owner, element, null, with_attributes);
+    }
+    
+    /** Duplicates an element */
+    public static Element duplicateElementNS (Document owner,
+    Element element,
+    String namespace_uri,
+    boolean with_attributes) {
+        Element duplicate;
+        if (namespace_uri == null) {
+            duplicate = owner.createElement (element.getTagName ());
+        } else {
+            duplicate = owner.createElementNS (namespace_uri, element.getTagName ());
+        }
+        // Copy element attributes
+        if (with_attributes) {
+            NamedNodeMap attributes = element.getAttributes ();
+            for (int i = 0; i < attributes.getLength (); i++) {
+                Node attribute = attributes.item (i);
+                duplicate.setAttribute (attribute.getNodeName (), attribute.getNodeValue ());
+            }
+        }
+        
+        // Copy element children
+        NodeList children = element.getChildNodes ();
+        for (int i = 0; i < children.getLength (); i++) {
+            Node child = children.item (i);
+            duplicate.appendChild (owner.importNode (child, true));
+        }
+        
+        return duplicate;
+    }
+    
+    
     /** Remove all of the child nodes from a certain node. */
-    static final public void clear(Node node)
-    {
-	while (node.hasChildNodes()) {
-	    node.removeChild(node.getFirstChild());
-	}
-    }
-
-
-    static public ArrayList getChildElementsByTagName(Element parent_element, String element_name)
-    {
-	ArrayList child_elements = new ArrayList();
-
-	NodeList children_nodelist = parent_element.getChildNodes();
-	for (int i = 0; i < children_nodelist.getLength(); i++) {
-	    Node child_node = children_nodelist.item(i);
-	    if (child_node.getNodeType() == Node.ELEMENT_NODE && child_node.getNodeName().equals(element_name)) {
-		child_elements.add(child_node);
-	    }
-	}
-
-	return child_elements;
-    }
-
-
-    static public String getElementTextValue(Element element)
-    {
-	// Find the first text node child
-	NodeList children_nodelist = element.getChildNodes();
-	for (int i = 0; i < children_nodelist.getLength(); i++) {
-	    Node child_node = children_nodelist.item(i);
-	    if (child_node.getNodeType() == Node.TEXT_NODE) {
-		return child_node.getNodeValue();
-	    }
-	}
-
-	// None found
-	return "";
-    }
-
-
+    static final public void clear (Node node) {
+        while (node.hasChildNodes ()) {
+            node.removeChild (node.getFirstChild ());
+        }
+    }
+    
+    
+    static public ArrayList getChildElementsByTagName (Element parent_element, String element_name) {
+        ArrayList child_elements = new ArrayList ();
+        
+        NodeList children_nodelist = parent_element.getChildNodes ();
+        for (int i = 0; i < children_nodelist.getLength (); i++) {
+            Node child_node = children_nodelist.item (i);
+            if (child_node.getNodeType () == Node.ELEMENT_NODE && child_node.getNodeName ().equals (element_name)) {
+                child_elements.add (child_node);
+            }
+        }
+        
+        return child_elements;
+    }
+    
+    
+    static public String getElementTextValue (Element element) {
+        // Find the first text node child
+        NodeList children_nodelist = element.getChildNodes ();
+        for (int i = 0; i < children_nodelist.getLength (); i++) {
+            Node child_node = children_nodelist.item (i);
+            if (child_node.getNodeType () == Node.TEXT_NODE) {
+                return child_node.getNodeValue ();
+            }
+        }
+        
+        // None found
+        return "";
+    }
+    
+    
     /** Method to retrieve the value of a given node.
      * @param element The <strong>Element</strong> whose value we wish to find.
      * Soon to be deprecated!
      */
-    static final public String getValue(Node element) {
-	if (element == null) {
-	    return "";
-	}
-	// If we've been given a subject node first retrieve its value node.
-	if(element.getNodeName().equals("Subject")) {
-	    element = getNodeFromNamed(element, "Value");
-	}
-	// If we've got a value node, then reconstruct the text. Remember that DOM will split text over 256 characters into several text nodes
-	if(element != null && element.hasChildNodes()) {
-	    StringBuffer text_buffer = new StringBuffer();
-	    NodeList text_nodes = element.getChildNodes();
-	    for(int i = 0; i < text_nodes.getLength(); i++) {
-		Node possible_text = text_nodes.item(i);
-		if(possible_text.getNodeName().equals(StaticStrings.TEXT_NODE)) {
-		    text_buffer.append(possible_text.getNodeValue());
-		}
-	    }
-	    return text_buffer.toString();
-	}
-	return "";
-    }
-
-
+    static final public String getValue (Node element) {
+        if (element == null) {
+            return "";
+        }
+        // If we've been given a subject node first retrieve its value node.
+        if(element.getNodeName ().equals ("Subject")) {
+            element = getNodeFromNamed (element, "Value");
+        }
+        // If we've got a value node, then reconstruct the text. Remember that DOM will split text over 256 characters into several text nodes
+        if(element != null && element.hasChildNodes ()) {
+            StringBuffer text_buffer = new StringBuffer ();
+            NodeList text_nodes = element.getChildNodes ();
+            for(int i = 0; i < text_nodes.getLength (); i++) {
+                Node possible_text = text_nodes.item (i);
+                if(possible_text.getNodeName ().equals (StaticStrings.TEXT_NODE)) {
+                    text_buffer.append (possible_text.getNodeValue ());
+                }
+            }
+            return text_buffer.toString ();
+        }
+        return "";
+    }
+    
+    
     /** Method to retrieve from the node given, a certain child node with the specified name.
      * @param parent The <strong>Node</strong> whose children should be searched.
@@ -89,168 +246,274 @@
      * @return The requested <strong>Node</strong> if it is found, <i>null</i> otherwise.
      * Soon to be deprecated!
-     */ 
-    static final public Node getNodeFromNamed(Node parent, String name) {
-	Node child = null;
-	for(Node i = parent.getFirstChild(); i != null && child == null; 
-	    i = i.getNextSibling()) {
-	    if(i.getNodeName().equals(name)) {
-		child = i;
-	    }
-	}
-	return child;
-    }
-
+     */
+    static final public Node getNodeFromNamed (Node parent, String name) {
+        Node child = null;
+        for(Node i = parent.getFirstChild (); i != null && child == null;
+        i = i.getNextSibling ()) {
+            if(i.getNodeName ().equals (name)) {
+                child = i;
+            }
+        }
+        return child;
+    }
+    
+    static final public String WELLFORMED= "well-formed !";
+    static final public String NOTWELLFORMED= "not well-formed";
+    static final private String HEADER = "<?xml version='1.0' encoding='UTF-8'?><collectionConfig xmlns:gsf='http://www.greenstone.org/greenstone3/schema/ConfigFormat' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>";
+	static final private String FOOTER = "</collectionConfig>";
+       
+public static String parse (String xml_str) {
+        String validation_msg = WELLFORMED;
+        xml_str = HEADER + xml_str + FOOTER;
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance ();
+            factory.setNamespaceAware (true);
+            //factory.setValidating (true);
+            SAXParser parser = factory.newSAXParser ();
+            InputSource iSource = new InputSource ( new StringReader ( xml_str ) );
+//              parser.parse (iSource, new DefaultHandler ());
+            
+            org.xml.sax.XMLReader reader = parser.getXMLReader ();
+            reader.setContentHandler(new DefaultHandler());
+            reader.setErrorHandler(new DefaultHandler());
+            reader.parse(iSource);
+        } catch (FactoryConfigurationError e) {
+            validation_msg = "unable to get a document builder factory";
+        } catch (ParserConfigurationException e) {
+            validation_msg = "unable to configure parser";
+        } catch (SAXParseException e) {
+            validation_msg = NOTWELLFORMED + getLocationString(e) + e.getMessage ();
+        } catch (SAXException e) {
+            validation_msg += " Fatal error: " + e.toString ();
+        } catch (IOException e) {
+            validation_msg = "Unable to read the input, i/o error";
+        }
+        
+        return validation_msg;
+    }
+//In this method, the parsed string xml_str is not wrapped by the header and footer strings.
+public static String parseDOM (String xml_str) {
+        String validation_msg = WELLFORMED;
+        
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance ();
+            factory.setNamespaceAware (true);
+            //factory.setValidating (true);
+            SAXParser parser = factory.newSAXParser ();
+            InputSource iSource = new InputSource ( new StringReader ( xml_str ) );
+//              parser.parse (iSource, new DefaultHandler ());
+            
+            org.xml.sax.XMLReader reader = parser.getXMLReader ();
+            reader.setContentHandler(new DefaultHandler());
+            reader.setErrorHandler(new DefaultHandler());
+            reader.parse(iSource);
+        } catch (FactoryConfigurationError e) {
+            validation_msg = "unable to get a document builder factory";
+        } catch (ParserConfigurationException e) {
+            validation_msg = "unable to configure parser";
+        } catch (SAXParseException e) {
+            validation_msg = NOTWELLFORMED + getLocationString(e) + e.getMessage ();
+        } catch (SAXException e) {
+            validation_msg += " " + e.toString ();
+        } catch (IOException e) {
+            validation_msg = "Unable to read the input, i/o error";
+        }
+        
+        return validation_msg;
+    }
+
+public static String parse (File xml_file) {
+        String validation_msg = WELLFORMED;
+
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance ();
+            factory.setNamespaceAware (true);
+            //factory.setValidating (true);
+            SAXParser parser = factory.newSAXParser ();
+            FileReader r = new FileReader(xml_file);
+	        InputSource iSource = new InputSource(r);
+            XMLReader reader = parser.getXMLReader ();
+            reader.setContentHandler(new DefaultHandler());
+            reader.setErrorHandler(new DefaultHandler());
+            reader.parse(iSource);
+        } catch (FactoryConfigurationError e) {
+            validation_msg = "unable to get a document builder factory";
+        } catch (ParserConfigurationException e) {
+            validation_msg = "unable to configure parser";
+        } catch (SAXParseException e) {
+            validation_msg = NOTWELLFORMED + getLocationString(e) + e.getMessage ();
+        } catch (SAXException e) {
+            validation_msg += " Fatal error: " + e.toString ();
+        } catch (IOException e) {
+            validation_msg = "Unable to read the input, i/o error";
+        }
+        
+        return validation_msg;
+    }    
+    /** Returns a string of the location. */
+    private static String getLocationString(SAXParseException ex) {
+        StringBuffer str = new StringBuffer();
+
+        String systemId = ex.getSystemId();
+        if (systemId != null) {
+            int index = systemId.lastIndexOf('/');
+            if (index != -1)
+                systemId = systemId.substring(index + 1);
+            str.append(systemId);
+        }
+        str.append("(line ");
+        str.append(ex.getLineNumber()-1);
+        str.append(", column ");
+        str.append(ex.getColumnNumber());
+        str.append("): ");
+
+        return str.toString();
+
+    } // getLocationString(SAXParseException):String
 
     /** Parse an XML document from a given file path */
-    static public Document parseXMLFile(String xml_file_path, boolean use_class_loader)
-    {
-	if (use_class_loader == true) {
-	    InputStream is = JarTools.getResourceAsStream("/" + xml_file_path);
-	    if (is != null) {
-		return parseXML(is);
-	    }
-	}
-
- 	// Try the file outside the classes directory
- 	return parseXMLFile(new File(xml_file_path));
-    }
-
-
+    static public Document parseXMLFile (String xml_file_path, boolean use_class_loader) {
+        if (use_class_loader == true) {
+            InputStream is = JarTools.getResourceAsStream ("/" + xml_file_path);
+            if (is != null) {
+                return parseXML (is);
+            }
+        }
+        
+        // Try the file outside the classes directory
+        return parseXMLFile (new File (xml_file_path));
+    }
+    
+    
     /** Parse an XML document from a given file */
-    static public Document parseXMLFile(File xml_file)
-    {
-	// No file? No point trying!
-	if (xml_file.exists() == false) {
-	    return null;
-	}
-
-	try {
-	    return parseXML(new FileInputStream(xml_file));
-	}
-	catch (Exception exception) {
-	    DebugStream.printStackTrace(exception);
-	    return null;
-	}
-    }
-
-
+    static public Document parseXMLFile (File xml_file) {
+        // No file? No point trying!
+        if (xml_file.exists () == false) {
+            return null;
+        }
+        
+        try {
+            return parseXML (new FileInputStream (xml_file));
+        }
+        catch (Exception exception) {
+            DebugStream.printStackTrace (exception);
+            return null;
+        }
+    }
+    
+    
     /** Parse an XML document from a given input stream */
-    static public Document parseXML(InputStream xml_input_stream)
-    {
-	Document document = null;
-
-	try {
-	    InputStreamReader isr = new InputStreamReader(xml_input_stream, "UTF-8");
-	    Reader xml_reader = new BufferedReader(isr);
-	    document = parseXML(xml_reader);
-	    isr.close();
-	    xml_input_stream.close();
-	}
-	catch (Exception exception) {
-	    DebugStream.printStackTrace(exception);
-	}
-
-	return document;
-    }
-
-
+    static public Document parseXML (InputStream xml_input_stream) {
+        Document document = null;
+        
+        try {
+            InputStreamReader isr = new InputStreamReader (xml_input_stream, "UTF-8");
+            Reader xml_reader = new BufferedReader (isr);
+            document = parseXML (xml_reader);
+            isr.close ();
+            xml_input_stream.close ();
+        }
+        catch (Exception exception) {
+            DebugStream.printStackTrace (exception);
+        }
+        
+        return document;
+    }
+    
+    
     /** Parse an XML document from a given reader */
-    static public Document parseXML(Reader xml_reader)
-    {
-	Document document = null;
-
-	try {
-	    InputSource isc       = new InputSource(xml_reader);
-	    DOMParser parser      = new DOMParser();
-	    parser.setFeature("http://xml.org/sax/features/validation", false);
-	    parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
-	    // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
-	    parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
-	    parser.setFeature("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
-	    parser.parse(isc);
-	    document = parser.getDocument();
-	}
-	catch (SAXException exception) {
-	    System.err.println("SAX exception: " + exception.getMessage());
-	    DebugStream.printStackTrace(exception);
-	}
-	catch (Exception exception) {
-	    DebugStream.printStackTrace(exception);
-	}
-
-	return document;
-    }
-
-
-    static public StringBuffer readXMLStream(InputStream input_stream)
-    {
-	StringBuffer xml = new StringBuffer("");
-
-	try {
-	    InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
-	    BufferedReader buffered_in = new BufferedReader(isr);
-
-	    String line = "";
-	    boolean xml_content = false;
-	    while((line = buffered_in.readLine()) != null) {
-		if(xml_content) {
-		    xml.append(line);
-		    xml.append("\n");
-		}
-		else if(line.trim().startsWith("<?xml")) {
-		    xml_content = true;
-		    xml.append(line);
-		    xml.append("\n");
-		}
-	    }
-	    buffered_in = null;
-	}
-	catch (Exception error) {
-	    System.err.println("Failed when trying to parse XML stream");
-	    error.printStackTrace();
-	}
-
-	return xml;
-    }
-
-
+    static public Document parseXML (Reader xml_reader) {
+        Document document = null;
+        
+        try {
+            InputSource isc       = new InputSource (xml_reader);
+            DOMParser parser      = new DOMParser ();
+            parser.setFeature ("http://xml.org/sax/features/validation", false);
+            parser.setFeature ("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+            // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
+            parser.setFeature ("http://apache.org/xml/features/dom/defer-node-expansion", true);
+            parser.setFeature ("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
+            parser.parse (isc);
+            document = parser.getDocument ();
+        }
+        catch (SAXException exception) {
+            System.err.println ("SAX exception: " + exception.getMessage ());
+            DebugStream.printStackTrace (exception);
+        }
+        catch (Exception exception) {
+            DebugStream.printStackTrace (exception);
+        }
+        
+        return document;
+    }
+    
+    
+    static public StringBuffer readXMLStream (InputStream input_stream) {
+        StringBuffer xml = new StringBuffer ("");
+        
+        try {
+            InputStreamReader isr = new InputStreamReader (input_stream, "UTF-8");
+            BufferedReader buffered_in = new BufferedReader (isr);
+            
+            String line = "";
+            boolean xml_content = false;
+            while((line = buffered_in.readLine ()) != null) {
+                if(xml_content) {
+                    xml.append (line);
+                    xml.append ("\n");
+                }
+                else if(line.trim ().startsWith ("<?xml")) {
+                    xml_content = true;
+                    xml.append (line);
+                    xml.append ("\n");
+                }
+            }
+            buffered_in = null;
+        }
+        catch (Exception error) {
+            System.err.println ("Failed when trying to parse XML stream");
+            error.printStackTrace ();
+        }
+        
+        return xml;
+    }
+    
+    
     /** Removes characters that are invalid in XML (see http://www.w3.org/TR/2000/REC-xml-20001006#charsets) */
-    static public String removeInvalidCharacters(String text)
-    {
-	char[] safe_characters = new char[text.length()];
-	int j = 0;
-
-	char[] raw_characters = new char[text.length()];
-	text.getChars(0, text.length(), raw_characters, 0);
-	for (int i = 0; i < raw_characters.length; i++) {
-	    char character = raw_characters[i];
-	    if ((character >= 0x20 && character <= 0xD7FF) || character == 0x09 || character == 0x0A || character == 0x0D || (character >= 0xE000 && character <= 0xFFFD) || (character >= 0x10000 && character <= 0x10FFFF)) {
-		safe_characters[j] = character;
-		j++;
-	    }
-	}
-
-	return new String(safe_characters, 0, j);
-    }
-
-
-    static public void setElementTextValue(Element element, String text)
-    {
-	// Remove all text node children
-	NodeList children_nodelist = element.getChildNodes();
-	for (int i = children_nodelist.getLength() - 1; i >= 0; i--) {
-	    Node child_node = children_nodelist.item(i);
-	    if (child_node.getNodeType() == Node.TEXT_NODE) {
-		element.removeChild(child_node);
-	    }
-	}
-
-	// Add a new text node
-	if (text != null) {
-	    element.appendChild(element.getOwnerDocument().createTextNode(text));
-	}
-    }
-
-
+    static public String removeInvalidCharacters (String text) {
+        char[] safe_characters = new char[text.length ()];
+        int j = 0;
+        
+        char[] raw_characters = new char[text.length ()];
+        text.getChars (0, text.length (), raw_characters, 0);
+        for (int i = 0; i < raw_characters.length; i++) {
+            char character = raw_characters[i];
+            if ((character >= 0x20 && character <= 0xD7FF) || character == 0x09 || character == 0x0A || character == 0x0D || (character >= 0xE000 && character <= 0xFFFD) || (character >= 0x10000 && character <= 0x10FFFF)) {
+                safe_characters[j] = character;
+                j++;
+            }
+        }
+        
+        return new String (safe_characters, 0, j);
+    }
+    
+    
+    static public void setElementTextValue (Element element, String text) {
+        // Remove all text node children
+        NodeList children_nodelist = element.getChildNodes ();
+        for (int i = children_nodelist.getLength () - 1; i >= 0; i--) {
+            Node child_node = children_nodelist.item (i);
+            if (child_node.getNodeType () == Node.TEXT_NODE) {
+                element.removeChild (child_node);
+            }
+        }
+        
+        // Add a new text node
+        if (text != null) {
+            element.appendChild (element.getOwnerDocument ().createTextNode (text));
+        }
+    }
+    
+    
     /** Set the #text node value of some element.
      * @param element the Element whose value we wish to set
@@ -258,87 +521,221 @@
      * Soon to be deprecated!
      */
-    static final public void setValue(Element element, String value) {
-	// Remove any existing child node(s)
-	clear(element);
-	// Add new text node.
-	if (value != null) {
-	    element.appendChild(element.getOwnerDocument().createTextNode(value));
-	}
-    }
-
-
+    static final public void setValue (Element element, String value) {
+        // Remove any existing child node(s)
+        clear (element);
+        // Add new text node.
+        if (value != null) {
+            element.appendChild (element.getOwnerDocument ().createTextNode (value));
+        }
+    }
+    
+    /** Write an XML document to a given file with the text node of the specified element unescaped*/
+    static public void writeXMLFile (File xml_file, Document document, String[] nonEscapingTagNames) {
+        try {
+            OutputStream os = new FileOutputStream (xml_file);
+            // Create an output format for our document.
+            OutputFormat f = new OutputFormat (document);
+            f.setEncoding ("UTF-8");
+            f.setIndenting (true);
+            f.setLineWidth (0); // Why isn't this working!
+            f.setPreserveSpace (false);
+            
+            f.setNonEscapingElements (nonEscapingTagNames);
+            // Create the necessary writer stream for serialization.
+            OutputStreamWriter osw = new OutputStreamWriter (os, "UTF-8");
+            Writer w               = new BufferedWriter (osw);
+            // Generate a new serializer from the above.
+            XMLSerializer s        = new XMLSerializer (w, f);
+            s.asDOMSerializer ();
+            // Finally serialize the document to file.
+            s.serialize (document);
+            // And close.
+            os.close ();
+        }
+        catch (Exception exception) {
+            DebugStream.printStackTrace (exception);
+        }
+    }
+    
     /** Write an XML document to a given file */
-    static public void writeXMLFile(File xml_file, Document document)
-    {
-	try {
-	    OutputStream os = new FileOutputStream(xml_file);
-	    // Create an output format for our document.
-	    OutputFormat f = new OutputFormat(document);
-	    f.setEncoding("UTF-8");
-	    f.setIndenting(true);
-	    f.setLineWidth(0); // Why isn't this working!
-	    f.setPreserveSpace(false);
-	    // Create the necessary writer stream for serialization.
-	    OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
-	    Writer w               = new BufferedWriter(osw);
-	    // Generate a new serializer from the above.
-	    XMLSerializer s        = new XMLSerializer(w, f);
-	    s.asDOMSerializer();
-	    // Finally serialize the document to file.
-	    s.serialize(document);
-	    // And close.
-	    os.close();
-	}
-	catch (Exception exception) {
-	    DebugStream.printStackTrace(exception);
-	}
-    }
-
-    public static void printXMLNode(Node e) {
-	printXMLNode(e, 0) ;
-    }
- 
- public static void printXMLNode(Node e, int depth) { //recursive method call using DOM API...
-	
-	for (int i=0 ; i<depth ; i++) 
-	    System.out.print(' ') ;
-
-	if (e.getNodeType() == Node.TEXT_NODE){
-	    System.out.println("text") ;
-	    //System.out.println(e.getNodeValue()) ;
-	    return ;
-	}
-	
-	System.out.print('<');
-	System.out.print(e.getNodeName());
-	NamedNodeMap attrs = e.getAttributes();
-	for (int i = 0; i < attrs.getLength(); i++) {
-	    Node attr = attrs.item(i);
-	    System.out.print(' ');  
-	    System.out.print(attr.getNodeName());
-	    System.out.print("=\"");
-	    System.out.print(attr.getNodeValue());   
-	    System.out.print('"');
-	}
-
-	NodeList children = e.getChildNodes();
-
-	if (children == null || children.getLength() == 0)
-	    System.out.println("/>") ;
-	else {
-	    
-	    System.out.println('>') ;
-	    
-	    int len = children.getLength();
-	    for (int i = 0; i < len; i++) {
-		printXMLNode(children.item(i), depth + 1);
-	    }
-	    
-	    for (int i=0 ; i<depth ; i++) 
-		System.out.print(' ') ;
-	    
-	    System.out.println("</" + e.getNodeName() + ">");
-	}	
-
-    }
+    static public void writeXMLFile (File xml_file, Document document) {
+        try {
+            OutputStream os = new FileOutputStream (xml_file);
+            // Create an output format for our document.
+            OutputFormat f = new OutputFormat (document);
+            f.setEncoding ("UTF-8");
+            f.setIndenting (true);
+            f.setLineWidth (0); // Why isn't this working!
+            f.setPreserveSpace (false);
+            // Create the necessary writer stream for serialization.
+            OutputStreamWriter osw = new OutputStreamWriter (os, "UTF-8");
+            Writer w               = new BufferedWriter (osw);
+            // Generate a new serializer from the above.
+            XMLSerializer s        = new XMLSerializer (w, f);
+            s.asDOMSerializer ();
+            // Finally serialize the document to file.
+            s.serialize (document);
+            // And close.
+            os.close ();
+        }
+        catch (Exception exception) {
+            DebugStream.printStackTrace (exception);
+        }
+    }
+    
+    public static void printXMLNode (Node e) {
+        printXMLNode (e, 0) ;
+    }
+    
+    public static void printXMLNode (Node e, int depth) { //recursive method call using DOM API...
+        
+        for (int i=0 ; i<depth ; i++)
+            System.out.print (' ') ;
+        
+        if (e.getNodeType () == Node.TEXT_NODE){
+            //System.out.println("text") ;
+            if (e.getNodeValue () != "") {
+                System.out.println (e.getNodeValue ()) ;
+            }
+            return ;
+        }
+        
+        System.out.print ('<');
+        System.out.print (e.getNodeName ());
+        NamedNodeMap attrs = e.getAttributes ();
+        if (attrs != null) {
+            for (int i = 0; i < attrs.getLength (); i++) {
+                Node attr = attrs.item (i);
+                System.out.print (' ');
+                System.out.print (attr.getNodeName ());
+                System.out.print ("=\"");
+                System.out.print (attr.getNodeValue ());
+                System.out.print ('"');
+            }
+        }
+        NodeList children = e.getChildNodes ();
+        
+        if (children == null || children.getLength () == 0)
+            System.out.println ("/>") ;
+        else {
+            
+            System.out.println ('>') ;
+            
+            int len = children.getLength ();
+            for (int i = 0; i < len; i++) {
+                printXMLNode (children.item (i), depth + 1);
+            }
+            
+            for (int i=0 ; i<depth ; i++)
+                System.out.print (' ') ;
+            
+            System.out.println ("</" + e.getNodeName () + ">");
+        }
+        
+    }
+    public static String xmlNodeToString (Node e){
+        StringBuffer sb = new StringBuffer ("");
+        xmlNodeToString (sb,e,0);
+        return sb.toString ();
+    }
+    
+    private static void xmlNodeToString (StringBuffer sb, Node e, int depth){
+        
+        for (int i=0 ; i<depth ; i++)
+            sb.append (' ') ;
+        
+        if (e.getNodeType () == Node.TEXT_NODE){
+            if (e.getNodeValue () != "") {
+                sb.append (e.getNodeValue ()) ;
+            }
+            return ;
+        }
+        
+        sb.append ('<');
+        sb.append (e.getNodeName ());
+        NamedNodeMap attrs = e.getAttributes ();
+        if (attrs != null) {
+            for (int i = 0; i < attrs.getLength (); i++) {
+                Node attr = attrs.item (i);
+                sb.append (' ');
+                sb.append (attr.getNodeName ());
+                sb.append ("=\"");
+                sb.append (attr.getNodeValue ());
+                sb.append ('"');
+            }
+        }
+        NodeList children = e.getChildNodes ();
+        
+        if (children == null || children.getLength () == 0)
+            sb.append ("/>\n") ;
+        else {
+            
+            sb.append (">\n") ;
+            
+            int len = children.getLength ();
+            for (int i = 0; i < len; i++) {
+                xmlNodeToString (sb,children.item (i), depth + 1);
+            }
+            
+            for (int i=0 ; i<depth ; i++)
+                sb.append (' ') ;
+            
+            sb.append ("</" + e.getNodeName () + ">\n");
+        }
+        
+        
+    }
+    public static String xmlNodeToStringWithoutNewline (Node e){
+        StringBuffer sb = new StringBuffer ("");
+        xmlNodeToStringWithoutNewline (sb,e,0);
+        return sb.toString ();
+    }
+    
+    private static void xmlNodeToStringWithoutNewline (StringBuffer sb, Node e, int depth){
+        
+        for (int i=0 ; i<depth ; i++)
+            sb.append (' ') ;
+        
+        if (e.getNodeType () == Node.TEXT_NODE){
+            if (e.getNodeValue () != "") {
+                sb.append (e.getNodeValue ()) ;
+            }
+            return ;
+        }
+        
+        sb.append ('<');
+        sb.append (e.getNodeName ());
+        NamedNodeMap attrs = e.getAttributes ();
+        if (attrs != null) {
+            for (int i = 0; i < attrs.getLength (); i++) {
+                Node attr = attrs.item (i);
+                sb.append (' ');
+                sb.append (attr.getNodeName ());
+                sb.append ("=\"");
+                sb.append (attr.getNodeValue ());
+                sb.append ('"');
+            }
+        }
+        NodeList children = e.getChildNodes ();
+        
+        if (children == null || children.getLength () == 0)
+            sb.append ("/>") ;
+        else {
+            
+            sb.append (">") ;
+            
+            int len = children.getLength ();
+            for (int i = 0; i < len; i++) {
+                xmlNodeToStringWithoutNewline (sb,children.item (i), depth + 1);
+            }
+            
+            for (int i=0 ; i<depth ; i++)
+                sb.append (' ') ;
+            
+            sb.append ("</" + e.getNodeName () + ">");
+        }
+        
+        
+    }
+    
 }
