diff --git a/contrib/retep/CHANGELOG b/contrib/retep/CHANGELOG
index e69de29bb2d..59f7c335cb9 100644
--- a/contrib/retep/CHANGELOG
+++ b/contrib/retep/CHANGELOG
@@ -0,0 +1,4 @@
+Tue Jan 23 10:19:00 GMT 2001 peter@retep.org.uk
+ - Finished the XML Export classes
+ - First of the test data suite now in CVS.
+
diff --git a/contrib/retep/build.xml b/contrib/retep/build.xml
index cf377d3bad3..019903bc798 100644
--- a/contrib/retep/build.xml
+++ b/contrib/retep/build.xml
@@ -2,7 +2,7 @@
build file to build the donated retep tools packages
- $Id: build.xml,v 1.1 2001/01/18 14:50:14 peter Exp $
+ $Id: build.xml,v 1.2 2001/01/23 10:22:18 peter Exp $
-->
@@ -44,7 +44,7 @@
-
+
diff --git a/contrib/retep/data/cds.dtd b/contrib/retep/data/cds.dtd
new file mode 100644
index 00000000000..df542c34768
--- /dev/null
+++ b/contrib/retep/data/cds.dtd
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
diff --git a/contrib/retep/data/cds.xml b/contrib/retep/data/cds.xml
new file mode 100644
index 00000000000..fb0203bda90
--- /dev/null
+++ b/contrib/retep/data/cds.xml
@@ -0,0 +1,2691 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/retep/retep.jpx b/contrib/retep/retep.jpx
index 47f54296240..640df105046 100644
--- a/contrib/retep/retep.jpx
+++ b/contrib/retep/retep.jpx
@@ -15,7 +15,7 @@
-
+
@@ -25,7 +25,7 @@
-
+
@@ -34,6 +34,8 @@
+
+
diff --git a/contrib/retep/uk/org/retep/xml/core/XMLFactory.java b/contrib/retep/uk/org/retep/xml/core/XMLFactory.java
new file mode 100644
index 00000000000..09565b00110
--- /dev/null
+++ b/contrib/retep/uk/org/retep/xml/core/XMLFactory.java
@@ -0,0 +1,334 @@
+package uk.org.retep.xml.core;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * An XMLFactory is used to render XML Tags, accounting for nesting etc
+ */
+public class XMLFactory
+{
+ /**
+ * The lest level (ie, how many tags down the tree we are)
+ */
+ protected int level;
+
+ /**
+ * The size of our tag name cache
+ */
+ protected int maxlevel;
+
+ /**
+ * Our tag name cache
+ */
+ protected String[] names;
+
+ /**
+ * Used to keep track of how formatting is done
+ */
+ protected boolean hascontent;
+ protected boolean[] contbuf;
+
+ /**
+ * Scratch used by nest()
+ */
+ private char[] nestbuf;
+
+ /**
+ * The destination Writer
+ */
+ protected Writer out;
+
+ /**
+ * True if we are still within a tag
+ */
+ protected boolean inTag;
+
+ /**
+ * True if we have just created a tag so parameters are valid
+ */
+ protected boolean inArg;
+
+ /**
+ * Constructs an XMLFactory with no output Writer
+ */
+ public XMLFactory()
+ {
+ this(10);
+ }
+
+ /**
+ * Constructs an XMLFactory with no output Writer
+ * @param m Expected number of leaves in the XML Tree
+ */
+ public XMLFactory(int m)
+ {
+ // Initialise the names cache
+ level=0;
+ maxlevel=m;
+ names=new String[maxlevel];
+ contbuf=new boolean[maxlevel];
+
+ // This is used by nest()
+ nestbuf=new char[maxlevel];
+ for(int i=0;i\n");
+ }
+
+ /**
+ * @return Writer the XML is being sent out on.
+ */
+ public Writer getWriter() {
+ return out;
+ }
+
+ /**
+ * This starts a tag
+ * @param name The tag name
+ */
+ public void startTag(String name)
+ throws IOException
+ {
+ if(inTag && inArg) {
+ // Handles two startTag() calls in succession.
+ out.write(">");
+ }
+
+ nest(level);
+ out.write('<');
+ out.write(name);
+ inTag=true;
+ inArg=true;
+
+ // cache the current tag name
+ names[level]=name;
+
+ // cache the current hascontent value & reset
+ contbuf[level]=hascontent;
+ hascontent=false;
+
+ // increase the level and the cache's as necessary
+ level++;
+ if(level>maxlevel) {
+ maxlevel=maxlevel+10;
+
+ String n[]=new String[maxlevel];
+ System.arraycopy(names,0,n,0,level);
+ names=n;
+
+ boolean b[] = new boolean[maxlevel];
+ System.arraycopy(contbuf,0,b,0,level);
+ contbuf=b;
+ }
+ }
+
+ /**
+ * This ends a tag
+ */
+ public void endTag()
+ throws IOException, XMLFactoryException
+ {
+ if(level<1)
+ throw new XMLFactoryException("endTag called above root node");
+
+ level--;
+
+ if(inArg) {
+ // We are still within the opening tag
+ out.write(" />");
+ } else {
+ // We must have written some content or child tags
+
+ // hascontent is true if addContent() was called. If it was never called
+ // to get here some child tags must have been written, so we call nest()
+ // so that the close tag is on it's own line, and everything looks neat
+ // and tidy.
+ if(!hascontent)
+ nest(level);
+
+ out.write("");
+ out.write(names[level]);
+ out.write('>');
+ }
+
+ inArg=false; // The parent tag must be told it now has content
+ inTag= level>0; // Are we still in a tag?
+ hascontent=contbuf[level]; // retrieve this level's hascontent value
+ }
+
+ /**
+ * This completes the document releasing any open resources.
+ */
+ public void close()
+ throws IOException, XMLFactoryException
+ {
+ while(level>0)
+ endTag();
+ out.write('\n');
+ out.flush();
+ }
+
+ /**
+ * This writes an attribute to the current tag. If the value is null, then no action is taken.
+ * @param name Name of the parameter
+ * @param value Value of the parameter
+ * @throw XMLFactoryException if out of context
+ */
+ public void addAttribute(String name,Object value)
+ throws IOException, XMLFactoryException
+ {
+ if(value==null)
+ return;
+
+ if(inArg) {
+ out.write(' ');
+ out.write(name);
+ out.write("=\"");
+ out.write(encode(value.toString()));
+ out.write("\"");
+ } else
+ throw new XMLFactoryException("Cannot add attribute outside of a tag");
+ }
+
+ /**
+ * This writes some content to the current tag. Once this has been called,
+ * you cannot add any more attributes to the current tag. Note, if c is null,
+ * no action is taken.
+ * @param c content to add.
+ */
+ public void addContent(Object c)
+ throws IOException, XMLFactoryException
+ {
+ if(c==null)
+ return;
+
+ if(inTag) {
+ if(inArg) {
+ // close the open tag
+ out.write('>');
+ inArg=false;
+ }
+ out.write(c.toString());
+
+ // This is used by endTag()
+ hascontent=true;
+ } else
+ throw new XMLFactoryException("Cannot add content outside of a tag");
+ }
+
+ /**
+ * This adds a comment to the XML file. This is normally used at the start of
+ * any XML output.
+ * @parm c Comment to include
+ */
+ public void addComment(Object c)
+ throws IOException, XMLFactoryException
+ {
+ if(inTag)
+ throw new XMLFactoryException("Cannot add comments within a tag");
+
+ out.write("\n");
+ }
+
+ /**
+ * Indents the output according to the level
+ * @param level The indent level to generate
+ */
+ protected void nest(int level)
+ throws IOException
+ {
+ out.write('\n');
+ while(level>nestbuf.length) {
+ out.write(nestbuf,0,nestbuf.length);
+ level-=nestbuf.length;
+ }
+ out.write(nestbuf,0,level);
+ }
+
+ /**
+ * Encodes the string so that any XML tag chars are translated
+ */
+ protected String encode(String s) {
+ return s;
+ }
+
+}
\ No newline at end of file
diff --git a/contrib/retep/uk/org/retep/xml/core/XMLFactoryException.java b/contrib/retep/uk/org/retep/xml/core/XMLFactoryException.java
new file mode 100644
index 00000000000..5f9d4972097
--- /dev/null
+++ b/contrib/retep/uk/org/retep/xml/core/XMLFactoryException.java
@@ -0,0 +1,19 @@
+package uk.org.retep.xml.core;
+
+/**
+ * Title:
+ * Description:
+ * Copyright: Copyright (c) 2001
+ * Company:
+ * @author
+ * @version 1.0
+ */
+
+public class XMLFactoryException extends Exception
+{
+
+ public XMLFactoryException(String s)
+ {
+ super(s);
+ }
+}
\ No newline at end of file
diff --git a/contrib/retep/uk/org/retep/xml/jdbc/XMLDatabase.java b/contrib/retep/uk/org/retep/xml/jdbc/XMLDatabase.java
new file mode 100644
index 00000000000..50aaaa1d905
--- /dev/null
+++ b/contrib/retep/uk/org/retep/xml/jdbc/XMLDatabase.java
@@ -0,0 +1,237 @@
+package uk.org.retep.xml.jdbc;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import uk.org.retep.xml.core.XMLFactory;
+import uk.org.retep.xml.core.XMLFactoryException;
+
+public class XMLDatabase
+{
+ /**
+ * The XMLFactory being used by this instance
+ */
+ protected XMLFactory factory;
+
+ /**
+ * Constructor. setXMLFactory() must be called if this method is used.
+ */
+ public XMLDatabase()
+ {
+ }
+
+ /**
+ * Constructor
+ * @param fac XMLFactory to use
+ */
+ public XMLDatabase(XMLFactory fac)
+ {
+ this();
+ setXMLFactory(fac);
+ }
+
+ /**
+ * Sets the factory to use.
+ * @param factory XMLFactory to use
+ */
+ public void setXMLFactory(XMLFactory factory)
+ {
+ this.factory=factory;
+ }
+
+ /**
+ * @return the XMLFactory being used.
+ */
+ public XMLFactory getXMLFactory()
+ {
+ return factory;
+ }
+
+ /**
+ * Flushes all output to the Writer.
+ * @throw IOException from Writer
+ * @throw XMLFactoryException from XMLFactory
+ */
+ public void close()
+ throws IOException, XMLFactoryException
+ {
+ factory.close();
+ }
+
+ /**
+ * writes the schema of a table.
+ * @param con Connection to database
+ * @param table Table name
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ */
+ public void writeTable(Connection con,String table)
+ throws IOException,SQLException,XMLFactoryException
+ {
+ writeTable(con.getMetaData(),table);
+ }
+
+ /**
+ * writes the schema of a table.
+ * @param db DatabaseMetaData for the database
+ * @param table Table name
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ */
+ public void writeTable(DatabaseMetaData db,String table)
+ throws IOException,SQLException,XMLFactoryException
+ {
+ writeTable(db,null,null,table);
+ }
+
+ /**
+ * writes the schema of a table.
+ * @param db DatabaseMetaData for the database
+ * @param table Table name
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ */
+ public void writeTable(DatabaseMetaData db,String cat,String schem,String table)
+ throws IOException,SQLException,XMLFactoryException
+ {
+ ResultSet trs;
+
+ factory.startTag("TABLE");
+ factory.addAttribute("NAME",table);
+ // fetch the remarks for this table (if any)
+ trs = db.getTables(null,null,table,null);
+ if(trs!=null) {
+ if(trs.next()) {
+ String rem = trs.getString(5);
+ if(rem!=null)
+ factory.addContent(rem);
+ }
+ trs.close();
+ }
+
+ trs = db.getColumns(null,null,table,"%");
+ if(trs!=null) {
+ while(trs.next()) {
+ factory.startTag("COLUMN");
+ factory.addAttribute("NAME",trs.getString(4));
+ factory.addAttribute("TYPE",trs.getString(6));
+ factory.addAttribute("COLUMN_SIZE",trs.getString(7));
+ factory.addAttribute("DECIMAL_DIGITS",trs.getString(9));
+ factory.addAttribute("NUM_PREC_RADIX",trs.getString(10));
+ factory.addAttribute("NULLABLE",trs.getString(11));
+ factory.addAttribute("COLUMN_DEF",trs.getString(13));
+ factory.addAttribute("CHAR_OCTET_LENGTH",trs.getString(16));
+ factory.addAttribute("ORDINAL_POSITION",trs.getString(17));
+ factory.addAttribute("IS_NULLABLE",trs.getString(18));
+ factory.addAttribute("TABLE_CAT",trs.getString(1));
+ factory.addAttribute("TABLE_SCHEM",trs.getString(2));
+ String rem = trs.getString(12);
+ if(rem!=null)
+ factory.addContent(rem);
+ factory.endTag();
+ }
+ trs.close();
+ }
+
+ factory.endTag();
+ }
+
+ /**
+ * This generates the schema of an entire database.
+ * @param db Connection to database
+ * @param table Table pattern
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ * @see java.sql.DatabaseMetaData.getTables()
+ */
+ public void writeDatabase(Connection db,String table)
+ throws IOException, SQLException, XMLFactoryException
+ {
+ writeDatabase(db.getMetaData(),null,null,table);
+ }
+
+ /**
+ * This generates the schema of an entire database.
+ * @param db DatabaseMetaData of database
+ * @param table Table pattern
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ * @see java.sql.DatabaseMetaData.getTables()
+ */
+ public void writeDatabase(DatabaseMetaData db,String table)
+ throws IOException, SQLException, XMLFactoryException
+ {
+ writeDatabase(db,null,null,table);
+ }
+
+ /**
+ * This generates the schema of an entire database.
+ * @param db DatabaseMetaData of database
+ * @param cat Catalog (may be null)
+ * @param schem Schema (may be null)
+ * @param table Table pattern
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ * @see java.sql.DatabaseMetaData.getTables()
+ */
+ public void writeDatabase(Connection db)
+ throws IOException, SQLException, XMLFactoryException
+ {
+ writeDatabase(db.getMetaData(),null,null,"%");
+ }
+
+ /**
+ * This generates the schema of an entire database.
+ * @param db DatabaseMetaData of database
+ * @param cat Catalog (may be null)
+ * @param schem Schema (may be null)
+ * @param table Table pattern
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ * @see java.sql.DatabaseMetaData.getTables()
+ */
+ public void writeDatabase(DatabaseMetaData db)
+ throws IOException, SQLException, XMLFactoryException
+ {
+ writeDatabase(db,null,null,"%");
+ }
+
+ /**
+ * This generates the schema of an entire database.
+ * @param db DatabaseMetaData of database
+ * @param cat Catalog (may be null)
+ * @param schem Schema (may be null)
+ * @param table Table pattern
+ * @throw IOException from Writer
+ * @throw SQLException from JDBC
+ * @throw XMLFactoryException from XMLFactory
+ * @see java.sql.DatabaseMetaData.getTables()
+ */
+ public void writeDatabase(DatabaseMetaData db,String cat,String schem,String table)
+ throws IOException, SQLException, XMLFactoryException
+ {
+ ResultSet rs = db.getTables(cat,schem,table,null);
+ if(rs!=null) {
+ factory.startTag("DATABASE");
+ factory.addAttribute("PRODUCT",db.getDatabaseProductName());
+ factory.addAttribute("VERSION",db.getDatabaseProductVersion());
+
+ while(rs.next()) {
+ writeTable(db,rs.getString(1),rs.getString(2),rs.getString(3));
+ }
+
+ factory.endTag();
+ rs.close();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/contrib/retep/uk/org/retep/xml/jdbc/XMLResultSet.java b/contrib/retep/uk/org/retep/xml/jdbc/XMLResultSet.java
new file mode 100644
index 00000000000..ee020df940d
--- /dev/null
+++ b/contrib/retep/uk/org/retep/xml/jdbc/XMLResultSet.java
@@ -0,0 +1,505 @@
+package uk.org.retep.xml.jdbc;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Properties;
+import uk.org.retep.xml.core.XMLFactory;
+import uk.org.retep.xml.core.XMLFactoryException;
+
+/**
+ * This class takes a java.sql.ResultSet object and generates an XML stream
+ * based on it's contents.
+ *
+ * $Id: XMLResultSet.java,v 1.1 2001/01/23 10:22:20 peter Exp $
+ */
+public class XMLResultSet
+{
+ /**
+ * The current ResultSet to process
+ */
+ protected ResultSet rs;
+
+ /**
+ * The XMLFactory being used by this instance
+ */
+ protected XMLFactory factory;
+
+ /**
+ * The default properties used when none are supplied by the user
+ */
+ protected static Properties defaults;
+
+ /**
+ * The default property name for defining the tag name used to define a
+ * ResultSet
+ */
+ public static String RESULTSET_NAME = "resultset.name";
+
+ /**
+ * The default tag name for a resultset
+ */
+ public static String DEFAULT_RESULTSET_NAME = "RESULTSET";
+
+ /**
+ * The default property name for defining the tag name used to define a row
+ */
+ public static String ROW_NAME = "row.name";
+
+ /**
+ * The default tag name for a row
+ */
+ public static String DEFAULT_ROW_NAME = "RECORD";
+
+ /**
+ * The default tag name for a resultset
+ */
+ public static String COLNAME = ".name";
+
+ /**
+ * The value of the property (named as its related column) used to define
+ * how the column is generated. This indicates that the columns data is
+ * enclosed within a pair of tags, ie: <id>1234</id>
+ */
+ public static String CONTENT = "content";
+
+ /**
+ * The value of the property (named as its related column) used to define
+ * how the column is generated. This indicates that the columns data is
+ * an attribute in the columns tag. ie:
+ */
+ public static String ATTRIBUTE = "attribute";
+
+ /**
+ * This is the default attribute name used when the ATTRIBUTE option is set.
+ */
+ public static String DEFAULT_ATTRIBUTE = "VALUE";
+
+ /**
+ * The value of the property (named as its related column) used to define
+ * how the column is generated. This indicates that the columns data is
+ * an attribute in the parent's tag. ie:
+ */
+ public static String ROW_ATTRIBUTE = "row";
+
+ /**
+ * This property name marks the begining row number within the ResultSet to
+ * start processing.
+ */
+ public static String FIRST_ROW = "row.first";
+
+ /**
+ * This property name marks the last row number within the ResultSet to
+ * end processing.
+ */
+ public static String LAST_ROW = "row.last";
+
+ /**
+ * Constructor
+ */
+ public XMLResultSet()
+ {
+ factory = new XMLFactory();
+ }
+
+ /**
+ * Constructor
+ */
+ public XMLResultSet(ResultSet rs)
+ {
+ this();
+ setResultSet(rs);
+ }
+
+ /**
+ * Sets the ResultSet to use
+ * @param rs ResultSet
+ */
+ public void setResultSet(ResultSet rs)
+ {
+ this.rs=rs;
+ }
+
+ /**
+ * @return the current ResultSet
+ *
+ */
+ public ResultSet getResultSet()
+ {
+ return rs;
+ }
+
+ /**
+ * Sets the Writer to send all output to
+ * @param out Writer
+ * @throws IOException from XMLFactory
+ * @see XMLFactory.setWriter
+ */
+ public void setWriter(Writer out)
+ throws IOException
+ {
+ factory.setWriter(out);
+ }
+
+ /**
+ * @return Writer output is going to
+ */
+ public Writer getWriter()
+ {
+ return factory.getWriter();
+ }
+
+ /**
+ * @return XMLFactory being used
+ */
+ public XMLFactory getXMLFactory()
+ {
+ return factory;
+ }
+
+ /**
+ * Flushes all output to the Writer
+ * @throw IOException from Writer
+ * @throw XMLFactoryException from XMLFactory
+ */
+ public void close()
+ throws IOException, XMLFactoryException
+ {
+ factory.close();
+ }
+
+ /**
+ * Returns the default properties used by translate() and buildDTD()
+ * @return Properties default property settings
+ */
+ public static Properties getDefaultProperties()
+ {
+ if(defaults==null) {
+ defaults=new Properties();
+ defaults.setProperty(RESULTSET_NAME,DEFAULT_RESULTSET_NAME);
+ defaults.setProperty(ROW_NAME,DEFAULT_ROW_NAME);
+ }
+ return defaults;
+ }
+
+ /**
+ * This generates an XML version of a ResultSet sending it to the supplied
+ * Writer.
+ * @param rs ResultSet to convert
+ * @param p Properties for the conversion
+ * @param out Writer to send output to (replaces existing one)
+ * @throws XMLFactoryException from XMLFactory
+ * @throws IOException from Writer
+ * @throws SQLException from ResultSet
+ */
+ public void translate(ResultSet rs,Properties p,Writer out)
+ throws XMLFactoryException, IOException, SQLException
+ {
+ factory.setWriter(out);
+ translate(rs,p);
+ }
+
+ /**
+ * This generates an XML version of a ResultSet sending it to the supplied
+ * Writer using a default tag struct
+ * @param rs ResultSet to convert
+ * @param out Writer to send output to (replaces existing one)
+ * @throws XMLFactoryException from XMLFactory
+ * @throws IOException from Writer
+ * @throws SQLException from ResultSet
+ */
+ public void translate(ResultSet rs,Writer out)
+ throws XMLFactoryException, IOException, SQLException
+ {
+ factory.setWriter(out);
+ translate(rs,(Properties)null);
+ }
+
+ /**
+ * This generates an XML version of a ResultSet sending it to the current
+ * output stream using a default tag structure.
+ * @param rs ResultSet to convert
+ * @throws XMLFactoryException from XMLFactory
+ * @throws IOException from Writer
+ * @throws SQLException from ResultSet
+ */
+ public void translate(ResultSet rs)
+ throws XMLFactoryException, IOException, SQLException
+ {
+ translate(rs,(Properties)null);
+ }
+
+ /**
+ * This generates an XML version of a ResultSet sending it to the current
+ * output stream.
+ * @param rs ResultSet to convert
+ * @param p Properties for the conversion
+ * @throws XMLFactoryException from XMLFactory
+ * @throws IOException from Writer
+ * @throws SQLException from ResultSet
+ */
+ public void translate(ResultSet rs,Properties p)
+ throws XMLFactoryException, IOException, SQLException
+ {
+ // if we don't pass any properties, create an empty one and cache it if
+ // further calls do the same
+ if(p==null) {
+ p=getDefaultProperties();
+ }
+
+ // Fetch some common values
+ String setName = p.getProperty(RESULTSET_NAME,DEFAULT_RESULTSET_NAME);
+ String rowName = p.getProperty(ROW_NAME,DEFAULT_ROW_NAME);
+
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int numcols = rsmd.getColumnCount();
+
+ String colname[] = new String[numcols]; // field name cache
+ int coltype[] = new int[numcols]; // true to use attribute false content
+ String colattr[] = new String[numcols]; // Attribute name
+
+ // These deal with when an attribute is to go into the row's tag parameters
+ int parentFields[] = getRowAttributes(numcols,colname,colattr,coltype,rsmd,p); // used to cache the id's
+ int numParents= parentFields==null ? 0 : parentFields.length; // number of parent fields
+ boolean haveParent= numParents>0; // true only if we need to us these
+
+ // This allows some limiting of the output result
+ int firstRow = Integer.parseInt(p.getProperty(FIRST_ROW,"0"));
+ int lastRow = Integer.parseInt(p.getProperty(LAST_ROW,"0"));
+ int curRow=0;
+
+ // Start the result set's tag
+ factory.startTag(setName);
+
+ while(rs.next()) {
+ if(firstRow<=curRow && (lastRow==0 || curRowToDo:
+ * - Add ability to have NULLABLE columns appear as optional (ie instead of
+ * x, have x? (DTD for Optional). Can't use + or * as that indicates more than
+ * 1 instance).
+ *
+ *
+ * @param rs ResultSet
+ * @param p Properties defining tag types (as translate)
+ * @param out Writer to send output to
+ */
+ public void buildDTD(ResultSet rs,Properties p,Writer out)
+ throws IOException, SQLException
+ {
+ // if we don't pass any properties, create an empty one and cache it if
+ // further calls do the same
+ if(p==null) {
+ p=getDefaultProperties();
+ }
+
+ // Fetch some common values
+ String setName = p.getProperty(RESULTSET_NAME,DEFAULT_RESULTSET_NAME);
+ String rowName = p.getProperty(ROW_NAME,DEFAULT_ROW_NAME);
+
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int numcols = rsmd.getColumnCount();
+
+ String colname[] = new String[numcols]; // field name cache
+ int coltype[] = new int[numcols]; // true to use attribute false content
+ String colattr[] = new String[numcols]; // Attribute name
+
+ // These deal with when an attribute is to go into the row's tag parameters
+ int parentFields[] = getRowAttributes(numcols,colname,colattr,coltype,rsmd,p); // used to cache the id's
+ int numParents= parentFields==null ? 0 : parentFields.length; // number of parent fields
+ boolean haveParent= numParents>0; // true only if we need to us these
+
+ // Now the dtd defining the ResultSet
+ out.write("\n");
+
+ // Now the dtd defining each row
+ out.write("\n");
+
+ // Now handle any ROW_ATTRIBUTE's
+ if(haveParent) {
+ out.write("\n");
+ }
+
+ // Now add any CONTENT & ATTRIBUTE fields
+ for(int i=0;i\n");
+
+ // ATTRIBUTE
+ if(coltype[i]==1) {
+ out.write("\n");
+ }
+ }
+ }
+ }
+
+ /**
+ * Private method used by the core translate and buildDTD methods.
+ * @param numcols Number of columns in ResultSet
+ * @param colname Array of column names
+ * @param colattr Array of column attribute names
+ * @param coltype Array of column types
+ * @param rsmd ResultSetMetaData for ResultSet
+ * @param p Properties being used
+ * @return array containing field numbers which should appear as attributes
+ * within the rows tag.
+ * @throws SQLException from JDBC
+ */
+ private int[] getRowAttributes(int numcols,
+ String colname[],String colattr[],
+ int coltype[],
+ ResultSetMetaData rsmd,Properties p)
+ throws SQLException
+ {
+ int pf[] = null;
+ int nf = 0;
+
+ // Now we put a columns value as an attribute if the property
+ // fieldname=attribute (ie myname=attribute)
+ // and if the fieldname.name property exists, use it as the attribute name
+ for(int i=0;i0) {
+ int r[] = new int[nf];
+ System.arraycopy(pf,0,r,0,nf);
+ return r;
+ }
+
+ // Return null if no tags are to appear as attributes to the row's tag
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/contrib/retep/uk/org/retep/xml/parser/TagHandler.java b/contrib/retep/uk/org/retep/xml/parser/TagHandler.java
index add0a612745..78deb0ec0aa 100644
--- a/contrib/retep/uk/org/retep/xml/parser/TagHandler.java
+++ b/contrib/retep/uk/org/retep/xml/parser/TagHandler.java
@@ -4,7 +4,6 @@ import java.io.CharArrayWriter;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
-import java.util.Map;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/contrib/retep/uk/org/retep/xml/test/XMLExport.java b/contrib/retep/uk/org/retep/xml/test/XMLExport.java
new file mode 100644
index 00000000000..116f2509060
--- /dev/null
+++ b/contrib/retep/uk/org/retep/xml/test/XMLExport.java
@@ -0,0 +1,191 @@
+package uk.org.retep.xml.test;
+
+import java.lang.Exception;
+import java.io.*;
+import java.sql.*;
+import java.util.Properties;
+import uk.org.retep.xml.core.XMLFactoryException;
+import uk.org.retep.xml.jdbc.XMLDatabase;
+import uk.org.retep.xml.jdbc.XMLResultSet;
+
+/**
+ * This "test" class is a fully functional tool in its own right. It utilises
+ * the xml classes to query and export to XML, or to dump database structures
+ * into XML.
+ */
+
+public class XMLExport
+{
+ /**
+ * The current Database Connection
+ */
+ protected Connection conn;
+ protected Statement stat;
+ protected String drvr,url,table;
+
+ protected XMLResultSet xrs;
+ protected XMLDatabase xdb;
+ protected Properties prop;
+ protected boolean outXML;
+ protected boolean outDTD;
+ protected boolean outTAB;
+ protected int maxRows=0;
+
+ public XMLExport(String[] args)
+ throws IOException,SQLException,XMLFactoryException,ClassNotFoundException
+ {
+ xrs = new XMLResultSet();
+ xrs.setWriter(new OutputStreamWriter(System.out));
+ //Properties p = new Properties(xrs.getDefaultProperties());
+ prop = (Properties) xrs.getDefaultProperties().clone();
+
+ xdb = new XMLDatabase(xrs.getXMLFactory());
+
+ for(int i=0;i2) {
+ String table=arg.substring(2);
+ System.out.println("Generating XML Schema of table "+table);
+ xdb.writeTable(conn,table);
+ xdb.close();
+ } else {
+ System.out.println("Generating XML Schema of database");
+ xdb.writeDatabase(conn);
+ xdb.close();
+ }
+ } else if(arg.equals("-V")) {
+ // Select table output
+ outXML=outDTD=false;
+ } else if(arg.equals("-X")) {
+ // Select XML output
+ outXML=true;
+ outDTD=outTAB=false;
+ } else if(arg.equals("-Y")) {
+ // Select DTD output
+ outXML=outTAB=false;
+ outDTD=true;
+ } else if(arg.startsWith("-")) {
+ System.err.println("Unknown argument: "+arg);
+ System.exit(1);
+ } else {
+ // Ok, anything not starting with "-" are queries
+ if(stat==null)
+ stat=conn.createStatement();
+
+ System.out.println("Executing "+arg);
+ ResultSet rs = stat.executeQuery(arg);
+ if(rs!=null) {
+ if(outXML) {
+ xrs.translate(rs,prop);
+ xrs.close();
+ } else if(outDTD) {
+ // Output the DTD
+ xrs.buildDTD(rs,prop);
+ xrs.close();
+ } else {
+ // Normal resultset output
+ int rc=0;
+
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int nc = rsmd.getColumnCount();
+ boolean us=false;
+ for(int c=0;c