Menu

Write data back to XML files

2005-02-24
2013-04-09
  • TomWiedenhoeft

    TomWiedenhoeft - 2005-02-24

    Hallo, again!

    Here are two another classes that might interest you.

    Benefit:
    Provides a way to write data back into XML files.
    Example:
    - Documentation of status and error messages (in a GUI).
    - To modify files that hold test data (might be used by robots that follow up).

    The CreateXMLFileTagHandler.java creates a file and inserts a XML element.
    The AddElementToXMLFileTagHandler.java adds or overwrites XML elements in a file.

    If you think the classes are usefull for you or other users please intergrate it into the official version.
    We hope this small contibution will help to spread and develop JFC-Unit.

    Thanks a lot.
    Tom Wiedenhoeft

    P.S. Please note to modify the files XMLConstants.java and TagMapping.properties as shown below.

    ---schnipp  -- CreateXMLFileTagHandler.java ---package junit.extensions.xml.elements;

    import junit.extensions.xml.IXMLTestCase;
    import junit.extensions.xml.XMLException;

    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import org.jdom.output.XMLOutputter;
    import org.jdom.Document;
    import org.w3c.dom.Element;

    import java.util.StringTokenizer;

    /**
    * This tag handler creates an XML file and inserts
    * an XML element with a  value.
    *
    * <h3>Description</h3>
    * <pre>
    * &lt;createXMLFile
    *         id=&quot;myid&quot;
    *         file=&quot;c:/tmp/my.xml&quot;
    *         xpath=&quot;/AA/BB&quot;
    *         value=&quot;Oktoberfest in Munich&quot;/&gt;
    * </pre>
    * <p>
    * All atributes are mandatory except value.
    * </p>
    * <p>
    * Remember to use an absolute xPath with a leading &quot;/&quot;.
    * Examples: xpath=&quot;/AA/BB&quot;, xpath=&quot;/AA&quot;.
    * </p>
    * <p>
    * References to the file will be accessible by<br>
    * - &quot;id&quot; for the java.io.File. Example &quot;bag&quot;.<br>
    * - &quot;id.name&quot; for the name of the file.
    *   Example &quot;bag.name&quot; to get &quot;12.xml&quot;.<br>
    * - &quot;id.path&quot; for the absolut path.
    *   Example &quot;bag.path&quot; to get &quot;c:/tmp/12.xml&quot;.<br>
    * - &quot;id.dir&quot; for the directory.
    *   Example &quot;bag.dir&quot; to get &quot;c:/tmp&quot;.<br>
    * </p>
    * @author tom@smart-tail.com (Tom Wiedenhoeft, DV-Ratio acting under contract with Siemens L&A PA)
    */
    public class CreateXMLFileTagHandler extends AbstractTagHandler {
        /**
         * constructor.
         * @param element Element to be processed.
         * @param testCase containing test case.
         */
        public CreateXMLFileTagHandler(final Element element,
            final IXMLTestCase testCase) {
            super(element, testCase);
        }

        /**
         * Get the value of the id attribute.
         * @return String value of the id attribute.
         */
        public String getId() {
            return getString(ID);
        }

        /**
         * Get the file attribute from the element.
         * @return String The value of the file attribute.
         */
        public String getFile() {
            return getString(FILE);
        }

        /**
         * Get the xpath of the xmlElement attribute.
         * @return String value of the xpath attribute.
         */
        public String getXPath() {
            return getString(XPATH);
        }

        /**
         * Get the value of the value attribute.
         * @return String value of the value attribute.
         */
        public String getValue() {
            return getString(VALUE);
        }

        /**
         * Process the element.
         * Stores an object of type java.io.File for later usage in the cache.
         * This object is later accessable via the property "id".
         * @throws XMLException may be thrown.
         */
        public void processElement() throws XMLException {
            validateElement();
            // Get the attribute value
            String id = this.getId();
            // Get the file
            File file = this.writeFile();
            String name = null;
            String path = null;
            String dir = null;
            if(file != null)
            {
                name = file.getName();
                path = file.getAbsolutePath();
                dir = file.getParent().toString();
            }
            // Store the file
            getXMLTestCase().addProperty(id, file);
            getXMLTestCase().addProperty(id + "." + NAME, name);
            getXMLTestCase().addProperty(id + "." + ABSOLUTE_PATH, path);
            getXMLTestCase().addProperty(id + "." + DIRECTORY, dir);
        }

        /**
         * Validate that the element is properly configured.
         * @throws XMLException Exception may be thrown if there
         * are missing elements.
         */
        public void validateElement() throws XMLException {
            // check the element tag name
            checkElementTagName(CREATE_XML_FILE);

            checkRequiredAttribute(ID);

            checkRequiredAttribute(FILE);

            checkRequiredAttribute(XPATH);
            String xpath = this.getXPath();
            if("".equals(xpath))
            {
                throw new XMLException("Attribute 'xpath' is empty.",
                        null,
                        getElement(),
                        getTest().getPropertyCache());
            }
        }

        /**
         * Creates a JDOM document according to the xPath and
         * writes it to a file.
         *
         * @return java.io.File where a matching element was found.
         * @throws XMLException
         */
        private File writeFile() throws XMLException
        {
            // Get the attribute values
            String file = this.getFile();
            String xpath = this.getXPath();
            String value = this.getValue();
            if(value == null)
            {
                value = "";
            }

            // Check the directory
            File f = new File(file);
            File directory = f.getParentFile();
            if(! directory.exists())
            {
                throw new XMLException("Directory does not exist: " + directory,
                    null,
                    getElement(),
                    getTest().getPropertyCache());
            }
            if(! directory.isDirectory())
            {
                throw new XMLException(directory + " is not a directory.",
                    null,
                    getElement(),
                    getTest().getPropertyCache());
            }
            // Check for file with identical name and change the name
            // to a file name with a leading digit.
            // Example: If "fbag.xml" exists already name it "1fbag.xml".
            String fileNameOriginal = f.getName();
            int i = 1;
            while(f.exists())
            {
                String fileName = f.getName();
                file = directory + File.separator + i++ + fileNameOriginal;
                f = new File(file);
            }

            // Create the document
            org.jdom.Document doc = new org.jdom.Document();
            org.jdom.Element parentElement = null;
            // Look into the attribute xpath.
            // Navigate through the xpath (XML element to create).
            // Example: xpath = //AA/BB makes <AA><BB></BB></AA>).
            StringTokenizer st = new StringTokenizer(xpath, "/");
            while(st.hasMoreElements())
            {
                String elementName = st.nextToken();
                if("".equals(elementName))
                {
                    continue;
                }
                org.jdom.Element e = new org.jdom.Element(elementName);
                if(parentElement == null)
                {
                    doc.setRootElement(e);
                }
                else
                {
                    e.setText(value);
                    parentElement.addContent(e);
                }
                parentElement = e;
            }

            // Write the created document to file
            XMLOutputter outp = new XMLOutputter();
            outp.setIndent("  ");
            outp.setNewlines(true);
            BufferedOutputStream out = null;
            try {
                out = new BufferedOutputStream(new FileOutputStream(file));
                outp.output(doc, out);
            } catch(IOException e) {
                e.printStackTrace();
                throw new XMLException(
                        "Filed to write document for " + file + ". " + e.getMessage(),
                        null,
                        getElement(),
                        getTest().getPropertyCache());
            } finally {
                if(out != null)
                {
                    try {
                        out.close();
                    } catch(IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
            return f;
        }
    }

    ---schnapp -- CreateXMLFileTagHandler.java ---

    ---schnipp -- AddElementToXMLFileTagHandler.java ---

    package junit.extensions.xml.elements;

    import junit.extensions.xml.IXMLTestCase;
    import junit.extensions.xml.XMLException;

    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.StringTokenizer;

    import org.jdom.input.SAXBuilder;
    import org.jdom.output.XMLOutputter;
    import org.jdom.Document;
    import org.jdom.JDOMException;
    import org.w3c.dom.Element;

    /**
    * This is tag handler inserts a XML element into an XML file.
    * <p>
    * <h3>Example 1  - adds an element</h3>
    * <p>
    * Provided you have a file containing:
    * </p>
    * <pre>
    * &lt;AA&gt;&lt;BB&gt;Oktoberfest in Munich&lt;/BB&gt;&lt;/AA&gt;
    * </pre>
    * <p>
    * and want to insert a new element like this
    * </p>
    * <pre>
    * &lt;AA&gt;&lt;BB&gt;Oktoberfest in Munich&lt;/BB&gt;&lt;BB&gt;starts now&lt;/BB&gt;&lt;/AA&gt;
    * </pre>
    * <p>
    * You can use this TagHandler like this
    * </p>
    * <pre>
    * &lt;addElementToXMLFile
    *         id=&quot;myid&quot;
    *         file=&quot;c:/tmp/my.xml&quot;
    *         xpath=&quot;/AA/BB&quot;
    *         value=&quot;starts now&quot;/&gt;
    * </pre>
    * <p>
    * <h3>Example 2 - overwrites an element</h3>
    * </p>
    * <p>
    * Provided you have a file containing:
    * </p>
    * <pre>
    * &lt;AA&gt;&lt;BB&gt;Oktoberfest in Munich&lt;/BB&gt;&lt;/AA&gt;
    * </pre>
    * <p>
    * and want to overwrite the element like this
    * </p>
    * <pre>
    * &lt;AA&gt;&lt;BB&gt;Beer Festival in Munich&lt;/BB&gt;&lt;/AA&gt;
    * </pre>
    * <p>
    * You can use this TagHandler like this
    * </p>
    * <pre>
    * &lt;addElementToXMLFile
    *         id=&quot;myid&quot;
    *         file=&quot;c:/tmp/my.xml&quot;
    *         xpath=&quot;/AA/BB&quot;
    *         overwrite=&quot;yes&quot;
    *         value=&quot;starts now&quot;/&gt;
    * </pre>
    * <h3>The attributes</h3>
    * <pre>
    * id           - Referenz for later usage [required]
    * file         - The file [required]
    * xpath        - xPath of the XML element [required]
    * ignoreErrors - The reading of the file might throw errors.
    *                The TagHandler can ignore this.
    *                If ignored the referenz (id) is null and thats it.
    *                If not ignored (default) an error is thrown.
    *                (The test will fail.)
    *                Q: Where can it be usefull?
    *                   A: Parallel working robots. Robots might grab the
    *                   same file and not only read them (move, change,..)
    *                Q: How can I check if an errors did happen?
    *                A: Later reference of attribute "id" will be null.
    *                Default is "no" [optional]
    * value        - Value inside the XML element
    *                [required] if "regexp" is not provided
    * overwrite    - Overwrites an existing element with the same name
    *                [optional] "yes", "no", "true", "false"
    *                default is "no"/"false"
    * </pre>
    * <p>
    * TODO: Insert attributes.
    * </p>
    * <p>
    * Remember to use an absolute xPath with a leading &quot;/&quot;.
    * Examples: xpath=&quot;/AA/BB&quot;, xpath=&quot;/AA&quot;.
    * </p>
    * <p>
    * Later references to the file will be accessible by<br>
    * - &quot;id&quot; for the java.io.File. Example &quot;myid&quot;.<br>
    * - &quot;id.name&quot; for the name of the file.
    *   Example &quot;myid.name&quot; to get &quot;my.xml&quot;.<br>
    * - &quot;id.path&quot; for the absolut path.
    *   Example &quot;myid.path&quot; to get &quot;c:/tmp/my.xml&quot;.<br>
    * - &quot;id.dir&quot; for the directory.
    *   Example &quot;myid.dir&quot; to get &quot;c:/tmp&quot;.<br>
    * </p>
    * <h3>The behaviour if some elements are added to an existing XML file</h3>
    * <p>
    * The original file is:
    * </p>
    * <pre>
    * &lt;AA&gt;
    *   &lt;BB&gt;
    *     First Text
    *   &lt;/BB&gt;
    * &lt;/AA&gt;
    * </pre>
    * <p>
    * An element with XPath "/AA/BB" and value "second text" is added and
    * results in:
    * </p>
    * <pre>
    * &lt;AA&gt;
    *   &lt;BB&gt;
    *     First Text
    *   &lt;/BB&gt;
    *   &lt;BB&gt;
    *     second text
    *   &lt;/BB&gt;
    * &lt;/AA&gt;
    * </pre>
    * <p>
    * Another element with XPath "/AA/BB/CC" and value "third text" is added and
    * results in:
    * </p>
    * <pre>
    * &lt;AA&gt;
    *   &lt;BB&gt;
    *     First Text
    *     &lt;CC&gt;
    *       third Text
    *     &lt;/CC&gt;
    *   &lt;/BB&gt;
    *   &lt;BB&gt;
    *     second text
    *   &lt;/BB&gt;
    * &lt;/AA&gt;
    * </pre>
    * <p>
    * Another element with XPath "/AA/BB/CC" with value "fourth text" is added and
    * results in:
    * </p>
    * <pre>
    * &lt;AA&gt;
    *   &lt;BB&gt;
    *     First Text
    *     &lt;CC&gt;
    *       third Text
    *     &lt;/CC&gt;
    *     &lt;CC&gt;
    *       fourth Text
    *     &lt;/CC&gt;
    *   &lt;/BB&gt;
    *   &lt;BB&gt;
    *     second text
    *   &lt;/BB&gt;
    * &lt;/AA&gt;
    * </pre>
    * @author tom@smart-tail.com (Tom Wiedenhoeft, DV-Ratio acting under contract with Siemens L&A PA)
    */
    public class AddElementToXMLFileTagHandler extends AbstractTagHandler {
        /**
         * constructor.
         * @param element Element to be processed.
         * @param testCase containing test case.
         */
        public AddElementToXMLFileTagHandler(final Element element,
            final IXMLTestCase testCase) {
            super(element, testCase);
        }

        /**
         * Get the value of the id attribute.
         * @return String value of the id attribute.
         */
        public String getId() {
            return getString(ID);
        }

        /**
         * Get the file attribute from the element.
         * @return String The value of the file attribute.
         */
        public String getFile() {
            return getString(FILE);
        }

        /**
         * Get the xpath of the xmlElement attribute.
         * @return String value of the xpath attribute.
         */
        public String getXPath() {
            return getString(XPATH);
        }

        /**
         * Get the value of the value attribute.
         * @return String value of the value attribute.
         */
        public String getValue() {
            return getString(VALUE);
        }

        /**
         * Get the value of the ignoreErrors attribute.
         * @return String value of the ignoreErrors attribute.
         */
        public String getIgnoreErrors() {
            return getString(IGNORE_ERRORS);
        }

        /**
         * Get the value of the ignoreErrors attribute.
         * @return String value of the ignoreErrors attribute.
         */
        public String getOverwrite() {
            return getString(OVERWRITE);
        }

        /**
         * Process the element.
         * Stores an object of type java.io.File for later usage in the cache.
         * This object is later accessable via the property "id".
         * @throws XMLException may be thrown.
         */
        public void processElement() throws XMLException {
            validateElement();
            // Get the attribute value
            String id = this.getId();
            // Get the file
            File file = this.addElement();
            String name = null;
            String path = null;
            String dir = null;
            if(file != null)
            {
                name = file.getName();
                path = file.getAbsolutePath();
                dir = file.getParent().toString();
            }
            // Store the file
            getXMLTestCase().addProperty(id, file);
            getXMLTestCase().addProperty(id + "." + NAME, name);
            getXMLTestCase().addProperty(id + "." + ABSOLUTE_PATH, path);
            getXMLTestCase().addProperty(id + "." + DIRECTORY, dir);
        }

        /**
         * Validate that the element is properly configured.
         * @throws XMLException Exception may be thrown if there
         * are missing elements.
         */
        public void validateElement() throws XMLException {
            // check the element tag name
            checkElementTagName(ADD_ELEMENT_TO_XML_FILE);

            checkRequiredAttribute(ID);
            checkRequiredAttribute(FILE);
            checkRequiredAttribute(VALUE);

            checkRequiredAttribute(XPATH);
            String xpath = this.getXPath();
            if("".equals(xpath))
            {
                throw new XMLException("Attribute 'xpath' is empty.",
                        null,
                        getElement(),
                        getTest().getPropertyCache());
            }
            if(! xpath.startsWith("/"))
            {
                throw new XMLException(
                        "Invalid value for attribute 'xpath'. \n"
                        + "The xPath has to start with a '/' (absolute xPath).",
                        null,
                        getElement(),
                        getTest().getPropertyCache());
            }
        }

        /**
         * Overwrites the value of an existing XML element or
         * adds an xml-element into a xml-file according to the xPath
         * of the element to add or overwrite.
         * <p>
         * Behavior of this method when some elements are added
         * to an existing XML file.
         * </p>
         * <p>
         * The original file is:
         * </p>
         * <pre>
         * &lt;AA&gt;
         *   &lt;BB&gt;
         *     First Text
         *   &lt;/BB&gt;
         * &lt;/AA&gt;
         * </pre>
         * <p>
         * Added element with XPath "/AA/BB" and value "second text"
         * results in:
         * </p>
         * <pre>
         * &lt;AA&gt;
         *   &lt;BB&gt;
         *     First Text
         *   &lt;/BB&gt;
         *   &lt;BB&gt;
         *     second text
         *   &lt;/BB&gt;
         * &lt;/AA&gt;
         * </pre>
         * <p>
         * Another added Element with XPath "/AA/BB/CC" and value "third text"
         * results in:
         * </p>
         * <pre>
         * &lt;AA&gt;
         *   &lt;BB&gt;
         *     First Text
         *     &lt;CC&gt;
         *       third Text
         *     &lt;/CC&gt;
         *   &lt;/BB&gt;
         *   &lt;BB&gt;
         *     second text
         *   &lt;/BB&gt;
         * &lt;/AA&gt;
         * </pre>
         * <p>
         * Another added Element with XPath "/AA/BB/CC" with value "fourth text"
         * results in:
         * </p>
         * <pre>
         * &lt;AA&gt;
         *   &lt;BB&gt;
         *     First Text
         *     &lt;CC&gt;
         *       third Text
         *     &lt;/CC&gt;
         *     &lt;CC&gt;
         *       fourth Text
         *     &lt;/CC&gt;
         *   &lt;/BB&gt;
         *   &lt;BB&gt;
         *     second text
         *   &lt;/BB&gt;
         * &lt;/AA&gt;
         * </pre>
         *
         * @return java.io.File where a matching element was found.
         * @throws XMLException
         */
        private File addElement() throws XMLException
        {
            // Get the attribute values
            String file = this.getFile();
            String xpath = this.getXPath();
            String value = this.getValue();
            if(value == null)
            {
                value = "";
            }

            // In case more than one robot work on the same file.
            // Thats the purpose of boolean ignore
            String ignoreErrors = this.getIgnoreErrors();
            boolean ignore = false;
            if(ignoreErrors != null && ! "".equals(ignoreErrors))
            {
                if(ignoreErrors.trim().equalsIgnoreCase("yes"))
                {
                    ignore = true;;
                }
                if(ignoreErrors.trim().equalsIgnoreCase("true"))
                {
                    ignore = true;;
                }
            }

            // Overwrite or add the XML element?
            String overwriteElement = this.getOverwrite();
            boolean overwrite = false;
            if(overwriteElement != null && ! "".equals(overwriteElement))
            {
                if(overwriteElement.trim().equalsIgnoreCase("yes"))
                {
                    overwrite = true;;
                }
                if(overwriteElement.trim().equalsIgnoreCase("true"))
                {
                    overwrite = true;;
                }
            }

            // Check the directory
            File f = new File(file);
            if(! f.exists())
            {
                if(ignore)
                {
                    return null;
                }
                else
                {
                    throw new XMLException("File does not exist: " + f,
                            null,
                            getElement(),
                            getTest().getPropertyCache());
                }
            }
            if(f.isDirectory())
            {
                throw new XMLException(f + " is a directory and not a file.",
                    null,
                    getElement(),
                    getTest().getPropertyCache());
            }

            // Create a URL for the file. (Used by SAX Builder)
            String fileString = "file:" + file;
            URL url = null;
            try {
                url = new URL(fileString);
            } catch(MalformedURLException e) {
                throw new XMLException(fileString + " is a malformed URL.",
                    null,
                    getElement(),
                    getTest().getPropertyCache());
            }

            // Look into the file. Let the SAX builder create an
            // XML document.
            SAXBuilder builder = new SAXBuilder();
            Document doc = null;
            try {
                doc = builder.build(url);
            } catch(JDOMException e) {
                if(ignore)
                {
                    System.err.println("The TagHandler will IGNORE the above EXCEPTION");
                    System.err.println(
                            "An Exception was thrown inside AddElementToXMLFileTagHandler"
                            + "while reading the XML file. Exception message is: "
                            + e.getMessage());
                    return null;
                }
                else
                {
                    e.printStackTrace();
                    throw new XMLException(
                            "Error with file " + this.getFile() + ". " + e.getMessage(),
                            null,
                            getElement(),
                            getTest().getPropertyCache());
                }
            }

            // Insert the new element
            // Look into the javadoc for examples
            org.jdom.Element root = doc.getRootElement();
            String rootName = root.getName();
            org.jdom.Element currentElement = null;

            // Look into the attribute xpath.
            // Navigate through the xpath (XML element to add or overwrite
            // Example //AA/BB = <AA><BB></BB></AA>).
            // In case the XML element does not exist in the element create
            // one.
            StringTokenizer st = new StringTokenizer(xpath, "/");
            while(st.hasMoreElements())
            {
                // Go on to next element in xpath
                // Example: //AA
                // Example: //AA/BB and so on
                String elementName = st.nextToken();
                if(rootName.equals(elementName))
                {
                    currentElement = root;
                }
                else
                {
                    if(currentElement == null)
                    {
                        // It is not allowed to change the root element
                        throw new XMLException(
                            "Not allowed to overwrite the existing root in document \n"
                            + this.getFile() + " with " + xpath,
                            null,
                            getElement(),
                            getTest().getPropertyCache());
                    }
                    org.jdom.Element tmpElement =
                        currentElement.getChild(elementName);
                    // If the element does not exist create it
                    if(tmpElement == null)
                    {
                        tmpElement = new org.jdom.Element(elementName);
                        currentElement.addContent(tmpElement);
                    }
                    else if(! st.hasMoreElements())
                    {
                        // an element with same name does already exist
                        if(! overwrite)
                        {
                            // do not overwrite existing element (values)
                            // create a new element
                            org.jdom.Element newElement = new org.jdom.Element(elementName);
                            org.jdom.Element parentElement = tmpElement.getParent();
                            parentElement.addContent(newElement);
                            tmpElement = newElement;
                        }
                    }
                    else
                    {
                        // follow the tree
                    }
                    currentElement = tmpElement;
                }
            }

            // Set the value.
            currentElement.setText(value);

            // Write the document to file
            XMLOutputter outp = new XMLOutputter();
            outp.setIndent("  ");
            outp.setNewlines(true);
            BufferedOutputStream out = null;
            try {
                out = new BufferedOutputStream(new FileOutputStream(file));
                outp.output(doc, out);
            } catch(IOException e) {
                e.printStackTrace();
                throw new XMLException(
                        "Filed to write document for " + file + ". " + e.getMessage(),
                        null,
                        getElement(),
                        getTest().getPropertyCache());
            } finally {
                if(out != null)
                {
                    try {
                        out.close();
                    } catch(IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
            return f;
        }
    }

    ---schnapp -- AddElementToXMLFileTagHandler.java ---

    Please add in TagMapping.properties

    ---schnipp -- TagMapping.properties ---
    createXMLFile = junit.extensions.xml.elements.CreateXMLFileTagHandler
    addElementToXMLFile = junit.extensions.xml.elements.AddElementToXMLFileTagHandler
    ---schnapp -- TagMapping.properties ---

    Please add in XMLConstants.java

    ---schnipp -- XMLConstants.java ---
        /** xpath */
        String XPATH = "xpath";
        /** path. */
        String ABSOLUTE_PATH = "path";
        /** directory. */
        String DIRECTORY = "dir";
        /** ignoreErrors */
        String IGNORE_ERRORS = "ignoreErrors";
        /** overwrite */
        String OVERWRITE = "overwrite";
    ---schnapp -- XMLConstants.java ---

     
    • Kevin L Wilson

      Kevin L Wilson - 2005-03-29

      Great Idea. However your implementation is incomplete. Attributes and Comments are not supported via your API. 

      It would be great if the node to  insert were specified as a child node. The parent path would be the XPath specified. Thus any nodes or collections of nodes could be added with a single write operation.

      Also, What version of JDom are you using your API does not match that of the 1.0 published version.

      Kevin

       

Log in to post a comment.