Xalan3 specific additions and updates


git-svn-id: https://svn.apache.org/repos/asf/xalan/java/branches/xalan3@336637 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/org/apache/xml/dtm/DTM.java b/src/org/apache/xml/dtm/DTM.java
index 14446d1..27fd1ed 100644
--- a/src/org/apache/xml/dtm/DTM.java
+++ b/src/org/apache/xml/dtm/DTM.java
@@ -57,6 +57,7 @@
 package org.apache.xml.dtm;
 
 import org.apache.xml.utils.XMLString;
+import org.apache.xpath.objects.*;
 
 import javax.xml.transform.SourceLocator;
 
@@ -192,9 +193,11 @@
   public static final short NAMESPACE_NODE = 13;
   
   /**
-   * The number of valid nodetypes.
+   * The number of valid nodetypes. REMEMBER TO UPDATE THIS if you add more
+   * node types.
    */
   public static final short  NTYPES = 14;
+  
 
   // ========= DTM Implementation Control Functions. ==============
   // %TBD% RETIRED -- do via setFeature if needed. Remove from impls.
@@ -217,6 +220,7 @@
    * @param value an <code>Object</code> value
    */
   public void setProperty(String property, Object value);
+  
 
   // ========= Document Navigation Functions =========
 
@@ -999,6 +1003,75 @@
    * to shutdown any subsystem activity that may of been assoiated with
    * the active DTM Implementation.
    */
+  public void documentRelease();
+   
+   
+   /**
+    * EXPERIMENTAL XPath2 Support:
+    * 
+    * Query schema type name of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the expanded-QName (namespace URI
+    *	rather than prefix) of the type actually
+    *    resolved in the instance document. Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeName(int nodeHandle);
+  	
+  /** 
+    * EXPERIMENTAL XPath2 Support:
+    * 
+	* Query schema type namespace of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the namespace URI
+    *	of the type actually resolved in the instance document. This may
+    * 	be null if the default/unspecified namespace was used.
+    *    Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeNamespace(int nodeHandle);
 
-   public void documentRelease();
+  /** EXPERIMENTAL XPath2 Support: Query schema type localname of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the localname of the type
+   *    resolved in the instance document. Note that this may be derived from,
+   *	rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeLocalName(int nodeHandle);
+
+  /** EXPERIMENTAL XPath2 Support: Query whether node's type is derived from a specific type
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @param namespace String containing URI of namespace for the type we're intersted in
+   * @param localname String containing local name for the type we're intersted in
+   * @return true if node has a Schema Type which equals or is derived from 
+   *	the specified type. False if the node has no type or that type is not
+   * 	derived from the specified type.
+   */
+  public boolean isNodeSchemaType(int nodeHandle, String namespace, String localname);
+  
+  /** EXPERIMENTAL XPath2 Support: Retrieve the typed value(s), based on the schema
+   *  type.
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return XSequence object containing one or more values and their type
+   * information. If no typed value is available, returns an empty sequence.
+   * */
+  public DTMSequence getTypedValue(int nodeHandle);
+
+  /** Query which DTMManager this DTM is currently being handled by.
+   * 
+   * @return a DTMManager, or null if this is a "stand-alone" DTM.
+   */
+  public DTMManager getManager();
+
 }
diff --git a/src/org/apache/xml/dtm/DTMFilter.java b/src/org/apache/xml/dtm/DTMFilter.java
index 5efd4b8..e85ea45 100644
--- a/src/org/apache/xml/dtm/DTMFilter.java
+++ b/src/org/apache/xml/dtm/DTMFilter.java
@@ -175,6 +175,24 @@
    * possibly, to create a DTM-specific field for these additional bits.
    */
   public static final int SHOW_BYFUNCTION = 0x00010000;
+  
+  /**
+   * Special bit for supporting "item" in ItemType..
+   * <p>
+   * %REVIEW% Might be safer to start from higher bits and work down,
+   * to leave room for the DOM to expand its set of constants... Or,
+   * possibly, to create a DTM-specific field for these additional bits.
+   */
+  public static final int SHOW_ITEM = 0x00020000;
+
+  /**
+   * Special bit for supporting "untyped" in ItemType..
+   * <p>
+   * %REVIEW% Might be safer to start from higher bits and work down,
+   * to leave room for the DOM to expand its set of constants... Or,
+   * possibly, to create a DTM-specific field for these additional bits.
+   */
+  public static final int SHOW_UNTYPED = 0x00040000;
 
   /**
    * Test whether a specified node is visible in the logical view of a
diff --git a/src/org/apache/xml/dtm/DTMIterator.java b/src/org/apache/xml/dtm/DTMIterator.java
index 68633c3..a02c1d9 100644
--- a/src/org/apache/xml/dtm/DTMIterator.java
+++ b/src/org/apache/xml/dtm/DTMIterator.java
@@ -256,16 +256,18 @@
   //========= Random Access ==========
 
   /**
-   * If setShouldCacheNodes(true) is called, then nodes will
+   * If setShouldCache(true) is called, then nodes will
    * be cached, enabling random access, and giving the ability to do 
    * sorts and the like.  They are not cached by default.
    *
-   * %REVIEW% Shouldn't the other random-access methods throw an exception
-   * if they're called on a DTMIterator with this flag set false?
+   * %REVIEW% Should random-access methods 
+   * (specifically setCurrentPosition() and item())
+   * throw an exception if they're called on a DTMIterator 
+   * with this flag set false?
    *
    * @param b true if the nodes should be cached.
    */
-  public void setShouldCacheNodes(boolean b);
+  public void setShouldCache(boolean b);
   
   /**
    * Tells if this iterator can have nodes added to it or set via 
diff --git a/src/org/apache/xml/dtm/DTMManager.java b/src/org/apache/xml/dtm/DTMManager.java
index f0033ca..4604af7 100644
--- a/src/org/apache/xml/dtm/DTMManager.java
+++ b/src/org/apache/xml/dtm/DTMManager.java
@@ -486,7 +486,7 @@
           System.err.println("DTM: found  " + serviceId);
         }
 
-        BufferedReader rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+        BufferedReader rd = new BufferedReader(new InputStreamReader(is,"UTF-8"));
 
         foundFactory = rd.readLine();
 
diff --git a/src/org/apache/xml/dtm/DTMSequence.java b/src/org/apache/xml/dtm/DTMSequence.java
new file mode 100644
index 0000000..59f21ff
--- /dev/null
+++ b/src/org/apache/xml/dtm/DTMSequence.java
@@ -0,0 +1,131 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm;
+
+import java.util.Vector;
+
+
+// Xerces XNI post-Schema datatype support
+import org.apache.xerces.xni.psvi.ElementPSVI;
+import org.apache.xerces.xni.psvi.AttributePSVI;
+import org.apache.xerces.xni.psvi.ItemPSVI;
+import org.apache.xerces.impl.xs.ElementPSVImpl;
+import org.apache.xerces.impl.xs.AttributePSVImpl;
+import org.apache.xerces.impl.xs.XSTypeDecl;
+import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
+
+/** This interface provides an API representation for the XPath 2 
+ * Data Model's "Sequences" -- which are the basic representation 
+ * for typed values. Only built-in types, types derived from 
+ * built-ins, and sets thereof are returned directly by the XPath2
+ * DM; complex schema-types must be accessed through the document tree.
+ * 
+ * The interface also provides XSequence.EMPTY, an empty sequence,
+ * as a manefest constant.
+ * */
+public interface DTMSequence 
+{
+	/** @return the number of members in this sequence. */
+	public int getLength();
+
+	/** Retrieve the value for this member of the sequence. Since values may be
+	 * a heterogenous mix, and their type may not be known until they're examined,
+	 * they're returned as Objects. This is storage-inefficient if the value(s)
+	 * is/are builtins that map to Java primitives. Tough.
+	 * 
+	 * @param index 0-based index into the sequence.
+	 * @return the specified value
+	 * @throws exception if index <0 or >=length	 
+	 * */
+	public Object getValue(int index);
+			
+	/** Retrieve the datatype namespace URI for this member of the sequence.
+	 * 
+	 * @param index 0-based index into the sequence.
+	 * @return the namespace for the specified value's type
+	 * @throws exception if index <0 or >=length	 
+	 * */
+	public String getTypeNS(int index);
+
+	/** Retrieve the datatype namespace URI for this member of the sequence.
+	 * 
+	 * %REVIEW% Do we really need type -- 
+	 * or can we just tell folks to do instanceOf on the Java value objects?	
+	 * 
+	 * @param index 0-based index into the sequence.
+	 * @return the localname of the specified value's type
+	 * @throws exception if index <0 or >=length	 
+	 * */
+	public String getTypeLocalName(int index);
+
+	/** Ask whether this member's datatype equals or is derived from a specified
+	 * schema NSURI/localname pair.
+	 * 
+	 * @param index 0-based index into the sequence.
+	 * @return true if the type is an instance of this schema datatype,
+	 * false if it isn't.
+	 * @throws exception if index <0 or >=length	 
+	 * */
+	public boolean isSchemaType(int index, String namespace, String localname);
+
+	
+	/** MANAFEST CONSTANT: An empty XSequence, which can be returned when no
+	 * typed value exists.
+	 * */	
+	public static final DTMSequence EMPTY	= new DTMSequenceEmpty();
+}
+
diff --git a/src/org/apache/xml/dtm/DTMSequenceEmpty.java b/src/org/apache/xml/dtm/DTMSequenceEmpty.java
new file mode 100644
index 0000000..63960fa
--- /dev/null
+++ b/src/org/apache/xml/dtm/DTMSequenceEmpty.java
@@ -0,0 +1,131 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm;
+
+/**
+ * The responsibility of enclosing_type is to .
+ * 
+ * Created Jul 15, 2002
+ * @author sboag
+ */
+class DTMSequenceEmpty implements DTMSequence
+{
+  /** @return the number of members in this sequence. */
+  public int getLength()
+  {
+    return 0;
+  }
+
+  /** Retrieve the value for this member of the sequence. Since values may be
+   * a heterogenous mix, and their type may not be known until they're examined,
+   * they're returned as Objects. This is storage-inefficient if the value(s)
+   * is/are builtins that map to Java primitives. Tough.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the specified value
+   * @throws exception if index <0 or >=length   
+   * */
+  public Object getValue(int index)
+  {
+    throw new java.lang.ArrayIndexOutOfBoundsException();
+  }
+
+  /** Retrieve the datatype namespace URI for this member of the sequence.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the namespace for the specified value's type
+   * @throws exception if index <0 or >=length   
+   * */
+  public String getTypeNS(int index)
+  {
+    throw new java.lang.ArrayIndexOutOfBoundsException();
+  }
+
+  /** Retrieve the datatype namespace URI for this member of the sequence.
+   * 
+   * %REVIEW% Do we really need type -- 
+   * or can we just tell folks to do instanceOf on the Java value objects?  
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the localname of the specified value's type
+   * @throws exception if index <0 or >=length   
+   * */
+  public String getTypeLocalName(int index)
+  {
+    throw new java.lang.ArrayIndexOutOfBoundsException();
+  }
+
+  /** Ask whether this member's datatype equals or is derived from a specified
+   * schema NSURI/localname pair.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return true if the type is an instance of this schema datatype,
+   * false if it isn't.
+   * @throws exception if index <0 or >=length   
+   * */
+  public boolean isSchemaType(int index, String namespace, String localname)
+  {
+    throw new java.lang.ArrayIndexOutOfBoundsException();
+  }
+
+  /** %REVIEW% Format not yet firmly settled. Primarily for debugging purposes!
+   * */
+  public String toString()
+  {
+    return "EmptySequence[]";
+  }
+}
diff --git a/src/org/apache/xml/dtm/XType.java b/src/org/apache/xml/dtm/XType.java
new file mode 100644
index 0000000..f72224f
--- /dev/null
+++ b/src/org/apache/xml/dtm/XType.java
@@ -0,0 +1,342 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm;
+
+import java.net.URL;
+import java.util.Hashtable;
+
+import org.apache.xml.utils.QName;
+
+/**
+ * The responsibility of XType is to provide static information about 
+ * types, like the ID and the name.
+ * 
+ * Created Jul 16, 2002
+ * @author sboag
+ */
+public class XType
+{  
+  // These values need to be what they are, at least for right now.  -sb
+  // (This is because of the method resolver in the extension mechanism!)
+  public static final int ANYTYPE = 0;
+  public static final int BOOLEAN = 1;
+  public static final int DOUBLE = 2;
+  public static final int STRING = 3;
+  public static final int NODE = 4;
+  public static final int RTREEFRAG = 5;
+  
+  // Callers should expect the actual values of these constants to 
+  // changed... i.e. they should not rely on the value itself.
+  public static final int BASE64BINARY = 6;
+  public static final int HEXBINARY = 7;
+  public static final int FLOAT = 8;
+  public static final int DECIMAL = 9;
+  public static final int INTEGER = 10;
+  public static final int ANYURI = 11;
+  public static final int QNAME = 12;
+  public static final int NOTATION = 13;
+  public static final int DURATION = 14;
+  public static final int DATETIME = 15;
+  public static final int TIME = 16;
+  public static final int DATE = 17;
+  public static final int GYEARMONTH = 18;
+  public static final int GYEAR = 19;
+  public static final int GMONTHDAY = 20;
+  public static final int GDAY = 21;
+  public static final int GMONTH = 22;
+  
+  public static final int YEARMONTHDURATION = 23;
+  public static final int DAYTIMEDURATION = 24;
+
+  public static final int ANYSIMPLETYPE = 25;
+  public static final int EMPTYSEQ = 26;
+  
+  // Answer for a sequence when it hasn't iterated. -sb
+  public static final int SEQ = 27; 
+
+
+  public static final int MAXTYPES = 27; 
+  
+  // This is probably primarily for diagnostic purposes.
+  private static final String[] m_names = 
+  {
+    "AnyType", // ANYTYPE = 0;
+    "boolean", // BOOLEAN = 1;
+    "double", // DOUBLE = 2;
+    "string", // STRING = 3;
+    "NODE", // NODE = 4;
+    "RTreeRfrag", // RTREEFRAG = 5;
+    "base64Binary", // BASE64BINARY = 6;
+    "hexBinary", // HEXBINARY = 7;
+    "float", // FLOAT = 8;
+    "decimal", // DECIMAL = 9;
+    "integer", // INTEGER = 10;
+    "anyURI", // ANYURI = 11;
+    "QName", // QNAME = 12;
+    "NOTATION", // NOTATION = 13;
+    "duration", // DURATION = 14;
+    "dateTime", // DATETIME = 15;
+    "time", // TIME = 16;
+    "date", // DATE = 17;
+    "gYearMonth", // GYEARMONTH = 18;
+    "gYear", // GYEAR = 19;
+    "gMonthDay", // GMONTHDAY = 20;
+    "gDay", // GDAY = 21;
+    "gMonth", // GMONTH = 22;
+    "yearMonthDuration", // YEARMONTHDURATION = 23;
+    "dayTimeDuration", // DAYTIMEDURATION = 24;
+    "AnySimpleType", // ANYSIMPLETYPE = 25;
+    "EMPTY" // EMPTYSEQ = 26;
+  };
+  
+  public static final int NOTHOMOGENOUS = 0xFFFFFFFF;
+  
+  private static Hashtable m_nameToIDs;
+  
+  static
+  {
+    m_nameToIDs = new Hashtable();
+    m_nameToIDs.put("string", new Integer(STRING));
+    m_nameToIDs.put("boolean", new Integer(BOOLEAN));
+    m_nameToIDs.put("decimal", new Integer(DECIMAL));
+    m_nameToIDs.put("integer", new Integer(INTEGER));
+    m_nameToIDs.put("float", new Integer(FLOAT));
+    m_nameToIDs.put("double", new Integer(DOUBLE));
+    m_nameToIDs.put("duration", new Integer(DURATION));
+    m_nameToIDs.put("dateTime", new Integer(DATETIME));
+    m_nameToIDs.put("time", new Integer(TIME));
+    m_nameToIDs.put("date", new Integer(DATE));
+    m_nameToIDs.put("gYearMonth", new Integer(GYEARMONTH));
+    m_nameToIDs.put("gYear", new Integer(GYEAR));
+    m_nameToIDs.put("gMonthDay", new Integer(GMONTHDAY));
+    m_nameToIDs.put("gDay", new Integer(GDAY));
+    m_nameToIDs.put("gMonth", new Integer(GMONTH));
+    m_nameToIDs.put("hexBinary", new Integer(HEXBINARY));
+    m_nameToIDs.put("base64Binary", new Integer(BASE64BINARY));
+    m_nameToIDs.put("anyURI", new Integer(ANYURI));
+    m_nameToIDs.put("QName", new Integer(QNAME));
+    m_nameToIDs.put("NOTATION", new Integer(NOTATION));
+    m_nameToIDs.put("yearMonthDuration", new Integer(YEARMONTHDURATION));
+    m_nameToIDs.put("dayTimeDuration", new Integer(DAYTIMEDURATION));
+  }
+  
+  /** Manefest constant: Namespace of schema built-in datatypes.
+   * Provided here as a coding convenience.
+   * */
+  public static final String XMLSCHEMA_DATATYPE_NAMESPACE="http://www.w3.org/2001/XMLSchema-datatypes";
+  
+  /** Manefest constant: Namespace of schema declarations.
+   * Provided here as a coding convenience.
+   * */
+  public static final String XMLSCHEMA_NAMESPACE="http://www.w3.org/2001/XMLSchema";
+
+  /**
+   * Get the type ID that maps to a local name, The namespace 
+   * URI of "http://www.w3.org/2001/XMLSchema-datatypes" is assumed.
+   * 
+   * @param localName The local name of a type.
+   * @return one of STRING, BOOLEAN, etc, or ANYTYPE if the string does 
+   * not map to any name.
+   */
+  public static int getTypeFromLocalName(String localName)
+  {
+    Integer idObj = (Integer)m_nameToIDs.get(localName);
+    return (null != idObj) ? idObj.intValue() : ANYTYPE;
+  }
+  
+  /**
+   * Get the type ID that maps to a qualified name, The namespace 
+   * of which must be URI of "http://www.w3.org/2001/XMLSchema-datatypes".
+   * 
+   * @param namespace of data type
+   * @param localName of data type
+   * @return one of STRING, BOOLEAN, etc, or ANYTYPE if the string does 
+   * not map to any name.
+   */
+  public static int getTypeID(String namespace, String localName)
+  {
+    if(null == namespace 
+      || (!namespace.equals(XMLSCHEMA_DATATYPE_NAMESPACE)
+      && !namespace.equals(XMLSCHEMA_NAMESPACE)))
+      return ANYTYPE; // Should be good enough to test for error.
+    Integer idObj = (Integer)m_nameToIDs.get(localName);
+    return (null != idObj) ? idObj.intValue() : ANYTYPE;
+  }
+  
+  /**
+   * Get the type ID that maps to a qualified name, The namespace 
+   * of which must be URI of "http://www.w3.org/2001/XMLSchema-datatypes".
+   * This should probably be moved into the DTM interface?
+   * 
+   * @param nodeHandle A handle to a node.
+   * @return one of STRING, BOOLEAN, etc, or ANYTYPE if the string does 
+   * not map to any name.
+   */
+  public static int getTypeID(DTM dtm, int nodeHandle)
+  {
+    String namespace = dtm.getSchemaTypeNamespace(nodeHandle);
+    String localName = dtm.getSchemaTypeLocalName(nodeHandle);
+    if(null == namespace 
+      || (!namespace.equals(XMLSCHEMA_DATATYPE_NAMESPACE)
+      && !namespace.equals(XMLSCHEMA_NAMESPACE)))
+      return ANYTYPE; // Should be good enough to test for error.
+    Integer idObj = (Integer)m_nameToIDs.get(localName);
+    return (null != idObj) ? idObj.intValue() : ANYTYPE;
+  }
+
+
+  
+  /**
+   * Get the type ID that maps to a qualified name, The namespace 
+   * of which must be URI of "http://www.w3.org/2001/XMLSchema-datatypes".
+   * 
+   * @param qname A qualifed name object.
+   * @return one of STRING, BOOLEAN, etc, or ANYTYPE if the string does 
+   * not map to any name.
+   */
+  public static int getTypeFromQName(QName qname)
+  {
+    String namespace = qname.getNamespaceURI();
+    if(null == namespace 
+      || (!namespace.equals(XMLSCHEMA_DATATYPE_NAMESPACE)
+      && !namespace.equals(XMLSCHEMA_NAMESPACE)))
+      return ANYTYPE; // Should be good enough to test for error.
+    Integer idObj = (Integer)m_nameToIDs.get(qname.getLocalName());
+    return (null != idObj) ? idObj.intValue() : ANYTYPE;
+  }
+
+  
+  /**
+   * Returns the nameToIDs table.
+   * @return Hashtable that contains Strings as the key, and Integers as 
+   * the value.
+   */
+  public static Hashtable getNameToIDs()
+  {
+    return m_nameToIDs;
+  }
+  
+  /**
+   * Get the type ID that maps to a local name, The namespace 
+   * URI of "http://www.w3.org/2001/XMLSchema-datatypes" is assumed.
+   * 
+   * @param id one of EMPTYSEQ, NODE, STRING, BOOLEAN, etc.
+   * @throws IndexOutOfBoundsException if id &gt;= 22, or id &lt; 0.
+   */
+  public static String getLocalNameFromType(int id)
+  {
+    return m_names[id];
+  }
+
+
+  /**
+   * Returns the names table, primarily for diagnostic purposes.
+   * @return String[]
+   */
+  public static String[] getNames()
+  {
+    return m_names;
+  }
+  
+  /**
+   * This method does it's best to infer the type name from a 
+   * java object.
+   * @param obj
+   * @return String
+   */
+  public static String inferLocalNameFromJavaObject(Object obj)
+  {
+    //  public static final int STRING = 4;
+    //  public static final int BOOLEAN = 5;
+    //  public static final int BASE64BINARY = 6;
+    //  public static final int HEXBINARY = 7;
+    //  public static final int FLOAT = 8;
+    //  public static final int DECIMAL = 9;
+    //  public static final int INTEGER = 10;
+    //  public static final int DOUBLE = 11;
+    //  public static final int ANYURI = 12;
+    //  public static final int QNAME = 13;
+    //  public static final int NOTATION = 14;
+    //  public static final int DURATION = 15;
+    //  public static final int DATETIME = 16;
+    //  public static final int TIME = 17;
+    //  public static final int DATE = 18;
+    //  public static final int GYEARMONTH = 19;
+    //  public static final int GYEAR = 20;
+    //  public static final int GMONTHDAY = 21;
+    //  public static final int GDAY = 22;
+    //  public static final int GMONTH = 23;
+    if(obj instanceof String)
+      return getLocalNameFromType(STRING);
+    else if(obj instanceof Boolean)
+      return getLocalNameFromType(BOOLEAN);
+    else if(obj instanceof Float)
+      return getLocalNameFromType(FLOAT);
+    else if(obj instanceof Double)
+      return getLocalNameFromType(DOUBLE);
+    else if(obj instanceof Integer)
+      return getLocalNameFromType(INTEGER);
+    else if(obj instanceof URL)
+      return getLocalNameFromType(ANYURI);
+    else if(obj instanceof QName)
+      return getLocalNameFromType(QNAME);
+    // TBD: all the rest.
+    else
+      return "unknown";
+  }
+
+}
diff --git a/src/org/apache/xml/dtm/XTypeConverter.java b/src/org/apache/xml/dtm/XTypeConverter.java
new file mode 100644
index 0000000..2ca2d30
--- /dev/null
+++ b/src/org/apache/xml/dtm/XTypeConverter.java
@@ -0,0 +1,252 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm;
+
+import java.util.Date;
+
+import org.apache.xerces.util.URI;
+import org.apache.xml.utils.QName;
+import org.apache.xml.utils.XMLString;
+
+/**
+ * This interface defines a type that can convert to the given type.
+ * 
+ * Created Jul 18, 2002
+ * @author sboag
+ */
+public interface XTypeConverter
+{
+  //  public static final int ANYTYPE = 2;
+  //  public static final int ANYSIMPLETYPE = 3;
+  
+  /**
+   * Return a java object that's closest to the representation
+   * that should be handed to an extension.
+   *
+   * @return The object that this class wraps
+   */
+  public Object object();
+  
+  //  public static final int STRING = 4;
+  /**
+   * Cast result object to a string.
+   *
+   * @return The object as a string
+   */
+  public String str();
+
+  /**
+   * Cast result object to an XString.
+   *
+   * @return The object as a string
+   */
+  public XMLString xstr();
+  
+  //  public static final int BOOLEAN = 5;
+  /**
+   * Cast result object to a float.
+   *
+   * @return float value.
+   */
+  public boolean bool();  
+  
+  //  public static final int BASE64BINARY = 6;
+  /**
+   * Cast result object to a float.
+   *
+   * @return float value.
+   */
+  public Object base64Binary();
+  
+  //  public static final int HEXBINARY = 7;
+  /**
+   * Cast result object to a float.
+   *
+   * @return float value.
+   */
+  public Object hexBinary();
+  
+  //  public static final int FLOAT = 8;
+  /**
+   * Cast result object to a float.
+   *
+   * @return float value.
+   */
+  public float floatCast();
+
+  
+  //  public static final int DECIMAL = 9;
+  /**
+   * Cast result object to a double (for lack of something better. -sb)
+   *
+   * @return 0.0
+   */
+  public double decimal();
+
+  //  public static final int INTEGER = 10;
+  /**
+   * Cast result object to a integer.
+   *
+   * @return integer value.
+   */
+  public int integer();
+
+  //  public static final int DOUBLE = 11;
+  /**
+   * Cast result object to a double.
+   *
+   * @return double value.
+   */
+  public double doubleCast();
+  
+  //  public static final int ANYURI = 12;
+  /**
+   * Cast result object to a double.
+   *
+   * @return URI object
+   */
+  public URI anyuri();
+  
+  //  public static final int QNAME = 13;
+  /**
+   * Cast result object to a double.
+   *
+   * @return QName object.
+   */
+  public QName qname();
+  
+  //  public static final int NOTATION = 14;
+  /**
+   * Cast result object to a String that representa a NOTATION.
+   * TBD: I think this needs to be a special object!
+   *
+   * @return String object
+   */
+  public String notation();  // not sure what to do with this!
+
+  //  public static final int DURATION = 15;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object duration();  // Use myriam's Duration
+
+  //  public static final int DATETIME = 16;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Date datetime();  // Use myriam's 
+  
+  //  public static final int TIME = 17;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object time();  // Use myriam's 
+
+  //  public static final int DATE = 18;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Date date();  // Use myriam's 
+
+  //  public static final int GYEARMONTH = 19;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object gYearMonth();  // Use myriam's 
+
+  //  public static final int GYEAR = 20;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object gYear();  // Use myriam's 
+
+  //  public static final int GMONTHDAY = 21;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object gMonthDay();  // Use myriam's 
+
+  //  public static final int GDAY = 22;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object gDay();  // Use myriam's 
+
+  //  public static final int GMONTH = 23;
+  /**
+   * Cast result object to a duration.
+   *
+   * @return Duration object
+   */
+  public Object gMonth();  // Use myriam's 
+}
diff --git a/src/org/apache/xml/dtm/ref/DTMDefaultBase.java b/src/org/apache/xml/dtm/ref/DTMDefaultBase.java
index 222eb57..1c345fb 100644
--- a/src/org/apache/xml/dtm/ref/DTMDefaultBase.java
+++ b/src/org/apache/xml/dtm/ref/DTMDefaultBase.java
@@ -56,33 +56,28 @@
  */
 package org.apache.xml.dtm.ref;
 
-import org.apache.xml.dtm.*;
-import org.apache.xml.utils.SuballocatedIntVector;
-import org.apache.xml.utils.SuballocatedByteVector;
-import org.apache.xml.utils.IntStack;
-import org.apache.xml.utils.BoolStack;
-import org.apache.xml.utils.StringBufferPool;
-import org.apache.xml.utils.FastStringBuffer;
-import org.apache.xml.utils.TreeWalker;
-import org.apache.xml.utils.QName;
-import org.apache.xml.utils.XMLCharacterRecognizer;
-
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
 import java.util.Vector;
 
-import org.xml.sax.ContentHandler;
-
-import org.apache.xml.utils.NodeVector;
-
 import javax.xml.transform.Source;
 
-import org.apache.xml.utils.XMLString;
-import org.apache.xml.utils.XMLStringFactory;
-
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xalan.res.XSLTErrorResources;
-
-import java.io.*; // for dumpDTM
-
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMAxisTraverser;
+import org.apache.xml.dtm.DTMException;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.DTMSequence;
+import org.apache.xml.dtm.DTMWSFilter;
+import org.apache.xml.utils.BoolStack;
+import org.apache.xml.utils.SuballocatedIntVector;
+import org.apache.xml.utils.XMLString;
+import org.apache.xml.utils.XMLStringFactory;
+import org.apache.xpath.objects.XSequence;
 /**
  * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
  * It sets up structures for navigation and type, while leaving data
@@ -460,7 +455,7 @@
     if (NULL != info)
       return m_expandedNameTable.getType(info);
     else
-      return NULL;
+      return (short)NULL;
   }
 
   /**
@@ -820,7 +815,7 @@
         case DTM.NOTATION_NODE :
           typestring = "NOTATION";
           break;
-        case DTM.NULL :
+        case (short)DTM.NULL:
           typestring = "null";
           break;
         case DTM.PROCESSING_INSTRUCTION_NODE :
@@ -1401,7 +1396,7 @@
    */
   public int getDocument()
   {
-    return m_dtmIdent.elementAt(0); // makeNodeHandle(0)
+    return m_dtmIdent.elementAt(0);
   }
 
   /**
@@ -1439,6 +1434,20 @@
   }
 
   /**
+   * Given a node identifier, find the owning document node.  Unlike the DOM,
+   * this considers the owningDocument of a Document to be itself. Note that
+   * in shared DTMs this may not be zero.
+   *
+   * @param nodeId the id of the node.
+   * @return int Node identifier of owning document, or the nodeId if it is
+   *             a Document.
+   */
+  protected int _documentRoot(int nodeIdentifier)
+  {
+    return 0;
+  }
+
+  /**
    * Get the string-value of a node as a String object
    * (see http://www.w3.org/TR/xpath#data-model
    * for the definition of a node's string-value).
@@ -2128,8 +2137,6 @@
 
 	 /** Query which DTMManager this DTM is currently being handled by.
 	  * 
-	  * %REVEW% Should this become part of the base DTM API?
-	  * 
 	  * @return a DTMManager, or null if this is a "stand-alone" DTM.
 	  */
 	 public DTMManager getManager()
@@ -2148,4 +2155,73 @@
 		 if(m_mgr==null) return null;
 		 return m_dtmIdent;
 	 }
+	 
+
+  /**
+    * EXPERIMENTAL XPath2 Support:
+    * 
+    * Query schema type name of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the expanded-QName (namespace URI
+    *	rather than prefix) of the type actually
+    *    resolved in the instance document. Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeName(int nodeHandle)
+   { return null; }
+  	
+  /** 
+    * EXPERIMENTAL XPath2 Support:
+    * 
+	* Query schema type namespace of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the namespace URI
+    *	of the type actually resolved in the instance document. This may
+    * 	be null if the default/unspecified namespace was used.
+    *    Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeNamespace(int nodeHandle)
+   { return null; }
+
+  /** EXPERIMENTAL XPath2 Support: Query schema type localname of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the localname of the type
+   *    resolved in the instance document. Note that this may be derived from,
+   *	rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeLocalName(int nodeHandle)
+   { return null; }
+
+  /** EXPERIMENTAL XPath2 Support: Query whether node's type is derived from a specific type
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @param namespace String containing URI of namespace for the type we're intersted in
+   * @param localname String containing local name for the type we're intersted in
+   * @return true if node has a Schema Type which equals or is derived from 
+   *	the specified type. False if the node has no type or that type is not
+   * 	derived from the specified type.
+   */
+  public boolean isNodeSchemaType(int nodeHandle, String namespace, String localname)
+   { return false; }
+  
+  /** EXPERIMENTAL XPath2 Support: Retrieve the typed value(s), based on the schema
+   *  type.
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return XSequence object containing one or more values and their type
+   * information. If no typed value is available, returns an empty sequence.
+   * */
+  public DTMSequence getTypedValue(int nodeHandle)
+   {return DTMSequence.EMPTY;}
+	 
 }
diff --git a/src/org/apache/xml/dtm/ref/DTMDefaultBaseIterators.java b/src/org/apache/xml/dtm/ref/DTMDefaultBaseIterators.java
index 304a023..b266f78 100644
--- a/src/org/apache/xml/dtm/ref/DTMDefaultBaseIterators.java
+++ b/src/org/apache/xml/dtm/ref/DTMDefaultBaseIterators.java
@@ -1491,6 +1491,8 @@
         else
           _startNode = getParent(node);
 
+        _currentNode = getDocumentRoot(node);
+        
         node = _startNode;
         while (node != END)
         {
@@ -1499,10 +1501,6 @@
         }
         m_ancestorsPos = m_ancestors.size()-1;
 
-        _currentNode = (m_ancestorsPos>=0)
-                               ? m_ancestors.elementAt(m_ancestorsPos)
-                               : DTM.NULL;
-
         return resetPosition();
       }
 
@@ -1518,11 +1516,10 @@
     public DTMAxisIterator reset()
     {
 
+      _currentNode = getDocumentRoot(_startNode);
+            
       m_ancestorsPos = m_ancestors.size()-1;
 
-      _currentNode = (m_ancestorsPos>=0) ? m_ancestors.elementAt(m_ancestorsPos)
-                                         : DTM.NULL;
-
       return resetPosition();
     }
 
@@ -1536,10 +1533,11 @@
 
       int next = _currentNode;
       
-      int pos = --m_ancestorsPos;
-
-      _currentNode = (pos >= 0) ? m_ancestors.elementAt(m_ancestorsPos)
-                                : DTM.NULL;
+      int pos = m_ancestorsPos--;
+      if(pos < 0)
+         _currentNode = DTM.NULL;
+      else
+     	 _currentNode = m_ancestors.elementAt(pos);
       
       return returnNode(next);
     }
diff --git a/src/org/apache/xml/dtm/ref/DTMDefaultBaseTraversers.java b/src/org/apache/xml/dtm/ref/DTMDefaultBaseTraversers.java
index 61b3de9..071003d 100644
--- a/src/org/apache/xml/dtm/ref/DTMDefaultBaseTraversers.java
+++ b/src/org/apache/xml/dtm/ref/DTMDefaultBaseTraversers.java
@@ -195,9 +195,8 @@
     }
 
     if (null == traverser)
-      throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object[]{Axis.names[axis]}));
-      // "Axis traverser not supported: "
-      //                       + Axis.names[axis]);
+      throw new DTMException("Axis traverser not supported: "
+                             + Axis.names[axis]);
 
     m_traversers[axis] = traverser;
 
@@ -1257,7 +1256,8 @@
 			// compute in ID space
       int subtreeRootIdent = makeNodeIdentity(context);
 
-      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
+      int doc=_documentRoot(subtreeRootIdent);
+      for (current = makeNodeIdentity(current) - 1; current >= doc; current--)
       {
         short type = _type(current);
 
@@ -1286,7 +1286,8 @@
 			// Compute in ID space
       int subtreeRootIdent = makeNodeIdentity(context);
 
-      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
+      int doc=_documentRoot(subtreeRootIdent);
+      for (current = makeNodeIdentity(current) - 1; current >= doc; current--)
       {
         int exptype = m_exptype.elementAt(current);
 
@@ -1321,7 +1322,8 @@
 			// Compute in ID space
       int subtreeRootIdent = makeNodeIdentity(context );
 
-      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
+      int doc=_documentRoot(subtreeRootIdent);
+      for (current = makeNodeIdentity(current) - 1; current >= doc; current--)
       {
         short type = _type(current);
 
@@ -1349,7 +1351,8 @@
 			// Compute in ID space
       int subtreeRootIdent = makeNodeIdentity(context);
 
-      for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
+      int doc=_documentRoot(subtreeRootIdent);
+      for (current = makeNodeIdentity(current) - 1; current >= doc; current--)
       {
         int exptype = m_exptype.elementAt(current);
 
@@ -1486,7 +1489,7 @@
      */
     public int first(int context)
     {
-      return getDocument();
+      return getDocumentRoot(context);
     }
 
     /**
@@ -1499,7 +1502,7 @@
      */
     public int first(int context, int expandedTypeID)
     {
-      return (getExpandedTypeID(getDocument()) == expandedTypeID)
+      return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID)
              ? context : next(context, context, expandedTypeID);
     }
 
@@ -1619,8 +1622,7 @@
      */
     protected int getSubtreeRoot(int handle)
     {
-			// %REVIEW% Shouldn't this always be 0?
-      return makeNodeIdentity(getDocument());
+      return _documentRoot(makeNodeIdentity(handle));
     }
 
     /**
@@ -1632,7 +1634,7 @@
      */
     public int first(int context)
     {
-      return getDocument();
+      return getDocumentRoot(context);
     }
     
     /**
@@ -1653,7 +1655,7 @@
     {
       if (isIndexed(expandedTypeID))
       {
-        int identity = 0;
+        int identity = _documentRoot(makeNodeIdentity(context));
         int firstPotential = getFirstPotential(identity);
 
         return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
@@ -1681,7 +1683,7 @@
      */
     protected int getFirstPotential(int identity)
     {
-      return _firstch(0);
+      return _firstch(_documentRoot(identity));
     }
 
     /**
@@ -1691,7 +1693,7 @@
      */
     protected int getSubtreeRoot(int handle)
     {
-      return 0;
+      return _documentRoot(makeNodeIdentity(handle));
     }
 
     /**
@@ -1703,7 +1705,7 @@
      */
     public int first(int context)
     {
-      return makeNodeHandle(_firstch(0));
+      return makeNodeHandle(_firstch(_documentRoot(makeNodeIdentity(context))));
     }
     
     /**
@@ -1724,13 +1726,13 @@
     {
       if (isIndexed(expandedTypeID))
       {
-        int identity = 0; 
+        int identity = _documentRoot(makeNodeIdentity(context)); 
         int firstPotential = getFirstPotential(identity);
 
         return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
       }
 
-      int root = getDocument(); 
+      int root = getDocumentRoot(context); 
       return next(root, root, expandedTypeID);
     }
     
diff --git a/src/org/apache/xml/dtm/ref/DTMDocumentImpl.java b/src/org/apache/xml/dtm/ref/DTMDocumentImpl.java
index 6a8ec80..30c7c88 100644
--- a/src/org/apache/xml/dtm/ref/DTMDocumentImpl.java
+++ b/src/org/apache/xml/dtm/ref/DTMDocumentImpl.java
@@ -56,23 +56,21 @@
  */
 package org.apache.xml.dtm.ref;
 
-import org.apache.xml.dtm.*;
-import java.util.Hashtable;
-//import java.util.Stack;
-import java.util.Vector;
-
 import javax.xml.transform.SourceLocator;
 
-import org.apache.xml.dtm.ref.ChunkedIntArray;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMAxisIterator;
+import org.apache.xml.dtm.DTMAxisTraverser;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.DTMSequence;
+import org.apache.xml.dtm.DTMWSFilter;
 import org.apache.xml.utils.FastStringBuffer;
-
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.Attributes;
-import org.xml.sax.ext.LexicalHandler;
-
 import org.apache.xml.utils.XMLString;
 import org.apache.xml.utils.XMLStringFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.ext.LexicalHandler;
 
 /**
  * This is the implementation of the DTM document interface.  It receives
@@ -148,6 +146,8 @@
    * @see setIncrementalSAXSource
    */
   private IncrementalSAXSource m_incrSAXSource=null;
+  
+  DTMManager m_manager;
 
 
         // ========= DTM data structure declarations. ==============
@@ -196,11 +196,15 @@
          * DTMManager's responsibility to assign a unique number to each
          * document.
          */
-        public DTMDocumentImpl(DTMManager mgr, int documentNumber,
-                               DTMWSFilter whiteSpaceFilter,
-                               XMLStringFactory xstringfactory){
-                initDocument(documentNumber);	 // clear nodes and document handle
-                m_xsf = xstringfactory;
+        public DTMDocumentImpl(
+          DTMManager mgr,
+          int documentNumber,
+          DTMWSFilter whiteSpaceFilter,
+          XMLStringFactory xstringfactory)
+        {
+          m_manager = mgr;
+          initDocument(documentNumber); // clear nodes and document handle
+          m_xsf = xstringfactory;
         }
 
   /** Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
@@ -2445,5 +2449,79 @@
    {
    }
 
+   /**
+    * EXPERIMENTAL XPath2 Support:
+    * 
+    * Query schema type name of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the expanded-QName (namespace URI
+    *	rather than prefix) of the type actually
+    *    resolved in the instance document. Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeName(int nodeHandle)
+   { return null; }
+  	
+  /** 
+    * EXPERIMENTAL XPath2 Support:
+    * 
+	* Query schema type namespace of a given node.
+    * 
+    * %REVIEW% Is this actually needed?
+    * 
+    * @param nodeHandle DTM Node Handle of Node to be queried
+    * @return null if no type known, else returns the namespace URI
+    *	of the type actually resolved in the instance document. This may
+    * 	be null if the default/unspecified namespace was used.
+    *    Note that this may be derived from,
+    *	rather than identical to, the type declared in the schema.
+    */
+   public String getSchemaTypeNamespace(int nodeHandle)
+   { return null; }
+
+  /** EXPERIMENTAL XPath2 Support: Query schema type localname of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the localname of the type
+   *    resolved in the instance document. Note that this may be derived from,
+   *	rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeLocalName(int nodeHandle)
+   { return null; }
+
+  /** EXPERIMENTAL XPath2 Support: Query whether node's type is derived from a specific type
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @param namespace String containing URI of namespace for the type we're intersted in
+   * @param localname String containing local name for the type we're intersted in
+   * @return true if node has a Schema Type which equals or is derived from 
+   *	the specified type. False if the node has no type or that type is not
+   * 	derived from the specified type.
+   */
+  public boolean isNodeSchemaType(int nodeHandle, String namespace, String localname)
+   { return false; }
+  
+  /** EXPERIMENTAL XPath2 Support: Retrieve the typed value(s), based on the schema
+   *  type.
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return XSequence object containing one or more values and their type
+   * information. If no typed value is available, returns an empty sequence.
+   * */
+  public DTMSequence getTypedValue(int nodeHandle)
+   {return DTMSequence.EMPTY;}
+
+  /**
+   * @see org.apache.xml.dtm.DTM#getManager()
+   */
+  public DTMManager getManager()
+  {
+    return m_manager;
+  }
 
 }
diff --git a/src/org/apache/xml/dtm/ref/DTMManagerDefault.java b/src/org/apache/xml/dtm/ref/DTMManagerDefault.java
index 2d76162..26eebf4 100644
--- a/src/org/apache/xml/dtm/ref/DTMManagerDefault.java
+++ b/src/org/apache/xml/dtm/ref/DTMManagerDefault.java
@@ -73,12 +73,13 @@
 import org.apache.xml.utils.SystemIDResolver;
 import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM;
 import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
-import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
+//import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
 
-/**************************************************************
+/**************************************************************/
 // EXPERIMENTAL 3/22/02
 import org.apache.xml.dtm.ref.xni2dtm.XNI2DTM;
-**************************************************************/
+import org.apache.xml.dtm.ref.xni2dtm.XNISource;
+/**************************************************************/
 
 // W3C DOM
 import org.w3c.dom.Document;
@@ -121,12 +122,10 @@
  * */
 public class DTMManagerDefault extends DTMManager
 {
-  //static final boolean JKESS_XNI_EXPERIMENT=true;
-
   /** Set this to true if you want a dump of the DTM after creation. */
   private static final boolean DUMPTREE = false;
 
-  /** Set this to true if you want a basic diagnostics. */
+  /** Set this to true if you want basic diagnostics. */
   private static final boolean DEBUG = false;
 
   /**
@@ -275,7 +274,6 @@
                                  DTMWSFilter whiteSpaceFilter,
                                  boolean incremental, boolean doIndexing)
   {
-
     if(DEBUG && null != source)
       System.out.println("Starting "+
                          (unique ? "UNIQUE" : "shared")+
@@ -286,243 +284,345 @@
     int dtmPos = getFirstFreeDTMID();
     int documentID = dtmPos << IDENT_DTM_NODE_BITS;
 
-    if ((null != source) && source instanceof DOMSource)
+    if (source instanceof DOMSource)
     {
+      // Simplest case: Wrap a DTM around an existing DOM.
+      //
+      // %REVIEW% May get more complicated if we start trying to match
+      // DOM2DTM implementations against specific DOM implementations,
+      // eg taking advantage of a particular DOM's hashability or
+      // userData hooks.
       DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID,
                                 whiteSpaceFilter, xstringFactory, doIndexing);
+      addDTM(dtm, dtmPos, 0);
+      return dtm;
+    }
+    
+    if(source==null)
+    {
+      // Set up a DTM which will accept a SAX input stream to be bound later.
+      // Note that XNI is _not_ currently an option in this case.
+      SAX2DTM dtm;
+
+      if(unique && !incremental && !doIndexing)
+      {
+        // Special case to support RTF construction into shared DTM.
+        // It should actually still work for other uses,
+        // but may be slightly deoptimized relative to the base
+        // to allow it to deal with carrying multiple documents.
+        //
+        // %REVIEW% This is a sloppy way to request this mode;
+        // we need to consider architectural improvements.
+        dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
+                             xstringFactory, doIndexing, true);
+        if(DEBUG)
+        	System.out.println("CREATING RTF DTM: "+dtm);
+      }
+      else // Create the basic SAX2DTM.
+      {
+        dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
+                          xstringFactory, doIndexing);
+      }
 
       addDTM(dtm, dtmPos, 0);
 
-      //      if (DUMPTREE)
-      //      {
-      //        dtm.dumpDTM();
-      //      }
-
+      // If the source is null, but they requested an incremental build,
+      // then we still want to set up the IncrementalSAXSource stuff
+      // so it can be bound later.
+      if (this.m_incremental && incremental)
+      {
+        IncrementalSAXSource coParser=new IncrementalSAXSource_Filter();
+        dtm.setIncrementalSAXSource(coParser);
+      }
+      
       return dtm;
     }
-    else
+
+    if (source instanceof XNISource)
     {
-      boolean isSAXSource = (null != source)
-        ? (source instanceof SAXSource) : true;
-      boolean isStreamSource = (null != source)
-        ? (source instanceof StreamSource) : false;
+    	XNISource xsrc=(XNISource)source;
+    	
+        XNI2DTM dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
+                              xstringFactory, doIndexing);
+        addDTM(dtm, dtmPos, 0);
+        
+        xsrc.setDocumentHandler(dtm);
+        xsrc.setErrorHandler(dtm);
+        
+        // XNI's document scanner does support incremental.
+        // Would require yet another flavor of incremental-source to
+        // glue it to our APIs. For now, just run it to completion.
+        // MOVE THIS DOWN !!!!!
+        // %REVIEW%
+        try
+        {
+	        xsrc.reset();
+	        xsrc.scanDocument(true);
+        }
+        catch (RuntimeException re)
+        {
+          throw re;
+        }
+        catch (Exception e)
+        {
+          throw new org.apache.xml.utils.WrappedRuntimeException(e);
+        }
+          
+        return dtm;
+    } // XNISource
 
-      if (isSAXSource || isStreamSource)
+    if (source instanceof StreamSource)
+    {
+      // Try processing it as XNI first, to get PSVI information!
+      
+      // %REVIEW% Arguably, we shouldn't go XNI (or at least not
+      // Schema-validated?) unless it's requested and/or XSLT2/XPath2
+      // are in use, since the schema processor is so expensive.
+      // Unfortunately, we don't have the XPathContext here to ask
+      // which version of the language is in use...
+
+      InputSource xmlSource = SAXSource.sourceToInputSource(source);
+      String urlOfSource = xmlSource.getSystemId();
+      if (null != urlOfSource)
       {
-        XMLReader reader;
-        InputSource xmlSource;
-
-        if (null == source)
+        try
         {
-          xmlSource = null;
-          reader = null;
+          urlOfSource=SystemIDResolver.getAbsoluteURI(urlOfSource);
         }
-        else
+        catch (Exception e)
         {
-          reader = getXMLReader(source);
-          xmlSource = SAXSource.sourceToInputSource(source);
-
-          String urlOfSource = xmlSource.getSystemId();
-
-          if (null != urlOfSource)
-          {
-            try
-            {
-              urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
-            }
-            catch (Exception e)
-            {
-
-              // %REVIEW% Is there a better way to send a warning?
-              System.err.println("Can not absolutize URL: " + urlOfSource);
-            }
-
-            xmlSource.setSystemId(urlOfSource);
-          }
+          // %REVIEW% Is there a better way to send a warning?
+          System.err.println("Can not absolutize URL: " + urlOfSource);
         }
-
-        SAX2DTM dtm;
-        if(source==null && unique && !incremental && !doIndexing)
-        {
-          // Special case to support RTF construction into shared DTM.
-          // It should actually still work for other uses,
-          // but may be slightly deoptimized relative to the base
-          // to allow it to deal with carrying multiple documents.
-          //
-          // %REVIEW% This is a sloppy way to request this mode;
-          // we need to consider architectural improvements.
-          dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter,
-                               xstringFactory, doIndexing);
-        }
-        /**************************************************************
-        // EXPERIMENTAL 3/22/02
-        else if(JKESS_XNI_EXPERIMENT && m_incremental)
-        {        	
-          dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
-                            xstringFactory, doIndexing);
-        }
-        **************************************************************/
-        else // Create the basic SAX2DTM.
-        {
-          dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
-                            xstringFactory, doIndexing);
-        }
-
-        // Go ahead and add the DTM to the lookup table.  This needs to be
-        // done before any parsing occurs. Note offset 0, since we've just
-        // created a new DTM.
+        xmlSource.setSystemId(urlOfSource);
+      } // urlOfSource fixup
+      
+      // %REVIEW% Need a better test for whether Xerces2 is available
+      // This one involves creating a SAX reader, then discarding
+      // it in order to build a lower-level XNI reader. Wasteful.
+      XMLReader reader = getXMLReader(source);
+      if(reader.getClass().getName().equals("org.apache.xerces.parsers.SAXParser")) 
+      {         
+        DTM dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
+                              xstringFactory, doIndexing);
         addDTM(dtm, dtmPos, 0);
 
-
-        boolean haveXercesParser =
-          (null != reader)
-          && (reader.getClass().getName().equals("org.apache.xerces.parsers.SAXParser") );
-        
-        if (haveXercesParser)
-          incremental = true;  // No matter what.  %REVIEW%
-        
-        // If the reader is null, but they still requested an incremental build,
-        // then we still want to set up the IncrementalSAXSource stuff.
-        if (this.m_incremental && incremental /* || ((null == reader) && incremental) */)
         {
-          IncrementalSAXSource coParser=null;
+          // %REVIEW% Currently this creates a new instance of Xerces, since
+          // there's no way to access the XNI APIs of an existing SAXParser.
+          // This is wasteful since a reader as already created.
+          // Can we rationalize this flow? Can we get Xerces improved?
+          IncrementalSAXSource_Xerces coParser;
+          coParser=(IncrementalSAXSource_Xerces)IncrementalSAXSource_Xerces.createIncrementalSAXSource();
 
-          if (haveXercesParser)
-          {
-            // IncrementalSAXSource_Xerces to avoid threading.
-            try {
-              coParser=org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces.createIncrementalSAXSource();
-            }  catch( Exception ex ) {
-              ex.printStackTrace();
-              coParser=null;
-            }
-          }
-
-          if( coParser==null ) {
-            // Create a IncrementalSAXSource that will run on the secondary thread.
-            if (null == reader)
-              coParser = new IncrementalSAXSource_Filter();
-            else
-            {
-              IncrementalSAXSource_Filter filter=new IncrementalSAXSource_Filter();
-              filter.setXMLReader(reader);
-              coParser=filter;
-            }
-
-          }
-
-			
-        /**************************************************************
-        // EXPERIMENTAL 3/22/02
-          if(JKESS_XNI_EXPERIMENT && m_incremental & 
-          	dtm instanceof XNI2DTM && 
-          	coParser instanceof IncrementalSAXSource_Xerces)
-          {          	
-       		org.apache.xerces.xni.parser.XMLPullParserConfiguration xpc=
-       			((IncrementalSAXSource_Xerces)coParser).getXNIParserConfiguration();
-       		if(xpc!=null)	
-       			// Bypass SAX; listen to the XNI stream
-          		((XNI2DTM)dtm).setIncrementalXNISource(xpc);
-          	else
-          		// Listen to the SAX stream (will fail, diagnostically...)
-				dtm.setIncrementalSAXSource(coParser);
-          } else
-          ***************************************************************/
+          // Bypass SAX; listen to the XNI stream
+          // %REVIEW% This shouldn't have a compile-time dependency on Xerces2!
+          // Can we fix it? (Change to Object?)
+          org.apache.xerces.xni.parser.XMLPullParserConfiguration xpc=
+            ((IncrementalSAXSource_Xerces)coParser).getXNIParserConfiguration();
+          ((XNI2DTM)dtm).setIncrementalXNISource(xpc);
           
-          // Have the DTM set itself up as the IncrementalSAXSource's listener.
-          dtm.setIncrementalSAXSource(coParser);
-
-          if (null == xmlSource)
-          {
-
-            // Then the user will construct it themselves.
-            return dtm;
-          }
-
-          if(null == reader.getErrorHandler())
-            reader.setErrorHandler(dtm);
-          reader.setDTDHandler(dtm);
-
           try
           {
-
-            // Launch parsing coroutine.  Launches a second thread,
-            // if we're using IncrementalSAXSource.filter().
+            // Launch parsing coroutine. 
             coParser.startParse(xmlSource);
+            
+            // %REVIEW% Kluge: Run nominal incremental setup in non-incremental
+            // mode. Simplifies this code, but it's a badly mixed metaphor.
+	        if(!this.m_incremental)
+	        	coParser.deliverAllNodes();
           }
           catch (RuntimeException re)
           {
-
-            dtm.clearCoRoutine();
-
             throw re;
           }
           catch (Exception e)
           {
-
-            dtm.clearCoRoutine();
-
             throw new org.apache.xml.utils.WrappedRuntimeException(e);
           }
-        }
-        else
+          
+          return dtm;
+        } // if incremental
+        
+      } // If Xerces2
+      
+      // Fallback: Turn it into a SAX request. (We _could_ just let
+      // it fall through unchanged and put an OR in SAX case, as I do
+      // when disabling this block for debugging purposes... but
+      // I think making it explicit may be clearer.
+      source=new SAXSource(reader,xmlSource);
+      // FALL THROUGH to SAX processing
+    } // if streamsource
+        
+        
+    if ((source instanceof SAXSource) 
+    	// || (!JJK_ENABLE_XNI && source instanceof StreamSource) // debug fallback
+    	)
+    {
+      XMLReader reader;
+      InputSource xmlSource;
+      SAX2DTM dtm;
+      
+      reader = getXMLReader(source);
+      xmlSource = SAXSource.sourceToInputSource(source);
+      
+      String urlOfSource = xmlSource.getSystemId();
+      if (null != urlOfSource)
+      {
+        try
         {
+          urlOfSource=SystemIDResolver.getAbsoluteURI(urlOfSource);
+        }
+        catch (Exception e)
+        {
+          // %REVIEW% Is there a better way to send a warning?
+          System.err.println("Can not absolutize URL: " + urlOfSource);
+        }
+        xmlSource.setSystemId(urlOfSource);
+      }
+
+      dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
+                          xstringFactory, doIndexing);
+
+      // Add the DTM to the lookup table with offset 0 (start of new DTM).
+      // This needs to be done before any parsing occurs.
+      addDTM(dtm, dtmPos, 0);
+
+      boolean haveXercesParser =
+        (null != reader)
+        && (reader.getClass().getName().equals("org.apache.xerces.parsers.SAXParser") );
+        
+      if (haveXercesParser)
+        incremental = true;  // No matter what.  %REVIEW%
+        
+      // If the reader is null, but they still requested an incremental build,
+      // then we still want to set up the IncrementalSAXSource stuff.
+      if (this.m_incremental && incremental /* || ((null == reader) && incremental) */)
+      {
+        IncrementalSAXSource coParser=null;
+
+        if (haveXercesParser)
+        {
+          // IncrementalSAXSource_Xerces to avoid threading.
+          // %REVIEW% Currently this creates a new instance of Xerces, since
+          // there's no way to access the incremental parsing APIs in today's
+          // Xerces. This is wasteful since a reader was already created.
+          // Can we rationalize this flow?
+          try {
+            coParser=org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces.createIncrementalSAXSource();
+          }  catch( Exception ex ) {
+            ex.printStackTrace();
+            coParser=null;
+          }
+        }
+
+        if( coParser==null ) {
+          // Create a IncrementalSAXSource that will run on the secondary thread.
           if (null == reader)
+            coParser = new IncrementalSAXSource_Filter();
+          else
           {
-
-            // Then the user will construct it themselves.
-            return dtm;
+            IncrementalSAXSource_Filter filter=new IncrementalSAXSource_Filter();
+            filter.setXMLReader(reader);
+            coParser=filter;
           }
 
-          // not incremental
-          reader.setContentHandler(dtm);
-          reader.setDTDHandler(dtm);
-          if(null == reader.getErrorHandler())
-            reader.setErrorHandler(dtm);
-
-          try
-          {
-            reader.setProperty(
-                               "http://xml.org/sax/properties/lexical-handler", dtm);
-          }
-          catch (SAXNotRecognizedException e){}
-          catch (SAXNotSupportedException e){}
-
-          try
-          {
-            reader.parse(xmlSource);
-          }
-          catch (RuntimeException re)
-          {
-
-            dtm.clearCoRoutine();
-
-            throw re;
-          }
-          catch (Exception e)
-          {
-
-            dtm.clearCoRoutine();
-
-            throw new org.apache.xml.utils.WrappedRuntimeException(e);
-          }
         }
 
-        if (DUMPTREE)
+        // Have the DTM set itself up as the IncrementalSAXSource's listener.
+        dtm.setIncrementalSAXSource(coParser);
+
+        if (null == xmlSource)
         {
-          System.out.println("Dumping SAX2DOM");
-          dtm.dumpDTM(System.err);
+
+          // Then the user will construct it themselves.
+          return dtm;
         }
 
-        return dtm;
+        if(null == reader.getErrorHandler())
+          reader.setErrorHandler(dtm);
+        reader.setDTDHandler(dtm);
+
+        try
+        {
+
+          // Launch parsing coroutine.  Launches a second thread,
+          // if we're using IncrementalSAXSource.filter().
+          coParser.startParse(xmlSource);
+        }
+        catch (RuntimeException re)
+        {
+
+          dtm.clearCoRoutine();
+
+          throw re;
+        }
+        catch (Exception e)
+        {
+
+          dtm.clearCoRoutine();
+
+          throw new org.apache.xml.utils.WrappedRuntimeException(e);
+        }
       }
       else
       {
+        if (null == reader)
+        {
 
-        // It should have been handled by a derived class or the caller
-        // made a mistake.
-        throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source);
+          // Then the user will construct it themselves.
+          return dtm;
+        }
+
+        // not incremental
+        reader.setContentHandler(dtm);
+        reader.setDTDHandler(dtm);
+        if(null == reader.getErrorHandler())
+          reader.setErrorHandler(dtm);
+
+        try
+        {
+          reader.setProperty(
+                             "http://xml.org/sax/properties/lexical-handler", dtm);
+        }
+        catch (SAXNotRecognizedException e){}
+        catch (SAXNotSupportedException e){}
+
+        try
+        {
+          reader.parse(xmlSource);
+        }
+        catch (RuntimeException re)
+        {
+
+          dtm.clearCoRoutine();
+
+          throw re;
+        }
+        catch (Exception e)
+        {
+
+          dtm.clearCoRoutine();
+
+          throw new org.apache.xml.utils.WrappedRuntimeException(e);
+        }
       }
+
+      if (DUMPTREE)
+      {
+        System.out.println("Dumping SAX2DOM");
+        dtm.dumpDTM(System.err);
+      }
+
+      return dtm;
+    }
+
+    else
+    {
+
+      // It should have been handled by a derived class or the caller
+      // made a mistake.
+      throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source);
     }
   }
 
@@ -794,10 +894,10 @@
     {
       System.out.println("Releasing "+
 			 (shouldHardDelete ? "HARD" : "soft")+
-			 " dtm="+
+			 " dtm="+dtm
 			 // Following shouldn't need a nodeHandle, but does...
 			 // and doesn't seem to report the intended value
-			 dtm.getDocumentBaseURI()
+			 +" ("+dtm.getDocumentBaseURI()+")"
 			 );
     }
 
diff --git a/src/org/apache/xml/dtm/ref/DTMNodeList.java b/src/org/apache/xml/dtm/ref/DTMNodeList.java
index 761485e..896035d 100644
--- a/src/org/apache/xml/dtm/ref/DTMNodeList.java
+++ b/src/org/apache/xml/dtm/ref/DTMNodeList.java
@@ -112,10 +112,23 @@
         dtm_iter=(DTMIterator)dtmIterator.cloneWithReset();
       }
       catch(CloneNotSupportedException cnse) {}
-      dtm_iter.setShouldCacheNodes(true);
+      dtm_iter.setShouldCache(true);
       dtm_iter.runTo(-1);
       dtm_iter.setCurrentPos(pos);
     }
+    
+  /** Public constructor: Create a NodeList to support a XNodeSequenceSingleton.
+   *
+   * @param dtm The DTM containing this node.
+   * @param node node-handle integer.
+   * @param dummy unused.
+   * */
+  public DTMNodeList(DTM dtm,int node, boolean dummy)
+  {
+    dtm_iter=null;
+    m_parentDTM=dtm;
+    m_firstChild=node;
+  }
 
   /** Public constructor: Create a NodeList to support
    * DTMNodeProxy.getChildren().
diff --git a/src/org/apache/xml/dtm/ref/ExpandedNameTable.java b/src/org/apache/xml/dtm/ref/ExpandedNameTable.java
index 24bb4b1..0adc7a7 100644
--- a/src/org/apache/xml/dtm/ref/ExpandedNameTable.java
+++ b/src/org/apache/xml/dtm/ref/ExpandedNameTable.java
@@ -77,6 +77,11 @@
  * */
 public class ExpandedNameTable
 {
+  // A bit of a kluge... We want assign-only-once behavior for the
+  // schemaType field, and null is a legitimate value... so we need
+  // a cheap non-null singleton object to use as the not-yet-set flag.
+  // As it happens, almost anything will work...
+  static final Object UNKNOWN_SCHEMA_TYPE=Boolean.FALSE;    
 
   /** Probably a reference to static pool.     */
   private DTMStringPool m_locNamesPool;
@@ -282,12 +287,45 @@
     return (short)etype.nodetype;
   }
   
-  
+  /** Store the default schema datatype associated with this expanded
+      name.
+
+      @return true if the default has been set (or if the new value
+      matches the old one), false if the new doesn't match (meaning
+      you'd better record this as a per-node exception).
+  */
+  public boolean setSchemaType(int ExpandedNameID, Object schemaType)
+  {
+    ExtendedType et=(ExtendedType)m_extendedTypes.elementAt (ExpandedNameID);
+    if(et.schemaType==UNKNOWN_SCHEMA_TYPE)
+    {
+      et.schemaType=schemaType;
+      return true;
+    }
+    else if(et.schemaType==schemaType || 
+    	(et.schemaType!=null && et.schemaType.equals(schemaType)) )
+      return true;
+    else
+      return false;
+  }
+
+  /** @return the default schema datatype associated with this expanded
+      name, null if none has been bound OR if the type bound was itself
+      null.
+  */
+  public Object getSchemaType(int ExpandedNameID)
+  {
+    ExtendedType et=(ExtendedType)m_extendedTypes.elementAt (ExpandedNameID);
+    return (et.schemaType==UNKNOWN_SCHEMA_TYPE) ? null : et.schemaType;
+  }
+
   /**
    * Private class representing an extended type object 
    */
   private class ExtendedType
   {
+    protected Object schemaType=UNKNOWN_SCHEMA_TYPE;
+    
     protected int nodetype;
     protected String namespace;
     protected String localName;
diff --git a/src/org/apache/xml/dtm/ref/IncrementalSAXSource_Xerces.java b/src/org/apache/xml/dtm/ref/IncrementalSAXSource_Xerces.java
index ec02fdf..8be90a9 100644
--- a/src/org/apache/xml/dtm/ref/IncrementalSAXSource_Xerces.java
+++ b/src/org/apache/xml/dtm/ref/IncrementalSAXSource_Xerces.java
@@ -61,13 +61,17 @@
 import org.xml.sax.SAXException;
 import java.io.IOException;
 import org.apache.xerces.parsers.SAXParser;
+import org.apache.xml.utils.WrappedRuntimeException;
 import org.xml.sax.XMLReader;
 
 import org.apache.xalan.res.XSLTErrorResources;
 import org.apache.xalan.res.XSLMessages;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
+import javax.xml.transform.TransformerException;
+
 
 /** <p>IncrementalSAXSource_Xerces takes advantage of the fact that Xerces1
  * incremental mode is already a coroutine of sorts, and just wraps our
@@ -177,7 +181,41 @@
 			this.fParseSome=dummy.fParseSome;
 			this.fIncrementalParser=dummy.fIncrementalParser;
 		}
-  }
+
+		// General SAX-level feature initialization
+		try
+		{
+			fIncrementalParser.setFeature("http://xml.org/sax/features/validation",true);
+		}
+		catch(org.xml.sax.SAXNotRecognizedException e) {e.printStackTrace();}
+		catch(org.xml.sax.SAXNotSupportedException e) {e.printStackTrace();}
+		try
+		{
+			fIncrementalParser.setFeature("http://apache.org/xml/features/validation/dynamic",true);
+		}
+		catch(org.xml.sax.SAXNotRecognizedException e) {e.printStackTrace();}
+		catch(org.xml.sax.SAXNotSupportedException e) {e.printStackTrace();}
+
+		// %REVIEW% Turning on schema support is necessary for some
+		// of the information we'd like to retrieve. Unfortunately,
+		// XERCES currently slows down by 90% (ie, takes twice as
+		// long to run!) with this feature enabled, even if the
+		// document never references schemas. We could make this
+		// optional (resurrect the old -VALIDATE switch?), but it's
+		// really not clear we want the user to have to deal with
+		// manually setting this appropriately for every document.
+		// The default would have to be full validation, slow mode.
+		//
+		// I'm trying to convince Xerces that higher speed should be
+		// given higher priority.
+		try
+		{
+			fIncrementalParser.setFeature("http://apache.org/xml/features/validation/schema",true);
+		}
+		catch(org.xml.sax.SAXNotRecognizedException e) {e.printStackTrace();}
+		catch(org.xml.sax.SAXNotSupportedException e) {e.printStackTrace();}
+		
+   }
 
   /** Create a IncrementalSAXSource_Xerces wrapped around
    * an existing SAXParser. Currently this works only for recent
@@ -348,7 +386,39 @@
     return arg;
   }
 	
-	// Private methods -- conveniences to hide the reflection details
+  static final Object[] parmstrue={Boolean.TRUE};
+	
+  /** deliverAllNodes() is a simple API which tells the coroutine
+   * parser to run until all nodes have been delivered.  
+   * This is a bit of a kluge, intended to address the case where
+   * we're using IncrementalSAXSource_Xerces not for its incrementality
+   * but as a wrapper around the Xerces XNI layer; its primary purpose
+   * is to simplify the logic in DTMManagerDefault.java
+   * */
+  public void deliverAllNodes() throws SAXException
+  {
+    try
+    {
+      Object ret =
+        (Boolean) (fConfigParse.invoke(fPullParserConfig, parmstrue));
+    }
+    catch (IllegalAccessException iae)
+    {
+      throw new WrappedRuntimeException(
+        new TransformerException(iae));
+    }
+    catch (InvocationTargetException ite)
+    {
+      throw new WrappedRuntimeException(
+        new TransformerException(ite.getTargetException()));
+    }
+    catch (RuntimeException ex)
+    {
+      throw new WrappedRuntimeException(new TransformerException(ex));
+    }
+  }
+  
+  	// Private methods -- conveniences to hide the reflection details
 	private boolean parseSomeSetup(InputSource source) 
 		throws SAXException, IOException, IllegalAccessException, 
 					 java.lang.reflect.InvocationTargetException,
@@ -479,6 +549,18 @@
     }
     
   }
+  
+  /** EXPERIMENTAL AS OF 3/22/02: Support for XNI2DTM, allowing us to
+   * bind direct to the parser's XNI stream.
+   * 
+   * %BUG% Gonk -- This requires hard link to Xerces2. Could use reflection
+   * typecasting, but for now... Does anyone still care about Xerces1?
+   * */
+  public org.apache.xerces.xni.parser.XMLPullParserConfiguration getXNIParserConfiguration()
+  {
+  	return (org.apache.xerces.xni.parser.XMLPullParserConfiguration)fPullParserConfig;
+  }
+
 
   
 } // class IncrementalSAXSource_Xerces
diff --git a/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java b/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
index 80eb115..0ae8473 100644
--- a/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
+++ b/src/org/apache/xml/dtm/ref/dom2dtm/DOM2DTM.java
@@ -94,6 +94,9 @@
  * Note too that we do not currently attempt to track document
  * mutation. If you alter the DOM after wrapping DOM2DTM around it,
  * all bets are off.
+ * %REVIEW% We _could_ ask the DOM whether it supports mutation
+ * events, and if so use that to invalidate the DTM or at least
+ * toss a warning back into Xalan...
  * */
 public class DOM2DTM extends DTMDefaultBaseIterators
 {
diff --git a/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java b/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java
index 57e0e13..aeb7c06 100644
--- a/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java
+++ b/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java
@@ -82,6 +82,12 @@
 /**
  * This class implements a DTM that tends to be optimized more for speed than
  * for compactness, that is constructed via SAX2 ContentHandler events.
+ * 
+ * NOTE: This version of the code incorporates the logic needed to allow
+ * "shared DTMs", where a single DTM contains several documents which may
+ * be tail-pruned away. This mode is used for result tree 
+ * fragments/temporary trees. A separate constructor *must* be used to
+ * invoke this mode.
  */
 public class SAX2DTM extends DTMDefaultBaseIterators
         implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
@@ -89,6 +95,14 @@
 {
   /** Set true to monitor SAX events and similar diagnostic info. */
   private static final boolean DEBUG = false;
+  
+	/** See discussion in endDocument() */
+	static final boolean JJK_LEAVE_DOCUMENT_CURRENT=false;  
+
+  /** Set true when the DTM goes into Shared DTM mode -- specifically, when
+   * the shared-mode constructor is invoked.
+   * */
+  private boolean m_isSharedDTM=false;
 
   /**
    * If we're building the model incrementally on demand, we need to
@@ -116,11 +130,26 @@
    * between RTFs, and tail-pruning... consider going back to the larger/faster.
    *
    * Made protected rather than private so SAX2RTFDTM can access it.
+   * Minimum chunk size pushed up now that SAX2RTFDTM is in use (larger
+   * minimum allocation, lower overhead as it grows). 
+   * %REVIEW% Variable size disabled in FSB. Consider (13,13).
    */
-  //private FastStringBuffer m_chars = new FastStringBuffer(13, 13);
-  protected FastStringBuffer m_chars = new FastStringBuffer(5, 13);
+  protected FastStringBuffer m_chars = new FastStringBuffer(10, 13);
 
-  /** This vector holds offset and length data.
+  /** This vector holds _integer pairs_ representing the "node value"
+   * referenced by m_dataOrQName. It's basically a kluge to save a word 
+   * per node for nodes which don't carry this information... AND is
+   * overloaded to handle two distinct cases.
+   * 
+   * In: index (and index+1) from m_dataOrQName 
+   * 
+   * Out: Offset and length references into m_chars (for character content)
+   * 	***OR***
+   * 	(IF m_dataOrQName returned a negated index for an Attr node,
+   *    indicating a prefixed attribute):
+   * 	m_valuesOrPrefixes identifiers of prefix and value 
+   *
+   * %REVIEW% Is this really the best solution? I hae me doots!
    */
   protected SuballocatedIntVector m_data;
 
@@ -164,7 +193,7 @@
   protected DTMTreeWalker m_walker = new DTMTreeWalker();
 
   /** pool of string values that come as strings. */
-  private DTMStringPool m_valuesOrPrefixes = new DTMStringPool();
+  protected DTMStringPool m_valuesOrPrefixes = new DTMStringPool();
 
   /** End document has been reached.
    * Made protected rather than private so SAX2RTFDTM can access it.
@@ -237,9 +266,34 @@
    */
   protected IntVector m_sourceColumn;
   
+  /** Index of most recently started Document, or NULL if the DTM is shared and empty.  */
+  private int m_currentDocumentNode=0;
+  
+  /** Tail-pruning mark: Number of nodes in use. Null if not a shared DTM. */
+  IntStack mark_size=null;
+  /** Tail-pruning mark: Number of data items in use. Null if not a shared DTM. */
+  IntStack mark_data_size=null;
+  /** Tail-pruning mark: Number of size-of-data fields in use. Null if not a shared DTM. */
+  IntStack mark_char_size=null;
+  /** Tail-pruning mark: Number of dataOrQName slots in use. Null if not a shared DTM. */
+  IntStack mark_doq_size=null;
+  /** Tail-pruning mark: Number of namespace declaration sets in use. Null if not a shared DTM.
+   * %REVIEW% I don't think number of NS sets is ever different from number
+   * of NS elements. We can probabably reduce these to a single stack and save
+   * some storage.
+   * */
+  IntStack mark_nsdeclset_size=null;
+  /** Tail-pruning mark: Number of namespace declaration elements in use. Null if not a shared DTM.
+   * %REVIEW% I don't think number of NS sets is ever different from number
+   * of NS elements. We can probabably reduce these to a single stack and save
+   * some storage.
+   */
+  IntStack mark_nsdeclelem_size=null;
+    
   /**
    * Construct a SAX2DTM object ready to be constructed from SAX2
-   * ContentHandler events.
+   * ContentHandler events. DTMs produced by this constructor do _NOT_
+   * support shared mode.
    *
    * @param mgr The DTMManager who owns this DTM.
    * @param source the JAXP 1.1 Source object for this DTM.
@@ -261,8 +315,10 @@
           
     // %REVIEW%  Initial size pushed way down to reduce weight of RTFs
     // (I'm not entirely sure 0 would work, so I'm playing it safe for now.)
+    // %REVIEW% Given shared RTF DTM, we might be able to push this
+    // back up again...?
     //m_data = new SuballocatedIntVector(doIndexing ? (1024*2) : 512, 1024);
-    m_data = new SuballocatedIntVector(32, 1024);
+    m_data = new SuballocatedIntVector(32);
 
     m_data.addElement(0);   // Need placeholder in case index into here must be <0.
 
@@ -279,6 +335,57 @@
   }
 
   /**
+   * Construct a SAX2DTM object ready to be constructed from SAX2
+   * ContentHandler events. DTMs produced by this constructor may support
+   * shared mode.
+   *
+   * @param mgr The DTMManager who owns this DTM.
+   * @param source the JAXP 1.1 Source object for this DTM.
+   * @param dtmIdentity The DTM identity ID for this DTM.
+   * @param whiteSpaceFilter The white space filter for this DTM, which may
+   *                         be null.
+   * @param xstringfactory XMLString factory for creating character content.
+   * @param doIndexing true if the caller considers it worth it to use 
+   *    indexing schemes. HOWEVER: Indexes may be suppressed if shared is
+   *    true, since they tend to be hard to prune efficiently.
+   * @param shared true if the caller may want to write multiple documents
+   *    into this DTM and prune them away again. This should be set true
+   *    only for Result-Tree-Fragment/Temporary-Tree DTMs.
+   */
+  public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity,
+                 DTMWSFilter whiteSpaceFilter,
+                 XMLStringFactory xstringfactory,
+                 boolean doIndexing, boolean shared)
+  {
+  	// Normal construction. Note doIndexing forced false when shared is true.
+  	this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
+         doIndexing & !shared);
+         
+    m_isSharedDTM=shared;
+         
+    if(shared)
+    {
+		// NEVER track source locators for RTFs; they aren't meaningful. I think.
+		// (If we did track them, we'd need to tail-prune these too.)
+		m_useSourceLocationProperty=false; //org.apache.xalan.processor.TransformerFactoryImpl.m_source_location;
+		m_sourceSystemId =  null;
+		m_sourceLine = null;
+		m_sourceColumn = null;
+		
+		// Initialize data structures for tail-pruning
+		mark_size=new IntStack();
+		mark_data_size=new IntStack();
+		mark_char_size=new IntStack();
+		mark_doq_size=new IntStack();
+		mark_nsdeclset_size=new IntStack();
+		mark_nsdeclelem_size=new IntStack();
+		
+		// Safety-net, to help make sure we're using this as intended
+		m_currentDocumentNode=NULL;
+    }
+  }
+             
+  /**
    * Get the data or qualified name for the given node identity.
    *
    * @param identity The node identity.
@@ -304,6 +411,32 @@
         return m_dataOrQName.elementAt(identity);
     }
   }
+  
+  /**
+   * Given a node identifier, find the owning document node.  Unlike the DOM,
+   * this considers the owningDocument of a Document to be itself. Note that
+   * in shared DTMs this may be nonzero.
+   *
+   * @param nodeId the id of the node.
+   * @return int Node identifier of owning document, or the nodeId if it is
+   *             a Document.
+   */
+  protected int _documentRoot(int nodeIdentifier)
+  {
+  	if(nodeIdentifier==NULL) return NULL;
+  	
+  	if(!m_isSharedDTM)
+  		return 0;
+
+  	// Otherwise, shared DTM and we have to do this the slow way.
+    for(int parent=_parent(nodeIdentifier);
+    	parent!=NULL;
+    	nodeIdentifier=parent,parent=_parent(nodeIdentifier))
+    	;
+    
+    return nodeIdentifier;
+  }
+  
 
   /**
    * Ask the CoRoutine parser to doTerminate and clear the reference.
@@ -569,8 +702,7 @@
   {
 
     int expandedTypeID = getExpandedTypeID(nodeHandle);
-    // If just testing nonzero, no need to shift...
-    int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID);                     
+    int namespaceID =  m_expandedNameTable.getNamespaceID(expandedTypeID);
 
     if (0 == namespaceID)
     {
@@ -617,8 +749,8 @@
   public String getNodeNameX(int nodeHandle)
   {
 
-    int expandedTypeID = getExpandedTypeID(nodeHandle);    
-    int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID);                      
+    int expandedTypeID = getExpandedTypeID(nodeHandle);
+    int namespaceID =  m_expandedNameTable.getNamespaceID(expandedTypeID);
 
     if (0 == namespaceID)
     {
@@ -690,13 +822,13 @@
 
     identity += 1;
 
-    while (identity >= m_size)
-    {
-      if (null == m_incrementalSAXSource)
-        return DTM.NULL;
+    while (identity >= m_size && nextNode())
+    	;
 
-      nextNode();
-    }
+	// If we exited because nextNode ran off the end of the document,
+	// rather than because we found the node we needed, return null.
+	if(identity>=m_size)
+		return DTM.NULL;
 
     return identity;
   }
@@ -746,8 +878,13 @@
 
   /**
    * This method should try and build one or more nodes in the table.
+   * 
+   * %OPT% When working with Xerces2, an incremental parsing step may not
+   * actually generate a SAX event that causes a node to be built. Our higher-
+   * level code is already looping to see if the desired node was obtained...
+   * but should we also be looping more tightly here?
    *
-   * @return The true if a next node is found or false if
+   * @return True if parsing proceeded normally or false if
    *         there are no more nodes.
    */
   protected boolean nextNode()
@@ -1103,6 +1240,12 @@
         return getPrefix(qname, null);
       }
     }
+    else if (DTM.NAMESPACE_NODE == type)
+    {
+    	if(!"xmlns".equals(getLocalName(nodeHandle)))
+    		return "xmlns";
+    	// else return "".
+    }
 
     return "";
   }
@@ -1138,6 +1281,54 @@
 
     return DTM.NULL;
   }
+  
+  /**
+   * Given a DTM, find the owning document node. In the case of
+   * SAX2RTFDTM, which may contain multiple documents, this returns
+   * the <b>most recently started</b> document, or null if the DTM is
+   * empty or no document is currently under construction.
+   *
+   * %REVIEW% Should we continue to report the most recent after
+   * construction has ended? I think not, given that it may have been
+   * tail-pruned.
+   *
+   *  @param nodeHandle the id of the node.
+   *  @return int Node handle of Document node, or null if this DTM does not
+   *  contain an "active" document.
+   * */
+  public int getDocument()
+  {
+  	// %REVIEW% Would adding these lines affect speed, and if so which way?
+  	// if(!m_isSharedDTM)
+  	//	return m_dtmIdent.elementAt(0); // like DTMDefaultBase
+    return makeNodeHandle(m_currentDocumentNode);
+  }
+  
+  /**
+   * Given a node handle, find the owning document node, using DTM semantics
+   * (Document owns itself) rather than DOM semantics (Document has no owner).
+   *
+   * (I'm counting on the fact that getOwnerDocument() is implemented on top
+   * of this call, in the superclass, to avoid having to rewrite that one.
+   * Be careful if that code changes!)
+   *
+   * @param nodeHandle the id of the node.
+   * @return int Node handle of owning document
+   */
+  public int getDocumentRoot(int nodeHandle)
+  {
+  	if(!m_isSharedDTM)
+  		return getDocument();
+  	
+  	// If shared, we have to do it the hard way
+    for(int id=makeNodeIdentity(nodeHandle);
+		id!=NULL;
+		id=_parent(id))
+		if(_type(id)==DTM.DOCUMENT_NODE)
+  			return makeNodeHandle(id);
+
+    return DTM.NULL; // Safety net; should never happen
+  }
 
   /**
    * Return the public identifier of the external subset,
@@ -1171,8 +1362,13 @@
    */
   public String getNamespaceURI(int nodeHandle)
   {
+  	int identity=makeNodeIdentity(nodeHandle);
+  	
+  	// DOM says all namespace nodes are in the namespace namespace.
+  	if (_type(identity) == NAMESPACE_NODE)
+  		return "http://www.w3.org/XML/1998/namespace";
 
-    return m_expandedNameTable.getNamespace(_exptype(makeNodeIdentity(nodeHandle)));
+    return m_expandedNameTable.getNamespace(_exptype(identity));
   }
 
   /**
@@ -1302,7 +1498,7 @@
    *
    * @return The prefix if there is one, or null.
    */
-  private String getPrefix(String qname, String uri)
+  protected String getPrefix(String qname, String uri)
   {
 
     String prefix;
@@ -1545,6 +1741,18 @@
   {
     if (DEBUG)
       System.out.println("startDocument");
+      
+    if(m_isSharedDTM)
+    {
+		// (Re)initialize the tree construction process
+		// %REVIEW% Slightly wasteful on the first document written to 
+		// the shared DTM, since these have already been allocated.
+		m_endDocumentOccured = false;
+		m_prefixMappings = new java.util.Vector();
+		m_contextIndexes = new IntStack();
+		m_parents = new IntStack();
+	    m_currentDocumentNode=m_size;
+    }
 
 		
     int doc = addNode(DTM.DOCUMENT_NODE,
@@ -1569,12 +1777,12 @@
     if (DEBUG)
       System.out.println("endDocument");
 
-		charactersFlush();
+	charactersFlush();
 
-    m_nextsib.setElementAt(NULL,0);
+    m_nextsib.setElementAt(NULL,m_currentDocumentNode);
 
-    if (m_firstch.elementAt(0) == NOTPROCESSED)
-      m_firstch.setElementAt(NULL,0);
+    if (m_firstch.elementAt(m_currentDocumentNode) == NOTPROCESSED)
+      m_firstch.setElementAt(NULL,m_currentDocumentNode);
 
     if (DTM.NULL != m_previous)
       m_nextsib.setElementAt(DTM.NULL,m_previous);
@@ -1583,6 +1791,15 @@
     m_prefixMappings = null;
     m_contextIndexes = null;
 
+	// This is debatable. Clearing it in shared DTMs does help keep
+	// us honest, by ensuring against using getDocument() in a situation
+	// where we aren't sure which document is being referred to.
+	// We _shouldn't_ clear it in non-shared DTMs, since -- at this time,
+	// anyway -- some of the start-up code assumes that getDocument() on the
+	// source document will work after the doc is closed.
+    if(!JJK_LEAVE_DOCUMENT_CURRENT && m_isSharedDTM)
+	    m_currentDocumentNode= NULL; // no longer open
+	    
     m_endDocumentOccured = true;
   }
 
@@ -1679,7 +1896,7 @@
     return false;
   }
 	
-	boolean m_pastFirstElement=false;
+	protected boolean m_pastFirstElement=false;
 
   /**
    * Receive notification of the start of an element.
@@ -2349,4 +2566,100 @@
     }
     return null;
   }
+  
+  /** "Tail-pruning" support for RTFs.
+   * 
+   * This function pushes information about the current size of the
+   * DTM's data structures onto a stack, for use by popRewindMark()
+   * (which see).
+   * 
+   * This will fail with null-pointer exceptions if called on a non-shared
+   * DTM. That's deliberate, since it's considered a severe coding error.
+   * 
+   * %REVIEW% I have no idea how to rewind m_elemIndexes. However,
+   * RTFs should not be indexed, so I can simply panic if that case
+   * arises. Hey, it works...
+   * */
+  public void pushRewindMark()
+  {
+    if(m_indexing || m_elemIndexes!=null) 
+      throw new java.lang.NullPointerException("Coding error; Don't try to mark/rewind an indexed DTM");
+
+    // Values from DTMDefaultBase
+    // %REVIEW% Can the namespace stack sizes ever differ? If not, save space!
+    mark_size.push(m_size);
+    mark_nsdeclset_size.push( (m_namespaceDeclSets==null) ? 0 : m_namespaceDeclSets.size() );
+    mark_nsdeclelem_size.push( (m_namespaceDeclSetElements==null) ? 0 : m_namespaceDeclSetElements.size() );
+    
+    // Values from SAX2DTM
+    mark_data_size.push(m_data.size());
+    mark_char_size.push(m_chars.size());
+    mark_doq_size.push(m_dataOrQName.size());	
+  }
+  
+  /** "Tail-pruning" support for RTFs.
+   * 
+   * This function pops the information previously saved by
+   * pushRewindMark (which see) and uses it to discard all nodes added
+   * to the DTM after that time. We expect that this will allow us to
+   * reuse storage more effectively.
+   * 
+   * This is _not_ intended to be called while a document is still being
+   * constructed -- only between endDocument and the next startDocument
+   * 
+   * %REVIEW% WARNING: This is the first use of some of the truncation
+   * methods.  If Xalan blows up after this is called, that's a likely
+   * place to check.
+   * 
+   * %REVIEW% Our original design for DTMs permitted them to share
+   * string pools.  If there any risk that this might be happening, we
+   * can _not_ rewind and recover the string storage. One solution
+   * might to assert that DTMs used for RTFs Must Not take advantage
+   * of that feature, but this seems excessively fragile. Another, much
+   * less attractive, would be to just let them leak... Nah.
+   * 
+   * This will fail with null-pointer exceptions if called on a non-shared
+   * DTM. That's deliberate, since it's considered a severe coding error.
+   * 
+   * @return true if and only if the pop completely emptied the
+   * RTF. That response is used when determining how to unspool
+   * RTF-started-while-RTF-open situations.
+   * */
+  public boolean popRewindMark()
+  {
+    boolean top=mark_size.empty();
+    
+    m_size=top ? 0 : mark_size.pop();
+    m_exptype.setSize(m_size);
+    m_firstch.setSize(m_size);
+    m_nextsib.setSize(m_size);
+    m_prevsib.setSize(m_size);
+    m_parent.setSize(m_size);
+
+    m_elemIndexes=null;
+
+    int ds= top ? 0 : mark_nsdeclset_size.pop();
+    if (m_namespaceDeclSets!=null)
+      m_namespaceDeclSets.setSize(ds);
+      
+    int ds1= top ? 0 : mark_nsdeclelem_size.pop();
+    if (m_namespaceDeclSetElements!=null)
+      m_namespaceDeclSetElements.setSize(ds1);
+  
+    // Values from SAX2DTM
+    m_data.setSize(top ? 0 : mark_data_size.pop());
+    m_chars.setLength(top ? 0 : mark_char_size.pop());
+    m_dataOrQName.setSize(top ? 0 : mark_doq_size.pop());
+
+    // Return true iff DTM now empty
+    return m_size==0;
+  }
+  
+  /** @return true if a DTM tree is currently under construction.
+   * */
+  public boolean isTreeIncomplete()
+  {
+  	return !m_endDocumentOccured;
+  	
+  }  
 }
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/AbstractSchema.java b/src/org/apache/xml/dtm/ref/xni2dtm/AbstractSchema.java
new file mode 100644
index 0000000..d8445a3
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/AbstractSchema.java
@@ -0,0 +1,191 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.*;
+import org.w3c.dom.*;
+
+import org.apache.xerces.xni.*;
+import org.apache.xerces.xni.psvi.*;
+import org.apache.xerces.xni.grammars.XMLGrammarPool;
+
+
+/** This is a vague -- very vague -- attempt to encapsulate the XPath2
+ * "in-scope schema definitions". Our only available implementation at this
+ * time is highly Xerces-dependent, but I'd really rather not expose that
+ * more widely than I have to. 
+ * 
+ * This is supposed to be a set of (QName, type definition) pairs, defining the set
+ * of types available for reference within XPath expressions, including
+ * the validate() operation. PLEASE NOTE that these make absolutely no
+ * reference to the types referenced by the instance document, though the
+ * two sets are expected/hoped to overlap.
+ * 
+ * The built-in schema types should always be available. Additional schema
+ * documents can be loaded into the mix.
+ * 
+ * %REVIEW% Many issues -- base URI, you-name-it.
+ * */
+public class AbstractSchema {
+	org.apache.xerces.impl.xs.XMLSchemaLoader xsload=
+		new org.apache.xerces.impl.xs.XMLSchemaLoader();
+	org.apache.xerces.util.XMLGrammarPoolImpl pool=
+		new org.apache.xerces.util.XMLGrammarPoolImpl();
+		
+	public AbstractSchema()
+	{
+		// Apparently required to bind the two together, per Neil G.
+		// This implies pool.putGrammar will be called after loading.
+		xsload.setProperty(DOMValidationConfigurationSwipedFromXerces.GRAMMAR_POOL,pool);
+	}
+		
+	public void appendSchema(String publicId, String systemId,  
+                          String baseSystemId, java.io.InputStream byteStream,
+                          String encoding)
+	{
+		if(publicId==null) publicId="";
+		if(systemId==null) systemId="";
+		if(baseSystemId==null) baseSystemId="";
+		try
+		{
+			org.apache.xerces.xni.grammars.Grammar gmr=
+				xsload.loadGrammar(
+					new org.apache.xerces.xni.parser.XMLInputSource(
+					publicId, systemId, baseSystemId, byteStream, encoding));
+		}
+		catch (java.io.IOException e)
+		{
+			// DO SOMETHING WITH THIS!
+			System.err.println(e);
+		}
+	}
+	public void appendSchema(String publicId, String systemId,  
+                          String baseSystemId, java.io.Reader charStream,
+                          String encoding)
+	{
+		if(publicId==null) publicId="";
+		if(systemId==null) systemId="";
+		if(baseSystemId==null) baseSystemId="";
+		try
+		{
+			org.apache.xerces.xni.grammars.Grammar gmr=
+				xsload.loadGrammar(
+					new org.apache.xerces.xni.parser.XMLInputSource(
+					publicId, systemId, baseSystemId, charStream, encoding));
+		}
+		catch (java.io.IOException e)
+		{
+			// DO SOMETHING WITH THIS!
+			System.err.println(e);
+		}
+	}
+	public void appendSchema(String publicId, String systemId,  
+                          String baseSystemId)
+	{
+		if(publicId==null) publicId="";
+		if(systemId==null) systemId="";
+		if(baseSystemId==null) baseSystemId="";
+		try
+		{
+			// %REVIEW% Need more education on loading grammars; this is a kluge
+			// Need to set an error handler on this.
+			// Should we really reset every time?
+			xsload.reset();
+			
+			org.apache.xerces.xni.grammars.Grammar gmr=
+				xsload.loadGrammar(
+					new org.apache.xerces.xni.parser.XMLInputSource(
+					publicId, systemId, baseSystemId));
+		}
+		catch (java.io.IOException e)
+		{
+			// DO SOMETHING WITH THIS!
+			System.err.println(e);
+		}
+	}
+	
+	public Object getGrammarPool()
+	{
+		return pool;
+	}
+	
+	/** This relies on unpublished Xerces APIs. It's even more vulnerable
+	 * to future change than the rest of the PSVI interfaces.
+	 * Caveat hackitor!
+	 * 
+	 * Outline courtesy of Sandy Gao -- thanks again!
+	 * */
+	public XPath2Type lookUpType(String namespace,String typename)
+	{
+		XPath2Type ret=null;	
+		
+		org.apache.xerces.impl.xs.XSDDescription descr=
+			new org.apache.xerces.impl.xs.XSDDescription();
+		descr.setContextType(descr.CONTEXT_PREPARSE);
+		if(namespace==null) namespace=""; // I *think* this is right; not sure
+		descr.setTargetNamespace(namespace);
+
+		org.apache.xerces.xni.grammars.Grammar g=pool.getGrammar(descr);
+		if(g!=null)		
+			ret=new XPath2Type( ((org.apache.xerces.impl.xs.SchemaGrammar)g).getGlobalTypeDecl(typename),
+				namespace,typename);
+			
+		return ret;
+	}
+
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/DOMValidationConfigurationSwipedFromXerces.java b/src/org/apache/xml/dtm/ref/xni2dtm/DOMValidationConfigurationSwipedFromXerces.java
new file mode 100644
index 0000000..d71bf79
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/DOMValidationConfigurationSwipedFromXerces.java
@@ -0,0 +1,558 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001, 2002 The Apache Software Foundation.  
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xerces" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.apache.xerces.impl.Constants;
+import org.apache.xerces.impl.XMLEntityManager;
+import org.apache.xerces.impl.XMLErrorReporter;
+import org.apache.xerces.impl.validation.ValidationManager;
+import org.apache.xerces.impl.msg.XMLMessageFormatter;
+import org.apache.xerces.impl.xs.XSMessageFormatter;
+import org.apache.xerces.util.ParserConfigurationSettings;
+import org.apache.xerces.util.SymbolTable;
+import org.apache.xerces.xni.XMLDocumentHandler;
+import org.apache.xerces.xni.XMLDTDHandler;
+import org.apache.xerces.xni.XMLDTDContentModelHandler;
+import org.apache.xerces.xni.XNIException;
+import org.apache.xerces.xni.parser.XMLComponent;
+import org.apache.xerces.xni.parser.XMLComponentManager;
+import org.apache.xerces.xni.parser.XMLConfigurationException;
+import org.apache.xerces.xni.parser.XMLDocumentSource;
+import org.apache.xerces.xni.parser.XMLEntityResolver;
+import org.apache.xerces.xni.parser.XMLErrorHandler;
+import org.apache.xerces.xni.parser.XMLInputSource;
+import org.apache.xerces.xni.parser.XMLParserConfiguration;
+
+/**
+ * This configuration holds information needed for revalidation 
+ * of the DOM tree, ie. properties and features.
+ * Note: This configuration is different from any parser
+ * configuration and must not be used other than for DOM revalidation.
+ * 
+ * @author Elena Litani, IBM
+ * @version $Id$
+ */
+public class DOMValidationConfigurationSwipedFromXerces extends ParserConfigurationSettings
+    implements XMLParserConfiguration {
+
+    //
+    // Constants
+    //
+
+    // feature identifiers
+
+    /** Feature identifier: validation. */
+    public static final String VALIDATION =
+        Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
+    
+    /** Feature identifier: namespaces. */
+    protected static final String NAMESPACES =
+        Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
+
+    public static final String SCHEMA = 
+        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
+    
+    protected static final String DYNAMIC_VALIDATION =
+        Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
+
+    protected static final String NORMALIZE_DATA = 
+        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;
+
+    
+    
+    // property identifiers
+
+    /** Property identifier: entity manager. */
+    protected static final String ENTITY_MANAGER = 
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
+
+    /** Property identifier: error reporter. */
+    protected static final String ERROR_REPORTER = 
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
+
+    /** Property identifier: xml string. */
+    protected static final String XML_STRING = 
+        Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
+
+    /** Property identifier: symbol table. */
+    protected static final String SYMBOL_TABLE = 
+        Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
+
+    /** Property id: Grammar pool*/
+    public static final String GRAMMAR_POOL = 
+    Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
+
+    /** Property identifier: error handler. */
+    protected static final String ERROR_HANDLER = 
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
+
+    /** Property identifier: entity resolver. */
+    protected static final String ENTITY_RESOLVER = 
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
+
+
+    protected static final String VALIDATION_MANAGER =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
+    //
+    // Data
+    //
+    XMLDocumentHandler fDocumentHandler;
+
+    // components (non-configurable)
+
+    /** Symbol table. */
+    protected SymbolTable fSymbolTable;
+
+    // data
+
+    /** Components. */
+    protected Vector fComponents;
+
+
+    /** Locale. */
+    protected Locale fLocale;
+    protected XMLErrorReporter fErrorReporter;
+
+    //
+    // Constructors
+    //
+
+    /** Default Constructor. */
+    public DOMValidationConfigurationSwipedFromXerces() {
+        this(null, null);
+    } // <init>()
+
+    /** 
+     * Constructs a parser configuration using the specified symbol table. 
+     *
+     * @param symbolTable The symbol table to use.
+     */
+    public DOMValidationConfigurationSwipedFromXerces(SymbolTable symbolTable) {
+        this(symbolTable, null);
+    } // <init>(SymbolTable)
+
+    /** 
+     * Constructs a parser configuration using the specified symbol table
+     * and parent settings.
+     *
+     * @param symbolTable    The symbol table to use.
+     * @param parentSettings The parent settings.
+     */
+    public DOMValidationConfigurationSwipedFromXerces(SymbolTable symbolTable,
+                                       XMLComponentManager parentSettings) {
+        super(parentSettings);
+
+        // create storage for recognized features and properties
+        fRecognizedFeatures = new Vector();
+        fRecognizedProperties = new Vector();
+
+        // create table for features and properties
+        fFeatures = new Hashtable();
+        fProperties = new Hashtable();
+
+        // add default recognized features
+        final String[] recognizedFeatures = {
+            VALIDATION,                 
+            NAMESPACES,
+            SCHEMA,
+            DYNAMIC_VALIDATION,
+            NORMALIZE_DATA
+        };
+        addRecognizedFeatures(recognizedFeatures);
+
+        // set state for default features
+        setFeature(VALIDATION, false);
+        setFeature(SCHEMA, false);
+        setFeature(DYNAMIC_VALIDATION, false);
+        setFeature(NORMALIZE_DATA, true);
+        setFeature(NAMESPACES, true);
+
+        // add default recognized properties
+        final String[] recognizedProperties = {
+            XML_STRING,     
+            SYMBOL_TABLE,
+            ERROR_HANDLER,  
+            ENTITY_RESOLVER,
+            ERROR_REPORTER,
+            ENTITY_MANAGER,
+            VALIDATION_MANAGER,
+            GRAMMAR_POOL
+        };
+        addRecognizedProperties(recognizedProperties);
+
+        if (symbolTable == null) {
+            symbolTable = new SymbolTable();
+        }
+        fSymbolTable = symbolTable;
+
+        fComponents = new Vector();
+
+        setProperty(SYMBOL_TABLE, fSymbolTable);
+        fErrorReporter = new XMLErrorReporter();
+        setProperty(ERROR_REPORTER, fErrorReporter);
+        addComponent(fErrorReporter);
+
+        XMLEntityManager manager =  new XMLEntityManager();
+        setProperty(ENTITY_MANAGER, manager);
+        addComponent(manager);
+        
+        setProperty(VALIDATION_MANAGER, new ValidationManager());
+
+
+        // add message formatters
+        if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
+            XMLMessageFormatter xmft = new XMLMessageFormatter();
+            fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
+            fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
+        }
+
+        if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) {
+            XSMessageFormatter xmft = new XSMessageFormatter();
+            fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft);
+        }
+
+
+        // set locale
+        try {
+            setLocale(Locale.getDefault());
+        }
+        catch (XNIException e) {
+            // do nothing
+            // REVISIT: What is the right thing to do? -Ac
+        }
+
+
+    } // <init>(SymbolTable)
+
+
+    //
+    // XMLParserConfiguration methods
+    //
+
+    /**
+     * Parse an XML document.
+     * <p>
+     * The parser can use this method to instruct this configuration
+     * to begin parsing an XML document from any valid input source
+     * (a character stream, a byte stream, or a URI).
+     * <p>
+     * Parsers may not invoke this method while a parse is in progress.
+     * Once a parse is complete, the parser may then parse another XML
+     * document.
+     * <p>
+     * This method is synchronous: it will not return until parsing
+     * has ended.  If a client application wants to terminate 
+     * parsing early, it should throw an exception.
+     *
+     * @param source The input source for the top-level of the
+     *               XML document.
+     *
+     * @exception XNIException Any XNI exception, possibly wrapping 
+     *                         another exception.
+     * @exception IOException  An IO exception from the parser, possibly
+     *                         from a byte stream or character stream
+     *                         supplied by the parser.
+     */
+    public void parse(XMLInputSource inputSource) 
+        throws XNIException, IOException{
+        // no-op
+    }
+
+    /**
+     * Sets the document handler on the last component in the pipeline
+     * to receive information about the document.
+     * 
+     * @param documentHandler   The document handler.
+     */
+    public void setDocumentHandler(XMLDocumentHandler documentHandler) {
+        fDocumentHandler = documentHandler;
+    } // setDocumentHandler(XMLDocumentHandler)
+
+    /** Returns the registered document handler. */
+    public XMLDocumentHandler getDocumentHandler() {
+        return fDocumentHandler;
+    } // getDocumentHandler():XMLDocumentHandler
+
+    /**
+     * Sets the DTD handler.
+     * 
+     * @param dtdHandler The DTD handler.
+     */
+    public void setDTDHandler(XMLDTDHandler dtdHandler) {
+        //no-op
+    } // setDTDHandler(XMLDTDHandler)
+
+    /** Returns the registered DTD handler. */
+    public XMLDTDHandler getDTDHandler() {
+        return null;
+    } // getDTDHandler():XMLDTDHandler
+
+    /**
+     * Sets the DTD content model handler.
+     * 
+     * @param handler The DTD content model handler.
+     */
+    public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) {
+        //no-op
+
+    } // setDTDContentModelHandler(XMLDTDContentModelHandler)
+
+    /** Returns the registered DTD content model handler. */
+    public XMLDTDContentModelHandler getDTDContentModelHandler() {
+        return null;
+    } // getDTDContentModelHandler():XMLDTDContentModelHandler
+
+    /**
+     * Sets the resolver used to resolve external entities. The EntityResolver
+     * interface supports resolution of public and system identifiers.
+     *
+     * @param resolver The new entity resolver. Passing a null value will
+     *                 uninstall the currently installed resolver.
+     */
+    public void setEntityResolver(XMLEntityResolver resolver) {
+        if (resolver !=null) {
+            fProperties.put(ENTITY_RESOLVER, resolver);
+        }
+    } // setEntityResolver(XMLEntityResolver)
+
+    /**
+     * Return the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none
+     *         has been registered.
+     * @see #setEntityResolver
+     */
+    public XMLEntityResolver getEntityResolver() {
+        return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER);
+    } // getEntityResolver():XMLEntityResolver
+
+    /**
+     * Allow an application to register an error event handler.
+     *
+     * <p>If the application does not register an error handler, all
+     * error events reported by the SAX parser will be silently
+     * ignored; however, normal processing may not continue.  It is
+     * highly recommended that all SAX applications implement an
+     * error handler to avoid unexpected bugs.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param errorHandler The error handler.
+     * @exception java.lang.NullPointerException If the handler 
+     *            argument is null.
+     * @see #getErrorHandler
+     */
+    public void setErrorHandler(XMLErrorHandler errorHandler) {
+        if (errorHandler != null) {        
+            fProperties.put(ERROR_HANDLER, errorHandler);
+        }
+    } // setErrorHandler(XMLErrorHandler)
+
+    /**
+     * Return the current error handler.
+     *
+     * @return The current error handler, or null if none
+     *         has been registered.
+     * @see #setErrorHandler
+     */
+    public XMLErrorHandler getErrorHandler() {
+        // REVISIT: Should this be a property?
+        return (XMLErrorHandler)fProperties.get(ERROR_HANDLER);
+    } // getErrorHandler():XMLErrorHandler
+
+    /**
+     * Set the state of a feature.
+     *
+     * Set the state of any feature in a SAX2 parser.  The parser
+     * might not recognize the feature, and if it does recognize
+     * it, it might not be able to fulfill the request.
+     *
+     * @param featureId The unique identifier (URI) of the feature.
+     * @param state The requested state of the feature (true or false).
+     *
+     * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the
+     *            requested feature is not known.
+     */
+    public void setFeature(String featureId, boolean state)
+        throws XMLConfigurationException {
+
+        // save state if noone "objects"
+        super.setFeature(featureId, state);
+
+    } // setFeature(String,boolean)
+
+    /**
+     * setProperty
+     * 
+     * @param propertyId 
+     * @param value 
+     */
+    public void setProperty(String propertyId, Object value)
+        throws XMLConfigurationException {
+
+        // store value if noone "objects"
+        super.setProperty(propertyId, value);
+
+    } // setProperty(String,Object)
+
+    /**
+     * Set the locale to use for messages.
+     *
+     * @param locale The locale object to use for localization of messages.
+     *
+     * @exception XNIException Thrown if the parser does not support the
+     *                         specified locale.
+     */
+    public void setLocale(Locale locale) throws XNIException {
+        fLocale = locale;
+        fErrorReporter.setLocale(locale);
+
+    } // setLocale(Locale)
+
+    /** Returns the locale. */
+    public Locale getLocale() {
+        return fLocale;
+    } // getLocale():Locale
+
+    //
+    // Protected methods
+    //
+
+    /**
+     * reset all components before parsing
+     */
+    protected void reset() throws XNIException {
+
+        int count = fComponents.size();
+        for (int i = 0; i < count; i++) {
+            XMLComponent c = (XMLComponent) fComponents.elementAt(i);
+            c.reset(this);
+        }
+
+    } // reset()
+
+    /**
+     * Check a property. If the property is known and supported, this method
+     * simply returns. Otherwise, the appropriate exception is thrown.
+     *
+     * @param propertyId The unique identifier (URI) of the property
+     *                   being set.
+     * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the
+     *            requested feature is not known or supported.
+     */
+    protected void checkProperty(String propertyId)
+        throws XMLConfigurationException {
+
+        // special cases
+        if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
+            String property =
+                propertyId.substring(Constants.SAX_PROPERTY_PREFIX.length());
+            //
+            // http://xml.org/sax/properties/xml-string
+            // Value type: String
+            // Access: read-only
+            //   Get the literal string of characters associated with the
+            //   current event.  If the parser recognises and supports this
+            //   property but is not currently parsing text, it should return
+            //   null (this is a good way to check for availability before the
+            //   parse begins).
+            //
+            if (property.equals(Constants.XML_STRING_PROPERTY)) {
+                // REVISIT - we should probably ask xml-dev for a precise
+                // definition of what this is actually supposed to return, and
+                // in exactly which circumstances.
+                short type = XMLConfigurationException.NOT_SUPPORTED;
+                throw new XMLConfigurationException(type, propertyId);
+            }
+        }
+
+        // check property
+        super.checkProperty(propertyId);
+
+    } // checkProperty(String)
+
+
+    public void addComponent(XMLComponent component) {
+
+        // don't add a component more than once
+        if (fComponents.contains(component)) {
+            return;
+        }
+        fComponents.addElement(component);
+
+        // register component's recognized features
+        String[] recognizedFeatures = component.getRecognizedFeatures();
+        addRecognizedFeatures(recognizedFeatures);
+
+        // register component's recognized properties
+        String[] recognizedProperties = component.getRecognizedProperties();
+        addRecognizedProperties(recognizedProperties);
+
+    } // addComponent(XMLComponent)
+
+
+} // class XMLParser
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/DTM2XNI.java b/src/org/apache/xml/dtm/ref/xni2dtm/DTM2XNI.java
new file mode 100644
index 0000000..108d742
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/DTM2XNI.java
@@ -0,0 +1,622 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.*;
+import org.w3c.dom.*;
+
+import org.apache.xml.utils.NodeConsumer;
+import org.apache.xml.utils.XMLString;
+
+import org.apache.xerces.xni.*;
+import org.apache.xerces.xni.psvi.*;
+
+/**
+ * <meta name="usage" content="advanced"/>
+ * This class does a pre-order walk of the DTM tree, calling an XNI
+ * XMLDocumentHandler interface as it goes. As such, it's more like 
+ * the Visitor design pattern than like the DOM's TreeWalker.
+ */
+public class DTM2XNI 
+implements org.apache.xerces.xni.parser.XMLDocumentScanner
+{
+  /** Set true if xsi:type and xsi:schemaLocation should _not_ be serialized.
+   * (Sets them aside into annotations.)
+   * This flag is also referenced in XNI2DTM
+   * */
+  public static boolean SUPPRESS_XSI_ATTRIBUTES=true;
+
+  /** Local reference to a XMLDocumentHandler          */
+  private XMLDocumentHandler m_XMLDocumentHandler = null;
+  
+  /** Source for this TreeWalker          */
+  protected DTM m_dtm;
+  
+  /** Source for this TreeWalker          */
+  protected int m_root;
+  
+  /** Context to wrap around this TreeWalker */
+  protected java.util.Vector m_context;
+	
+  /** Buffer for chars going out to the handler. Reusable. 
+   * WARNING:  o..a..xerces.xni.XMLString and o..a..xml.utils.XNIString
+   * are *NOT* the same thing! */
+  protected org.apache.xerces.xni.XMLString m_xnistring=new org.apache.xerces.xni.XMLString();
+  
+  /** Buffer for augmentations. Reusable.
+   * WARNING: XNI _will_ add values to this; be prepared to
+   * clear and reinstantiate it every time.
+   * */
+  protected org.apache.xerces.xni.Augmentations m_augs=
+  	new org.apache.xerces.util.AugmentationsImpl();
+  
+  /** Manefest constant: Augmentation flag for structure we added, which
+   * may need to be stripped out again after validation 
+   * This flag is also referenced in XNI2DTM
+   * */
+  public static final String DTM2XNI_ADDED_STRUCTURE="Synthetic-Node-added-by-org.apache.xml.dtm.ref.xni2dtm.DTM2XNI";
+  
+  /** Manafest constant: XML Schema Instance namespace 
+   * This constant is also referenced in XNI2DTM
+   * */
+  static final String XSI_NAMESPACE="http://www.w3.org/2001/XMLSchema-instance";
+  
+  /** Manefest constant: Annotation for suppressed xsi: 
+   * This constant is also referenced in XNI2DTM
+   * */
+  public static final String SUPPRESSED_XSI="XSI-directive-suppressed-by-org.apache.xml.dtm.ref.xni2dtm.DTM2XNI";
+
+  /**
+   * Set the DTM to be traversed.
+   * 
+   * @param dtm  Document Table Model to be used.
+   */
+  public void setDTM(DTM dtm)
+  {
+    m_dtm = dtm;
+  }
+
+  /**
+   * Get the XMLDocumentHandler used for the tree walk.
+   *
+   * @return the XMLDocumentHandler used for the tree walk
+   */
+  public XMLDocumentHandler getXMLDocumentHandler()
+  {
+    return m_XMLDocumentHandler;
+  }
+  
+  /**
+   * Set the XMLDocumentHandler used for the tree walk.
+   *
+   * @param ch the XMLDocumentHandler to be the result of the tree walk.
+   */
+  public void setXMLDocumentHandler(XMLDocumentHandler ch)
+  {
+    m_XMLDocumentHandler = ch;
+  }
+
+  
+  /**
+   * Constructor.
+   * @param   XMLDocumentHandler The implemention of the
+   * XMLDocumentHandler operation (toXMLString, digest, ...)
+   */
+  public DTM2XNI()
+  {
+  }
+  
+  /**
+   * Constructor.
+   * @param   XMLDocumentHandler The implemention of the
+   * XMLDocumentHandler operation (toXMLString, digest, ...)
+   */
+  public DTM2XNI(XMLDocumentHandler handler, DTM dtm,int nodeHandle)
+  {
+  	setDocumentHandler(handler);
+    setSource(dtm,nodeHandle);
+  }
+  
+  /**
+   * Constructor.
+   * @param   XMLDocumentHandler The implemention of the
+   * XMLDocumentHandler operation (toXMLString, digest, ...)
+   */
+  public DTM2XNI(DTM dtm,int nodeHandle)
+  {
+    setSource(dtm,nodeHandle);
+  }
+  /** Set XNI listener */
+  public void setDocumentHandler(XMLDocumentHandler handler)
+  {
+    m_XMLDocumentHandler = handler;
+  }
+  
+  /** Set source to read from */
+  public void setSource(DTM dtm,int nodeHandle)
+  {
+  	m_dtm=dtm;
+  	m_root=nodeHandle;
+  }
+
+  /** Set wrapper context -- a vector of QNames, outermost first */
+  public void setContext(java.util.Vector context)
+  {
+  	m_context=context;
+  }
+  
+  /** Perform a non-recursive pre-order/post-order traversal,
+   * operating as a Visitor. startNode (preorder) and endNode
+   * (postorder) are invoked for each node as we traverse over them,
+   * with the result that the node is written out to m_XMLDocumentHandler.
+   *
+   * @param pos Nodehandle in the tree at which to start (and end) traversal --
+   * in other words, the root of the subtree to traverse over.
+   * @param context Vector of QNames to be synthesized as "wrapper" elements
+   * around this tree. It is hoped that we can phase this out when Xerces
+   * adds a context parameter to their validator.
+   * These will be tagged with an XNI annotation indicating that status, so
+   * downstream processing can strip them out again if desired.
+   *
+   * @throws TransformerException */
+  public boolean scanDocument(boolean complete) throws org.apache.xerces.xni.XNIException
+  {
+  	try
+  	{
+  		
+  	int pos=m_root;
+  	int top=pos;
+
+	// Document node wants to be marked as synthesized iff root wasn't
+	// a Doc.
+	Augmentations docaugs=null;
+	if(m_dtm.getNodeType(top)==DTM.DOCUMENT_NODE)
+	{
+		docaugs=m_augs;	
+		docaugs.clear();
+		docaugs.putItem(DTM2XNI_ADDED_STRUCTURE,DTM2XNI_ADDED_STRUCTURE);
+	}
+
+    m_XMLDocumentHandler.startDocument(null, m_dtm.getDocumentEncoding(pos),
+    	docaugs);
+
+    // Generate the synthesized context
+    // %REVIEW% Reuse one rather than recreating?
+    org.apache.xerces.xni.XMLAttributes attrs = 
+                          new org.apache.xerces.util.XMLAttributesImpl();
+    if(m_context!=null)
+    	for(int i=0, count=m_context.size();i<count;++i)
+    	{
+    		// Need to convert from Xalan QName to XNI QName.
+			org.apache.xml.utils.QName q=(org.apache.xml.utils.QName) m_context.elementAt(i);
+    		String ns=q.getNamespaceURI();
+    		if(null!=ns && ns.length()==0) ns=null;
+			org.apache.xerces.xni.QName qq=new org.apache.xerces.xni.QName(
+				q.getPrefix(), q.getLocalPart(),q.toString(),ns);
+			// Mark as synthesized ancestor nodes
+			// NOTE: Must reassert every time; could have been altered!
+			m_augs.clear();
+			m_augs.putItem(DTM2XNI_ADDED_STRUCTURE,DTM2XNI_ADDED_STRUCTURE);
+		    m_XMLDocumentHandler.startElement(qq,attrs,m_augs);
+    	}
+
+	// %REVIEW% This can undoubtedly be simplified.
+    while (DTM.NULL != pos)
+    {
+      startNode(pos);
+      int nextNode = m_dtm.getFirstChild(pos);
+      while (DTM.NULL == nextNode)
+      {
+        endNode(pos);
+
+        if ((DTM.NULL != top) && top == pos)
+          break;
+
+        nextNode = m_dtm.getNextSibling(pos);
+
+        if (DTM.NULL == nextNode)
+        {
+          pos = m_dtm.getParent(pos);
+
+          if ((DTM.NULL == pos) || ((DTM.NULL != top) && (top == pos)))
+          {
+            nextNode = DTM.NULL;
+
+            break;
+          }
+        }
+      }
+
+      pos = nextNode;
+    }
+    
+    // Generate the context
+    if(m_context!=null)
+    	for(int i=m_context.size()-1;i>=0;--i)
+    	{
+    		// Need to convert from Xalan QName to XNI QName.
+			org.apache.xml.utils.QName q=(org.apache.xml.utils.QName) m_context.elementAt(i);
+    		String ns=q.getNamespaceURI();
+    		if(null!=ns && ns.length()==0) ns=null;
+			org.apache.xerces.xni.QName qq=new org.apache.xerces.xni.QName(
+				q.getPrefix(), q.getLocalPart(),q.toString(),ns);
+			// Mark as synthesized ancestor nodes
+			// NOTE: Must reassert every time; could have been altered!
+			m_augs.clear();
+			m_augs.putItem(DTM2XNI_ADDED_STRUCTURE,DTM2XNI_ADDED_STRUCTURE);
+		    m_XMLDocumentHandler.endElement(qq,m_augs);
+    	}
+
+	// Document node needs to be marked as synthesized iff root wasn't
+	// a Doc. Note that docaugs will be left null if this test didn't 
+	// succeed earlier, which is what we want.
+	if(m_dtm.getNodeType(top)==DTM.DOCUMENT_NODE)
+	{
+		docaugs.clear();
+		docaugs.putItem(DTM2XNI_ADDED_STRUCTURE,DTM2XNI_ADDED_STRUCTURE);
+	}
+    m_XMLDocumentHandler.endDocument(docaugs);
+   
+    return true; 
+    
+  	}
+  	catch(org.xml.sax.SAXException e)
+  	{
+  		throw new org.apache.xerces.xni.XNIException(e);
+  	}
+  }
+
+  /** Flag indicating whether following text to be processed is raw text          */
+  boolean nextIsRaw = false;
+  
+  /**
+   * Partly optimized dispatch of characters from Text-style nodes.
+   * 
+   * I really didn't want to propigate XNI deep into our data structures.
+   * That means pulling the data back here to process it.
+   * Best I could do was look for lighter-weight ways to retrive it...
+   * but I'm not really delighted with this solution.
+   */
+  private final void dispatchChars(int node)
+     throws org.xml.sax.SAXException
+  {
+  	// Warning: getStringValue includes children, if this isn't a
+  	// Text-type node. 
+  	XMLString value=m_dtm.getStringValue(node);
+  	if(value instanceof org.apache.xpath.objects.XString)
+  	{
+  		// Should this be moved up to the XMLString API?
+  		// I don't think we _have_ any XMLStrings other than XStrings...
+  		org.apache.xml.utils.CharacterBlockEnumeration e=
+  			((org.apache.xpath.objects.XString)value).enumerateCharacterBlocks();
+  			
+  		do
+  		{
+			m_xnistring.setValues(
+  					e.getChars(), e.getStart(), e.getLength());
+  			m_XMLDocumentHandler.characters(m_xnistring,null);
+  		}
+  		while(e.nextElement()!=null);
+  	}
+  	else
+  	{
+  		// Fallback in case someone else implemented XMLString
+  		// and might not support the enumeration call.
+  		// Shouldn't arise, but I'm feeling paranoid this week.
+  		//
+  		// This may involve a lot of data recopying, which is why
+  		// we prefer the enumeration -- with luck, that may be able
+  		// to yield data directly from the underlying structures.
+
+  		String s=value.toString();
+  		char[] ch=s.toCharArray();
+		m_xnistring.setValues(ch, 0, ch.length);
+		m_XMLDocumentHandler.characters(m_xnistring,null);
+  	}
+  }
+
+  /**
+   * Start processing given node
+   * 
+   * %BUG% We probably need to perform namespace normalization. 
+   * don't we (add declarations, add/change prefixes)... DOM's algorithm?
+   * (Adapt from Xerces DOMNormalizer.namespaceFixUp()?)
+   *
+   * @param node Node to process
+   *
+   * @throws org.xml.sax.SAXException
+   */
+  protected void startNode(int node) throws org.xml.sax.SAXException
+  {
+    switch (m_dtm.getNodeType(node))
+    {
+    case DTM.COMMENT_NODE :
+    {
+      XMLString data = m_dtm.getStringValue(node);
+
+  		// This may involve a lot of data recopying, which is why
+  		// we prefer the enumeration for character content...
+  		// unfortunately, a single comment does need to be a single
+  		// event. Might still want to try the enum first and only fall
+  		// back on concatenation if that says multiple blocks exist...?
+  		// %REVIEW% %OPT%
+  		String s=data.toString();
+  		char[] ch=s.toCharArray();
+  		m_xnistring.setValues(ch, 0, ch.length);
+		m_XMLDocumentHandler.comment(m_xnistring,null);
+    }
+    break;
+    case DTM.DOCUMENT_FRAGMENT_NODE :
+      // ??;
+      break;
+    case DTM.DOCUMENT_NODE :
+      // already dealt with in traverse().
+      break;
+    case DTM.ELEMENT_NODE :
+      // %REVIEW% Reuse one rather than recreating?
+      org.apache.xerces.xni.XMLAttributes attrs = 
+                            new org.apache.xerces.util.XMLAttributesImpl();
+
+	  // Note that this needs to scan the namespaces declared ON THIS NODE,
+	  // *not* the ones inherited.
+      for (int nsn = m_dtm.getFirstNamespaceNode(node, false); DTM.NULL != nsn;
+           nsn = m_dtm.getNextNamespaceNode(node, nsn, false))
+      {
+        String nsprefix = m_dtm.getLocalName(nsn); //xmlns:whatever
+        	
+        m_XMLDocumentHandler.startPrefixMapping(nsprefix, m_dtm.getNodeValue(nsn),null);
+
+		// Also generate as an attr?
+	    String ans = m_dtm.getNamespaceURI(nsn); // %REVIEW% Should always be NS NS.
+        org.apache.xerces.xni.QName aqq=new org.apache.xerces.xni.QName(
+				m_dtm.getPrefix(nsn), nsprefix,
+				m_dtm.getNodeName(nsn),ans);
+        int index=attrs.addAttribute(aqq, 
+                           "CDATA", 
+                           m_dtm.getNodeValue(nsn));
+      }
+
+      boolean xniTypeSeen=false;   
+      for (int i = m_dtm.getFirstAttribute(node); 
+           i != m_dtm.NULL; 
+           i = m_dtm.getNextAttribute(i))
+      {
+	    String ans = m_dtm.getNamespaceURI(i);
+        String aln=m_dtm.getLocalName(i);
+
+		// NOTE: Must reassert every time; could have been altered!
+		// %REVIEW% May be able to just pass null, if we don't wind up
+		// needing to route xsi: data through this channel.
+		m_augs.clear();
+      	
+        if(null!=ans && ans.length()==0)
+          ans = null; // Safety net
+        else if(XSI_NAMESPACE.equals(ans) && aln.equals("type"))
+          xniTypeSeen=true; // No need to use pass-through assertion below
+        org.apache.xerces.xni.QName aqq=new org.apache.xerces.xni.QName(
+				m_dtm.getPrefix(i), aln,
+				m_dtm.getNodeName(i),ans);
+
+		// %REVIEW% Most recent advice I've gotten from Scott is that
+		// the XPath folks do _NOT_ expect xsi:type and xsi:*schemaLocation
+		// appearing in the fragment to be honored. Very reasonably, the
+		// folks developing the Schema validator say "That's not _our_
+		// behavior"... So the only way to do this is to suppress the
+		// attributes on this end and -- presumably -- recreate them on 
+		// the other end.
+		//
+		// Changing their namespace isn't sufficient; we really need to
+		// move them into a separate data channel -- eg annotations.
+		//
+		// All right, everyone, in chorus: "KLUGE!" If the user went to the
+		// trouble of building an xsi: directive into their document fragment,
+		// shouldn't we respect it? Easier _AND_ more reasonable...
+      	if(SUPPRESS_XSI_ATTRIBUTES && XSI_NAMESPACE.equals(ans))
+      	{
+      		// %REVIEW% whether this test is necessary/sufficient
+      		if("type".equals(aln) || 
+      			"schemaLocation".equals(aln) ||
+      			"noNamespaceSchemaLocation".equals(aln) )
+      			{
+      				// Side channel: Pass these as Annotation rather than
+      				// Attribute (so they aren't visible to the validator),
+      				// and reconstruct attrs in XNI2DTM.
+      				//
+      				// Architecture based on Groucho Marx's explanation
+      				// of medical practice in _Horse_Feathers_
+      				java.util.Vector v=(java.util.Vector)m_augs.getItem(SUPPRESSED_XSI);
+      				if(v==null) v=new java.util.Vector();
+      				Object[] triplet= {aqq,"CDATA",m_dtm.getNodeValue(i)};
+      				v.addElement(triplet);
+      				m_augs.putItem(SUPPRESSED_XSI,v);
+      				continue;
+      			}
+      	}
+      	else
+      		attrs.addAttribute(aqq, "CDATA", m_dtm.getNodeValue(i));
+      }
+      
+      // The business of trying to force xni:type attributes
+      // into the validation stream has been taken out of the
+      // XSLT2 spec, at least for now. I'm happy; it was a mess,
+      // even with the use of annotations to strip these out again.
+
+      String ns = m_dtm.getNamespaceURI(node);
+      if(null!=ns && ns.length()==0)
+        ns = null;
+      org.apache.xerces.xni.QName qq=new org.apache.xerces.xni.QName(
+				m_dtm.getPrefix(node), m_dtm.getLocalName(node),
+				m_dtm.getNodeName(node),ns);
+      m_XMLDocumentHandler.startElement(qq,attrs,m_augs);
+      break;
+    case DTM.PROCESSING_INSTRUCTION_NODE :
+    {
+      String name = m_dtm.getNodeName(node);
+
+      // String data = pi.getData();
+
+   	  // No special handling needed here; we can let the xslt-next-is-raw
+   	  // pass through directly rather than having to convert it. 
+   	  // See discussion under TEXT_NODE.
+   	  //
+      // if (name.equals("xslt-next-is-raw"))
+      // {
+      //   nextIsRaw = true;
+      // }
+      // else
+      {
+  		// This may involve a lot of data recopying, which is why
+  		// we prefer the enumeration for character content...
+  		// unfortunately, a single comment does need to be a single
+  		// event. Might still want to try the enum first and only fall
+  		// back on concatenation if that says multiple blocks exist.
+  		// %REVIEW% %OPT%
+  		String s=m_dtm.getNodeValue(node);
+  		char[] ch=s.toCharArray();
+  		m_xnistring.setValues(ch, 0, ch.length);
+        m_XMLDocumentHandler.processingInstruction(name,m_xnistring,null);
+      }
+    }
+    break;
+    case DTM.CDATA_SECTION_NODE :
+    {
+      m_XMLDocumentHandler.startCDATA(null);
+      dispatchChars(node);
+      m_XMLDocumentHandler.endCDATA(null);
+    }
+    break;
+    case DTM.TEXT_NODE :
+    {
+   	  // No special handling needed here; we can let the xslt-next-is-raw
+   	  // pass through directly rather than having to convert it to a
+   	  // javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING and
+   	  // javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING pair, since
+   	  // (at this time) we do not intend to drive a serializer directly
+   	  // from an XNI stream. That may change in the future, though.
+      // if (nextIsRaw)
+      // {
+      //  nextIsRaw = false;
+	  //  m_XMLDocumentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
+      //  dispatachChars(node);
+      //  m_XMLDocumentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, "");
+      // }
+      // else
+      {
+        dispatchChars(node);
+      }
+    }
+    break;
+    case DTM.ENTITY_REFERENCE_NODE :
+		break;      // Should never exist in a DTM.	
+    default :
+    }
+  }
+
+  /**
+   * End processing of given node 
+   *
+   *
+   * @param node Node we just finished processing
+   *
+   * @throws org.xml.sax.SAXException
+   */
+  protected void endNode(int node) throws org.xml.sax.SAXException
+  {
+
+    switch (m_dtm.getNodeType(node))
+    {
+    case DTM.DOCUMENT_NODE :
+		// Dealt with in traverse()
+      break;
+    case DTM.ELEMENT_NODE :
+      String ns = m_dtm.getNamespaceURI(node);
+      if(null!=ns && ns.length()==0)
+        ns = null;
+      org.apache.xerces.xni.QName qq=new org.apache.xerces.xni.QName(
+				m_dtm.getPrefix(node), m_dtm.getLocalName(node),
+				m_dtm.getNodeName(node),ns);
+      m_XMLDocumentHandler.endElement(qq,null);
+
+      for (int nsn = m_dtm.getFirstNamespaceNode(node, false); DTM.NULL != nsn;
+           nsn = m_dtm.getNextNamespaceNode(node, nsn, false))
+      {
+        // String prefix = m_dtm.getPrefix(nsn);
+        String prefix = m_dtm.getNodeNameX(nsn);
+        m_augs.clear();
+        m_augs.putItem(DTM2XNI_ADDED_STRUCTURE,DTM2XNI_ADDED_STRUCTURE);
+        m_XMLDocumentHandler.endPrefixMapping(prefix,m_augs);
+      }
+      break;
+    case DTM.CDATA_SECTION_NODE :
+      break;
+    case DTM.ENTITY_REFERENCE_NODE :
+		break;      // Should never exist in a DTM.	
+    default :
+	    break;
+    }
+  }
+  
+
+	// Required for compliance with XNI XMLDocumentScanner API,
+	// ignored here. I suppose we could use it to set systemID and such...
+	public void setInputSource(org.apache.xerces.xni.parser.XMLInputSource inputSource)
+                    throws java.io.IOException
+	{
+		// No-op.
+	}
+}  //DTM2XNI
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/DTM_XSequence.java b/src/org/apache/xml/dtm/ref/xni2dtm/DTM_XSequence.java
new file mode 100644
index 0000000..456d530
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/DTM_XSequence.java
@@ -0,0 +1,195 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.DTMSequence;
+
+/** This class provides an API representation for the XPath 2 Data Model's "Sequences"
+ * -- which are the basic representation for typed values. Only built-in types, 
+ * types derived from built-ins, and sets thereof are returned directly by the XPath2
+ * DM; complex schema-types must be accessed through the document tree.
+ * 
+ * %REVIEW% Should we have a more compact empty-sequence? (Probably not worth
+ * the effort, since XNI2DTM will use a stored instance.)
+ * */
+public class DTM_XSequence 
+implements DTMSequence
+{
+  Object[] values;
+  
+  // We currently expect all elements in schema-produced sequencs to have
+  // the same type. This may need to be enhanced at some point in the future.
+  XPath2Type type;
+
+  /** Create a sequence.
+   * 
+   * @param value Object representation of the primitive value. May be array.
+   * @param type Datatype being represented. May be list-of type.
+   * */
+  public DTM_XSequence(Object value,XPath2Type type)
+  {   
+    // If it's a list-of type, we want to unwrap that and resport
+    // the type of the individual element...
+
+    XPath2Type itemType=type.getItemType();
+    
+    if(itemType==null)
+    {
+      // Creating the array is a bit wasteful. Special-case this?
+      this.values=new Object[1];
+      this.values[0]=value;
+      this.type=type;
+    }
+    else
+    {
+      this.values=(Object[])value;
+      this.type=itemType;
+    }
+  }
+  
+  /** @return the number of members in this sequence. */
+  public int getLength()
+  {
+    return values.length;
+  }
+  
+  /** Retrieve the value for this member of the sequence. Since values may be
+   * a heterogenous mix, and their type may not be known until they're examined,
+   * they're returned as Objects. This is storage-inefficient if the value(s)
+   * is/are builtins that map to Java primitives. Tough.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the specified value
+   * @throws exception if index <0 or >=length   
+   * */
+  public Object getValue(int index)
+  {
+    return values[index];
+  }
+  
+  /** Retrieve the datatype namespace URI for this member of the sequence.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the namespace for the specified value's type
+   * @throws exception if index <0 or >=length   
+   * */
+  public String getTypeNS(int index)
+  {
+    return type.getTargetNamespace();
+  }
+  
+  /** Retrieve the datatype namespace URI for this member of the sequence.
+   * 
+   * %REVIEW% Do we really need type -- 
+   * or can we just tell folks to do instanceOf on the Java value objects?  
+   * 
+   * @param index 0-based index into the sequence.
+   * @return the localname of the specified value's type
+   * @throws exception if index <0 or >=length   
+   * */
+  public String getTypeLocalName(int index)
+  {
+    return type.getTypeName();
+  }
+  
+  /** Ask whether this member's datatype equals or is derived from a specified
+   * schema NSURI/localname pair.
+   * 
+   * @param index 0-based index into the sequence.
+   * @return true if the type is an instance of this schema datatype,
+   * false if it isn't.
+   * @throws exception if index <0 or >=length   
+   * */
+  public boolean isSchemaType(int index, String namespace, String localname)
+  {
+    return type.derivedFrom(namespace,localname);
+  }
+  
+  /** %REVIEW% Format not yet firmly settled. Primarily for debugging purposes!
+   * */
+  public String toString()
+  {
+    StringBuffer b=new StringBuffer("Sequence[");
+    String start="";
+    
+    for(int i=0;i<values.length;++i)
+    {
+      b.append(start)
+          .append(type.getTargetNamespace()).append(':').append(type.getTypeName())
+          .append(" = ");
+          
+      if(values[i] instanceof int[])
+      {
+      	int[] v=(int[])values[i];
+      	b.append('[');
+      	if(v.length>0)
+      		b.append(v[0]);
+      	for(int j=1;j<v.length;++j)
+	      	b.append(',').append(v[j]);
+      	b.append(']');
+      }
+      else
+        b.append(values[i]);
+        
+      if(values[i]!=null)
+          b.append(" {"+values[i].getClass().getName()+"}");
+      start=", ";
+    }
+    return b.append(']').toString();
+  }
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/ElemImportSchema.java b/src/org/apache/xml/dtm/ref/xni2dtm/ElemImportSchema.java
new file mode 100644
index 0000000..a6b3910
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/ElemImportSchema.java
@@ -0,0 +1,87 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.w3c.dom.Node;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.ref.DTMDefaultBase;
+import org.apache.xml.dtm.ref.DTMNodeProxy;
+import org.apache.xml.dtm.ref.xni2dtm.XNI2DTM;
+import org.apache.xml.dtm.ref.xni2dtm.DTM2XNI;
+import org.apache.xpath.XPathContext;
+import javax.xml.transform.URIResolver;
+
+/** Temporary extension function, prototyping proposed XSLT2
+ * &lt;xsl:import-schema [namespace="uri-reference"] [schema-location="uri-reference"]/&gt;
+ * 
+ * Per xslt20.30apr02.html#import-schema:
+ * 
+ *  The xsl:import-schema declaration is used to identify schema components (that is,
+ *  definitions of types) which need to be available statically, that is, before any source
+ *  document is available. Every type name used statically within the stylesheet (including
+ *  type names used within XPath expressions) must be defined in an imported schema.
+ *  The declaration imports the element and attribute declarations and type definitions
+ *  from the schema, and maps them to types in the XPath data model according to rules
+ *  defined in [].
+ *
+ *      Ed. Note: Whether or not the locally declared elements and attributes of a
+ *      schema are imported is an open issue.
+ *
+ *  The namespace and schema-location attributes are both optional. At least one of them
+ *  must be present, and it is permissible to supply both.
+ *
+ *  The namespace attribute indicates that a schema for the given namespace is required
+ *  by the stylesheet. This information may be enough on its own to enable an
+ *  implementation to locate the required schema components.
+ *
+ *  The schema-location attribute gives the URI of a location where a schema document
+ *  or other resource containing the required definitions may be found. An XSLT
+ *  processor must have the capability to process an XML Schema that exists at this
+ *  location in the form of a source XML document; implementations may also be able to
+ *  access equivalent information held in other forms, for example a compiled XML
+ *  Schema, or type information expressed using some other schema language.
+ *
+ *  [ERR016] It is a static error if the processor is not able to locate a schema using the
+ *  namespace and/or schema-location attributes , or if the document that it locates is
+ *  neither a valid XML Schema nor any other resource that the implementation can
+ *  process.
+ *
+ *  [ERR017] It is a static error if two xsl:import-schema declarations yield multiple
+ *  definitions for the same named type, even if the definitions are consistent with each
+ *  other.
+ *
+ *  The use of a namespace in an xsl:import-schema declaration does not by itself make
+ *  the namespace available for use in the stylesheet. If names from the namespace are
+ *  used within the stylesheet, a prefix must be associated with the namespace by means
+ *  of a namespace declaration, in the normal way.
+ * 
+ *  The precise way in which an implementation uses the namespace and/or
+ *  schema-location attributes to locate schema definitions is implementation-defined.
+ * 
+ * */
+public class ElemImportSchema {
+	private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook
+	
+	public static String eval(org.apache.xalan.extensions.ExpressionContext expressionContext,
+		String schemaNamespace, String schemaLocation) 
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext();
+
+		// Looking up a schema by namespace is still an ill-defined operation
+		// at best, pending the Semantic Web (which as far as I know is still
+		// naught but a vision held by Tim Berners-Lee). It will probably have
+		// to be handled by a plug-in resolver of some kind until that settles.
+		// For now, the simplest answer seems to be to make whoever does entity
+		// resolution deal with it, calling the namespace a public ID.
+		// %REVIEW%
+		xctxt.addInScopeSchemaDefinitions(schemaNamespace,schemaLocation);
+		
+		return ""; // Bogus, just required because this is temporarily a function
+	}
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/FuncData.java b/src/org/apache/xml/dtm/ref/xni2dtm/FuncData.java
new file mode 100644
index 0000000..073457f
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/FuncData.java
@@ -0,0 +1,41 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMSequence;
+import org.apache.xpath.XPathContext;
+import org.w3c.dom.Node;
+
+/** Temporary extension function, prototyping proposed XPath2 xs:data()
+ * function. Returns a Java Object(which will probably become an XObject for
+ * a "non-XSLT type".
+ * 
+ * This may be moved back to XSLT/XQuery, or may be folded all the way down
+ * as an operation implied by low-level expression syntax, depending on what
+ * happens in the Working Group.
+ * 
+ * If the value passed in is NOT a Node, we're supposed to return the
+ * architected Error value. Currently, we assume it is a node.
+ * */
+public class FuncData {
+	private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook
+	private static final boolean JJK_DUMMY_CODE=true; // debugging hook
+	
+	
+	public static DTMSequence data(org.apache.xalan.extensions.ExpressionContext context,
+		Node root) 
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)context).getXPathContext();
+		
+    	int sourceHandle=xctxt.getDTMHandleFromNode(root);
+    	DTM sourceDTM=xctxt.getDTM(sourceHandle);
+
+		return sourceDTM.getTypedValue(sourceHandle);
+	}	
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/FuncInstanceOf.java b/src/org/apache/xml/dtm/ref/xni2dtm/FuncInstanceOf.java
new file mode 100644
index 0000000..50e217a
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/FuncInstanceOf.java
@@ -0,0 +1,63 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.DTM;
+import org.apache.xpath.XPathContext;
+import org.w3c.dom.Node;
+
+/** Temporary extension function, prototyping XSLT 2.0 type matching.
+ * */
+public class FuncInstanceOf {
+	private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook
+	private static final boolean JJK_DUMMY_CODE=true; // debugging hook
+	
+	
+	public static boolean eval(org.apache.xalan.extensions.ExpressionContext expressionContext,
+		Node root, String typeQName) 
+		throws javax.xml.transform.TransformerException
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext();
+		
+    	int sourceHandle=xctxt.getDTMHandleFromNode(root);
+    	DTM sourceDTM=xctxt.getDTM(sourceHandle);
+
+		DTM2XNI d2x=new DTM2XNI(sourceDTM,sourceHandle);
+
+
+		// Need to resolve typeQName
+		org.apache.xml.utils.PrefixResolver pfxresolver=xctxt.getNamespaceContext();
+		org.apache.xml.utils.QName qn=new org.apache.xml.utils.QName(typeQName,pfxresolver);
+		
+		return sourceDTM.isNodeSchemaType(
+			sourceHandle,qn.getNamespaceURI(),qn.getLocalName())
+			;
+	}
+	
+	public static boolean eval(org.apache.xalan.extensions.ExpressionContext expressionContext,
+		Node root, String typeNamespace, String typeName) 
+		throws javax.xml.transform.TransformerException
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext();
+		
+    	int sourceHandle=xctxt.getDTMHandleFromNode(root);
+    	DTM sourceDTM=xctxt.getDTM(sourceHandle);
+
+		DTM2XNI d2x=new DTM2XNI(sourceDTM,sourceHandle);
+
+		return sourceDTM.isNodeSchemaType(
+			sourceHandle,typeNamespace,typeName)
+			;
+	}
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/FuncTreatAs.java b/src/org/apache/xml/dtm/ref/xni2dtm/FuncTreatAs.java
new file mode 100644
index 0000000..e218aae
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/FuncTreatAs.java
@@ -0,0 +1,75 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xml.dtm.DTM;
+import org.apache.xpath.XPathContext;
+import org.w3c.dom.Node;
+
+/** Temporary extension function, prototyping proposed XPath2 "treat as"
+ * and "assert as" operators. Tests whether an expression is of the
+ * specified type, returning the expression's value if so and the 
+ * architected Error value otherwise. 
+ * 
+ * There's a bunch of stuff left open in this prototype, since to do it
+ * right we need to tie in to static typing of expressions (not yet
+ * supported, and the only place where treat/assert differ), and we need
+ * typed general expressions (also not yet supported; all we have is
+ * typed nodes in the source documents or validated RTFs).
+ * 
+ * I'm also not sure what the "error value" will be. For now I'm settling
+ * for announcing an error and returning null.
+ * */
+public class FuncTreatAs {
+	private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook
+	private static final boolean JJK_DUMMY_CODE=true; // debugging hook
+	
+	
+	public static Node eval(org.apache.xalan.extensions.ExpressionContext expressionContext,
+		Node root, String typeQName) 
+		throws javax.xml.transform.TransformerException
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext();
+		
+    	int sourceHandle=xctxt.getDTMHandleFromNode(root);
+    	DTM sourceDTM=xctxt.getDTM(sourceHandle);
+
+		DTM2XNI d2x=new DTM2XNI(sourceDTM,sourceHandle);
+
+
+		// Need to resolve typeQName
+		org.apache.xml.utils.PrefixResolver pfxresolver=xctxt.getNamespaceContext();
+		org.apache.xml.utils.QName qn=new org.apache.xml.utils.QName(typeQName,pfxresolver);
+		
+		if(sourceDTM.isNodeSchemaType(
+			sourceHandle,qn.getNamespaceURI(),qn.getLocalName())
+			)
+		{
+			return root;
+		}
+		else
+		{
+		    // %REVIEW% Should be routed to the JAXP error listener, presumably.
+		    // What's the easiest way to get that from here?
+		    javax.xml.transform.ErrorListener handler=xctxt.getErrorListener();
+		    javax.xml.transform.TransformerException err=
+				new javax.xml.transform.TransformerException(
+				"Type assertion failed; expected "+
+				qn.getNamespaceURI()+":"+qn.getLocalName()+" but found "+
+				sourceDTM.getSchemaTypeNamespace(sourceHandle)+":"+
+				sourceDTM.getSchemaTypeName(sourceHandle) );
+			if(handler==null)
+				throw err;
+			else
+				handler.error(err);
+				
+			return null; // in case handler said "proceed normally".
+		}
+	}
+	
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/FuncValidate.java b/src/org/apache/xml/dtm/ref/xni2dtm/FuncValidate.java
new file mode 100644
index 0000000..bfded98
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/FuncValidate.java
@@ -0,0 +1,185 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.w3c.dom.Node;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.ref.DTMDefaultBase;
+import org.apache.xml.dtm.ref.DTMNodeProxy;
+import org.apache.xml.dtm.ref.xni2dtm.XNI2DTM;
+import org.apache.xml.dtm.ref.xni2dtm.DTM2XNI;
+import org.apache.xpath.XPathContext;
+
+/** Temporary extension function, prototyping proposed XPath2 FuncValidate.
+ * 
+ * This may be moved back to XSLT/XQuery, or may be folded all the way down
+ * as an operation implied by low-level expression syntax, depending on what
+ * happens in the Working Group.
+ * 
+ * %REVIEW% Current code validates only a single root element. If we want more,
+ * we can do it but it'll take a bit more coding.
+ * */
+public class FuncValidate {
+	private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook
+	private static final boolean JJK_DUMMY_CODE=true; // debugging hook
+	
+	
+	public static Node eval(org.apache.xalan.extensions.ExpressionContext context,
+		Node root) 
+	{
+		return eval(context,root,null);
+	}
+	public static Node eval(org.apache.xalan.extensions.ExpressionContext expressionContext,
+		Node root, String contextPath) 
+	{
+		// This happens to work in current code. It isn't really
+		// documented. Future versions expect to expose it more elegantly,
+		// according to Don Leslie. But since this extension is just
+		// temporary, let's use the cheat... We know it's going to be a
+		// particular inner class, which has an accessor to retrieve its
+		// associated XPathContext, so we reach in and ask it to reach back.
+		XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext();
+		
+    	int sourceHandle=xctxt.getDTMHandleFromNode(root);
+    	DTM sourceDTM=xctxt.getDTM(sourceHandle);
+
+		DTM2XNI d2x=new DTM2XNI(sourceDTM,sourceHandle);
+
+		// %REVIEW% Still need to do something with contextPath.
+		// d2x is set up to synthesize a wrapper and then discard it again --
+		// BUT this fails when one of the synthesized elements has attr requirements,
+		// as Xerces apparently optimizes by not validating kids if the start-tag
+		// isn't valid.
+		// 
+		// A better answer would be to set the validator's context;
+		// Xerces agrees that this is a desirable feature but may not have
+		// implemented it yet.
+		if(contextPath!=null)
+		{
+			java.util.Vector d2xContext=new java.util.Vector();
+			// xctxt not available to extensions?
+			org.apache.xml.utils.PrefixResolver pfxresolver=xctxt.getNamespaceContext();
+			
+			java.util.StringTokenizer e=new java.util.StringTokenizer(contextPath,"/");
+			while(e.hasMoreElements())
+			{
+				String name=(String)e.nextElement();
+				org.apache.xml.utils.QName qn=new org.apache.xml.utils.QName(name,pfxresolver);
+				d2xContext.addElement(qn);
+			}
+			d2x.setContext(d2xContext);
+		}		
+
+		// VALIDATION GOES HERE!
+		// Sandy Gao recommends "create a customized parser configuration,
+		// which contains an XNI event source, a validator, and (optionally)
+		// a document handler." See "pipelines" in the XNI docs.
+		// I don't really grok that yet, so this is a SWAG based on what
+		// Elena Litani did for the DOM revalidator.
+		//
+		// If we need to suppress explicit xsi:*schemaLocation directives, recommended 
+		// kluge is to install a entity-resolver into the pipe which delivered
+		// a schema with appropriate targetNamespae and no details (or just empty???)
+		//
+		// If we need to suppress explicit xsi:type directives -- Xerces developers
+		// agree with me that this is Inherently Stupid. Solution would be to pass
+		// those through a secondary channel, eg by turning them into custom
+		// annotations until they get back to XNI.
+		XNISource xsrc;
+		if(JJK_DISABLE_VALIDATOR)
+			xsrc=new XNISource(d2x,null); // Test: Just flow thru
+		else
+		{
+			// ISSUE: Do we need to explicitly normalize namespaces?
+			
+			/* Adapted from Xerces DOMRevalidator.
+				Probably shouldn't be using this class, but
+				I haven't yet gotten the Xerces team to give me
+				a real stand-alone example I could model this on.
+				
+				I'm also REALLY not convinced this is a typical XNI setup;
+				I'm surprised I have to muck directly with the validator
+				rather than setting up a configuration that encapsulates
+				the dataflow more completely. (On the other hand, I'm also
+				surpised that Configuration doesn't seem to implement
+				DocumentSource.
+				*/
+			DOMValidationConfigurationSwipedFromXerces xnipipe
+				=new DOMValidationConfigurationSwipedFromXerces(null);
+			xnipipe.setFeature(DOMValidationConfigurationSwipedFromXerces.VALIDATION,true);
+			xnipipe.setFeature(DOMValidationConfigurationSwipedFromXerces.SCHEMA,true);
+			org.apache.xerces.impl.xs.XMLSchemaValidator validator
+				=new org.apache.xerces.impl.xs.XMLSchemaValidator();
+			xnipipe.addComponent(validator); // so config's reset() hits it
+			
+			if(JJK_DUMMY_CODE)
+			{
+				/* %REVIEW% Code in this section is preliminary/bogus,
+				   for debugging only */
+				
+				/* %ISSUE% 1) Is there such a thing as a base URI for this fragment?
+					%BUG% It is very unclear that this fragment has a real base URI.
+					Also, note that this call fails for RTFDTMs.
+					
+					(We may in fact need to set this otherwise to prevent
+					xsi:schemaLocation from succeeding, unless we can tell
+					Xerces not to honor that directive.. or filter it out
+					in DTM2XNI, ugh. For now leave this unset to expose
+					failure to reference the explicitly loaded GrammarPool.)
+					*/
+				//validator.setBaseURI(sourceDTM.getDocumentBaseURI());				
+				
+				/* %ISSUE% 2) Do we need to track mid-stream changes by issuing
+					entity/locator information into the stream?
+					%BUG% It is very unclear that this fragment has a real base URI.
+					Also, we don't actually record that data node-by-node unless
+					tooling support is turned on... and even then I'm not sure
+					this is retained after a layer or two of RTFs.
+				*/
+				// No.
+				
+				/* %ISSUE% 3) XPath2 says schema location comes from the XPath context,
+					*not* from the document. Need to assert this via the
+					schemaLocation property, or preparse into a Grammar Pool
+					and use that. (I expect the latter since other parts of
+					XPath2/XQuery/XSLT2 also want to muck with schemas.)
+					
+					%TODO%: Need to add that to the XPathContext and
+					Xalan startup?
+				*/
+				// Experimental, force it in manually just to see what happens
+				xnipipe.setProperty(xnipipe.GRAMMAR_POOL,
+					xctxt.getInScopeSchemaDefinitions().getGrammarPool());
+							
+				/* %ISSUE% 5) NOTE that we're making no effort to retain existing
+					type info (per latest XPath data I've seen). If we were,
+					we get into ugly issues w/r/t having to retain type on
+					Literal Result Elements in the stylesheet, plus questions
+					about what (if anything) happens when an LRE has
+					an xsi:type. The XQUERY team is still flailing on this topic.
+				*/
+			}
+			
+			
+			d2x.setDocumentHandler(validator);
+			
+			// Wrap up the pipeline for our use.
+			// There ought to be a way to avoid passing all these parts...
+			xsrc=new XNISource(d2x,xnipipe,validator,null);
+		}
+		
+		// %REVIEW% %BUG%
+		// I don't think we can make this incremental, attractive
+		// as that thought might be -- the source DTM might be an RTF and
+		// might Go Away. We probably _should_ make it an RTF DTM, but those
+		// currently aren't supported for XNI.
+		DTM newDTM=xctxt.getDTM(xsrc,
+			true, // unique
+			null, // whitespace filter
+			false, // incremental -- not supported at this writing
+			false // doIndexing -- open to debate
+			);
+		
+		return newDTM.getNode(newDTM.getDocument());
+	}
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/NamespaceSupportAtDTMNode.java b/src/org/apache/xml/dtm/ref/xni2dtm/NamespaceSupportAtDTMNode.java
new file mode 100644
index 0000000..22acb46
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/NamespaceSupportAtDTMNode.java
@@ -0,0 +1,322 @@
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.xml.sax.helpers.NamespaceSupport;
+import java.util.Enumeration;
+import org.apache.xml.dtm.*;
+
+
+/** Perform SAX-style lookup of namespace information in the context of a
+ * DTM node. Written as part of the glue for XNI2DTM and XPath2Type, but
+ * may be useful elsewhere. Unclear which package it should live in.
+ * */
+public class NamespaceSupportAtDTMNode extends NamespaceSupport {
+	DTM m_dtm;
+	int m_nodeHandle;
+
+	/**
+	 * Constructor for NamespaceContextAtDTMNode
+	 */
+	public NamespaceSupportAtDTMNode() {
+		throw new UnsupportedOperationException("not supported in this class");
+	}
+
+	/**
+	 * Constructor for NamespaceContextAtDTMNode
+	 */
+	public NamespaceSupportAtDTMNode(DTM dtm,int nodeHandle) {
+		m_dtm=dtm;
+		m_nodeHandle=nodeHandle;
+	}
+
+    public boolean declarePrefix (String prefix, String uri) {
+		throw new UnsupportedOperationException("not supported in this class");
+	}
+	/* No-op in this instantiation */
+    public void pushContext ()
+    {
+    }
+	/* No-op in this instantiation */
+    public void popContext ()
+    {
+    }
+	/* No-op in this instantiation */
+    public void reset ()    
+    {
+    }
+    
+    /**
+     * Return an enumeration of all prefixes declared in this context.
+     *
+     * <p>The empty (default) prefix will be included in this 
+     * enumeration; note that this behaviour differs from that of
+     * {@link #getPrefix} and {@link #getPrefixes}.</p>
+     *
+     * @return An enumeration of all prefixes declared in this
+     *         context.
+     * @see #getPrefixes
+     * @see #getURI
+     */
+    public Enumeration getDeclaredPrefixes ()
+    {
+    	return new Enumeration()
+    	{
+    		int nshandle=m_dtm.getFirstNamespaceNode(
+				m_nodeHandle,true);
+
+			public boolean hasMoreElements()
+			{
+				return nshandle!=DTM.NULL;
+			}
+			public Object nextElement()
+			{
+				if(nshandle==DTM.NULL)
+					return null;
+				String prefix=m_dtm.getLocalName(nshandle);
+	    		nshandle=m_dtm.getNextNamespaceNode(
+					m_nodeHandle,nshandle,true);
+				return prefix;
+			}
+		};
+    }
+    
+    
+    /**
+     * Return one of the prefixes mapped to a Namespace URI.
+     *
+     * <p>If more than one prefix is currently mapped to the same
+     * URI, this method will make an arbitrary selection; if you
+     * want all of the prefixes, use the {@link #getPrefixes}
+     * method instead.</p>
+     *
+     * <p><strong>Note:</strong> this will never return the empty (default) prefix;
+     * to check for a default prefix, use the {@link #getURI getURI}
+     * method with an argument of "".</p>
+     *
+     * @param uri The Namespace URI.
+     * @param isAttribute true if this prefix is for an attribute
+     *        (and the default Namespace is not allowed).
+     * @return One of the prefixes currently mapped to the URI supplied,
+     *         or null if none is mapped or if the URI is assigned to
+     *         the default Namespace.
+     * @see #getPrefixes(java.lang.String)
+     * @see #getURI
+     */
+    public String getPrefix (String uri)
+    {
+    	if(uri==null)
+    		uri="";
+    		
+   		int nshandle=m_dtm.getFirstNamespaceNode(
+			m_nodeHandle,true);
+		while(nshandle!=DTM.NULL)
+		{
+			if(uri.equals(m_dtm.getNamespaceURI(nshandle)))
+			{
+				String prefix=m_dtm.getLocalName(nshandle);
+				if(prefix!=null && !prefix.equals(""))
+					return prefix;
+			}
+    		nshandle=m_dtm.getNextNamespaceNode(
+				m_nodeHandle,nshandle,true);
+		}
+		return null;
+    }
+    
+    /**
+     * Look up a prefix and get the currently-mapped Namespace URI.
+     *
+     * <p>This method looks up the prefix in the current context.
+     * Use the empty string ("") for the default Namespace.</p>
+     *
+     * @param prefix The prefix to look up.
+     * @return The associated Namespace URI, or null if the prefix
+     *         is undeclared in this context.
+     * @see #getPrefix
+     * @see #getPrefixes
+     */
+    public String getURI (String prefix)
+    {
+    	if(prefix==null)
+    		prefix="";
+    		
+   		int nshandle=m_dtm.getFirstNamespaceNode(
+			m_nodeHandle,true);
+		while(nshandle!=DTM.NULL)
+		{
+			if(prefix.equals(m_dtm.getLocalName(nshandle))) // getPrefix?
+				//return m_dtm.getNamespaceURI(nshandle);
+				return m_dtm.getNodeValue(nshandle);
+    		nshandle=m_dtm.getNextNamespaceNode(
+				m_nodeHandle,nshandle,true);
+		}
+		return null;
+    }
+
+    /**
+     * Return an enumeration of all prefixes currently declared.
+     *
+     * <p><strong>Note:</strong> if there is a default prefix, it will not be
+     * returned in this enumeration; check for the default prefix
+     * using the {@link #getURI getURI} with an argument of "".</p>
+     *
+     * @return An enumeration of all prefixes declared in the
+     *         current context except for the empty (default)
+     *         prefix.
+     * @see #getDeclaredPrefixes
+     * @see #getURI
+     */
+    public Enumeration getPrefixes ()
+    {
+    	return new Enumeration()
+    	{    		
+    		int nshandle=m_dtm.getFirstNamespaceNode(
+				m_nodeHandle,true);
+
+			public boolean hasMoreElements()
+			{
+				skipdefault();
+				return nshandle!=DTM.NULL;
+			}
+			public Object nextElement()
+			{
+				skipdefault();
+				if(nshandle==DTM.NULL)
+					return null;
+				String prefix=m_dtm.getLocalName(nshandle);
+	    		nshandle=m_dtm.getNextNamespaceNode(
+					m_nodeHandle,nshandle,true);
+				return prefix;
+			}
+			
+			private void skipdefault()
+			{
+				if(nshandle!=DTM.NULL &&
+					"".equals(m_dtm.getLocalName(nshandle)))
+		    		nshandle=m_dtm.getNextNamespaceNode(
+						m_nodeHandle,nshandle,true);
+			}
+		};
+    }    
+
+    /**
+     * Return an enumeration of all prefixes currently declared for a URI.
+     *
+     * <p>This method returns prefixes mapped to a specific Namespace
+     * URI.  The xml: prefix will be included.  If you want only one
+     * prefix that's mapped to the Namespace URI, and you don't care 
+     * which one you get, use the {@link #getPrefix getPrefix}
+     *  method instead.</p>
+     *
+     * <p><strong>Note:</strong> the empty (default) prefix is <em>never</em> included
+     * in this enumeration; to check for the presence of a default
+     * Namespace, use the {@link #getURI getURI} method with an
+     * argument of "".</p>
+     *
+     * @param uri The Namespace URI.
+     * @return An enumeration of all prefixes declared in the
+     *         current context.
+     * @see #getPrefix
+     * @see #getDeclaredPrefixes
+     * @see #getURI
+     */
+    public Enumeration getPrefixes (String uri)
+    {
+    	return new Enumeration()
+    	{    		
+    		String e_uri;
+    		int nshandle=m_dtm.getFirstNamespaceNode(
+				m_nodeHandle,true);
+
+			// Kluge to pass in the URI
+			public Enumeration setURI(String uri)
+			{
+				e_uri=uri;
+				return this;
+			}
+
+			public boolean hasMoreElements()
+			{
+				skipwronguri();
+				return nshandle!=DTM.NULL;
+			}
+			public Object nextElement()
+			{
+				skipwronguri();
+				if(nshandle==DTM.NULL)
+					return null;
+				String prefix=m_dtm.getLocalName(nshandle);
+	    		nshandle=m_dtm.getNextNamespaceNode(
+					m_nodeHandle,nshandle,true);
+				return prefix;
+			}
+			
+			private void skipwronguri()
+			{
+				while(nshandle!=DTM.NULL &&
+					! (e_uri.equals(m_dtm.getLocalName(nshandle))) )
+		    		nshandle=m_dtm.getNextNamespaceNode(
+						m_nodeHandle,nshandle,true);
+			}
+		}.setURI(uri);
+    }
+    
+    
+    /**
+     * Process a raw XML 1.0 name, after all declarations in the current
+     * context have been handled by {@link #declarePrefix declarePrefix()}.
+     *
+     * <p>This method processes a raw XML 1.0 name in the current
+     * context by removing the prefix and looking it up among the
+     * prefixes currently declared.  The return value will be the
+     * array supplied by the caller, filled in as follows:</p>
+     *
+     * <dl>
+     * <dt>parts[0]</dt>
+     * <dd>The Namespace URI, or an empty string if none is
+     *  in use.</dd>
+     * <dt>parts[1]</dt>
+     * <dd>The local name (without prefix).</dd>
+     * <dt>parts[2]</dt>
+     * <dd>The original raw name.</dd>
+     * </dl>
+     *
+     * <p>All of the strings in the array will be internalized.  If
+     * the raw name has a prefix that has not been declared, then
+     * the return value will be null.</p>
+     *
+     * <p>Note that attribute names are processed differently than
+     * element names: an unprefixed element name will received the
+     * default Namespace (if any), while an unprefixed attribute name
+     * will not.</p>
+     *
+     * @param qName The raw XML 1.0 name to be processed.
+     * @param parts An array supplied by the caller, capable of
+     *        holding at least three members.
+     * @param isAttribute A flag indicating whether this is an
+     *        attribute name (true) or an element name (false).
+     * @return The supplied array holding three internalized strings 
+     *        representing the Namespace URI (or empty string), the
+     *        local name, and the raw XML 1.0 name; or null if there
+     *        is an undeclared prefix.
+     * @see #declarePrefix
+     * @see java.lang.String#intern */
+    public String [] processName (String qName, String parts[],
+				  boolean isAttribute)
+    {
+   		parts[2]=qName;
+    	
+    	int colon=qName.indexOf(':');
+   		parts[1]=(colon<0) ? qName : qName.substring(colon+1);
+    	
+    	String pfx;
+    	if(colon==-1)
+    		pfx=(isAttribute) ? null : "";
+    	else
+	    	pfx=qName.substring(0,colon);
+    	parts[0] = (pfx==null) ? null : getURI(pfx);
+	    	
+	    return parts;
+    }
+    
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/XNI2DTM.java b/src/org/apache/xml/dtm/ref/xni2dtm/XNI2DTM.java
new file mode 100644
index 0000000..b7f1c06
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/XNI2DTM.java
@@ -0,0 +1,1757 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import javax.xml.transform.Source;
+
+import org.apache.xerces.impl.xs.AttributePSVImpl;
+import org.apache.xerces.impl.xs.ElementPSVImpl;
+import org.apache.xerces.impl.xs.psvi.XSSimpleTypeDefinition;
+import org.apache.xerces.impl.xs.psvi.XSTypeDefinition;
+import org.apache.xerces.xni.Augmentations;
+import org.apache.xerces.xni.QName;
+import org.apache.xerces.xni.XMLAttributes;
+import org.apache.xerces.xni.XMLDTDHandler;
+import org.apache.xerces.xni.XMLDocumentHandler;
+import org.apache.xerces.xni.XMLLocator;
+import org.apache.xerces.xni.XMLResourceIdentifier;
+import org.apache.xerces.xni.XMLString;
+import org.apache.xerces.xni.XNIException;
+import org.apache.xerces.xni.parser.XMLErrorHandler;
+import org.apache.xerces.xni.parser.XMLParseException;
+import org.apache.xerces.xni.parser.XMLPullParserConfiguration;
+import org.apache.xerces.xni.psvi.ItemPSVI;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xml.dtm.DTMSequence;
+import org.apache.xml.dtm.DTMWSFilter;
+import org.apache.xml.utils.SparseVector;
+import org.apache.xml.utils.WrappedRuntimeException;
+import org.apache.xpath.objects.XSequence;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * This class implements a DTM that is constructed via an XNI data stream.
+ * 
+ * Please note that it this is a PROTOTYPE, since the Xerces post-schema 
+ * validation infoset (PSVI) APIs it is using are themselves prototypes and
+ * subject to change without warning. The most recent such change was from
+ * "lightweight" to "heavyweight" schema models -- the former are no longer
+ * supported.
+ * 
+ * This version is derived from SAX2DTM for ease of implementation and
+ * support, but deliberately blocks external access to
+ * the SAX-listener calls to make our testing a bit more rigorous.
+ * 
+ * Note to developers: Both XNI and Xalan have classes called XMLString.
+ * Don't confuse them!
+ * 
+ * %REVIEW% Should we re-unify this with SAX2(RTF)DTM?
+ * 	(Since we'll want to create typed temporary trees, definitely an issue...)
+ *  To actually _USE_ as a temporary tree, we'd need to accept SAX
+ *     rather than blocking it, and/or rewrite Xalan core to be XNI-based,
+ *     and/or do some bypassing to add types to SAX stream.
+ *  Test confirms we can successfully derive from either.
+ */
+public class XNI2DTM 
+  extends org.apache.xml.dtm.ref.sax2dtm.SAX2DTM
+  implements XMLDocumentHandler, XMLErrorHandler, XMLDTDHandler
+{
+  /** DEBUGGING FLAG: Set true to monitor XNI events and similar diagnostic info. */
+  private static final boolean DEBUG = false;  
+  
+  /** %OPT% %REVIEW% PROTOTYPE: Schema Type information, datatype as instantiated.
+   * See discussion in addNode */
+  protected SparseVector m_schemaTypeOverride=new SparseVector();
+  
+  /**
+   * If we're building the model incrementally on demand, we need to
+   * be able to tell the source when to send us more data.
+   *
+   * Note that if this has not been set, and you attempt to read ahead
+   * of the current build point, we'll probably throw a null-pointer
+   * exception. We could try to wait-and-retry instead, as a very poor
+   * fallback, but that has all the known problems with multithreading
+   * on multiprocessors and we Don't Want to Go There.
+   *
+   * @see setIncrementalXNISource
+   */
+  private XMLPullParserConfiguration m_incrementalXNISource = null;
+
+  /** The XNI Document locator 
+   * %REVIEW% Should we be storing a SAX locator instead? */
+  transient private LocatorWrapper m_locator_wrapper = new LocatorWrapper();
+  
+  /** Manefest constant: Schema namespace string */
+  private static final String SCHEMANS="http://www.w3.org/2001/XMLSchema";
+  
+  /** Manefest constant: Message for SAX-disablement stubs */
+  static final String UNEXPECTED="XNI2DTM UNEXPECTED SAX ";
+
+  /**
+   * Construct a XNI2DTM object ready to be constructed from XNI
+   * ContentHandler events.
+   *
+   * @param mgr The DTMManager who owns this DTM.
+   * @param source the JAXP 1.1 Source object for this DTM.
+   * @param dtmIdentity The DTM identity ID for this DTM.
+   * @param whiteSpaceFilter The white space filter for this DTM, which may
+   *                         be null.
+   * @param xstringfactory XMLString factory for creating character content.
+   * @param doIndexing true if the caller considers it worth it to use 
+   *                   indexing schemes.
+   */
+  public XNI2DTM(DTMManager mgr, Source source, int dtmIdentity,
+                 DTMWSFilter whiteSpaceFilter,
+                 org.apache.xml.utils.XMLStringFactory xstringfactory,
+                 boolean doIndexing)
+  {
+    super(mgr, source, dtmIdentity, whiteSpaceFilter, 
+          xstringfactory, doIndexing);
+  }
+
+  
+  /** ADDED for XNI, SUPPLEMENTS non-schema-typed addNode:
+   * 
+   * Construct the node map from the node. EXTENDED to carry PSVI type data
+   * delivered via XNI. This is currently using non-published Xerces APIs, which
+   * are subject to change as their PSVI support becomes more official.
+   *
+   * @param type raw type ID, one of DTM.XXX_NODE.
+   * @param expandedTypeID The expended type ID.
+   * @param parentIndex The current parent index.
+   * @param previousSibling The previous sibling index.
+   * @param dataOrPrefix index into m_data table, or string handle.
+   * @param canHaveFirstChild true if the node can have a first child, false
+   *                          if it is atomic.
+   * @param actualType Schema type object as resolved in actual instance document
+   *
+   * @return The index identity of the node that was added.
+   */
+  protected int addNode(int type, int expandedTypeID,
+                        int parentIndex, int previousSibling,
+                        int dataOrPrefix, boolean canHaveFirstChild,
+                        XPath2Type actualType)
+  {
+    int identity=super.addNode(type,expandedTypeID,
+                               parentIndex,previousSibling,
+                               dataOrPrefix,canHaveFirstChild);
+
+    // The goal is to not consume storage for types unless they actualy exist,
+    // and to minimize per-node overhead.
+    //
+    // NOTE: Record first-seen as default even if it is null, because
+    // otherwise late changes of type will bash previously recorded
+    // nodes. This is NOT necessarily maximally efficient, but to really
+    // optimize we would have to rewrite data to make the default the most
+    // common -- and since Scott insists that overrides will be uncommon,
+    // I don't want to go there.
+    //
+    // NOTE: Element schema-types aren't fully resolved until endElement, and
+    // need to be dealt with there.
+    if(type!=ELEMENT_NODE)
+    {
+      // Try to record as default for this nodetype
+      if(!m_expandedNameTable.setSchemaType(m_exptype.elementAt(identity),
+                                            actualType)
+         )
+      {
+        m_schemaTypeOverride.setElementAt(actualType,identity);
+      }
+    }
+
+    return identity;
+  }
+
+  /** ADDED FOR XPATH2: Query schema type name of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the expanded-QName (namespace URI
+   *    rather than prefix) of the type actually
+   *    resolved in the instance document. Note that this may be derived from,
+   *    rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeName(int nodeHandle)
+  {
+    int identity=makeNodeIdentity(nodeHandle);
+        
+    if(identity!=DTM.NULL)
+    {
+      XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
+      if(actualType==null)
+        actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
+
+      if(actualType!=null)
+      {
+        String nsuri=actualType.getTargetNamespace();
+        String local=actualType.getTypeName();
+        return (nsuri==null)
+          ? local
+          : nsuri+":"+local;
+      }
+    }
+        
+    return null;
+  }
+        
+  /** ADDED FOR XPATH2: Query schema type namespace of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the namespace URI
+   *    of the type actually resolved in the instance document. This may
+   *    be null if the default/unspecified namespace was used.
+   *    Note that this may be derived from,
+   *    rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeNamespace(int nodeHandle)
+  {
+    int identity=makeNodeIdentity(nodeHandle);
+        
+    if(identity!=DTM.NULL)
+    {
+      XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
+      if(actualType==null)
+        actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
+      if(actualType!=null)
+      {
+        return actualType.getTargetNamespace();
+      }
+    }
+        
+    return null;
+  }
+
+  /** ADDED FOR XPATH2: Query schema type localname of a given node.
+   * 
+   * %REVIEW% Is this actually needed?
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @return null if no type known, else returns the localname of the type
+   *    resolved in the instance document. Note that this may be derived from,
+   *    rather than identical to, the type declared in the schema.
+   */
+  public String getSchemaTypeLocalName(int nodeHandle)
+  {
+    int identity=makeNodeIdentity(nodeHandle);
+        
+    if(identity!=DTM.NULL)
+    {
+      XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
+      if(actualType==null)
+        actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
+      if(actualType!=null)
+      {
+        return actualType.getTypeName();
+      }
+    }
+        
+    return null;
+  }
+
+  /** ADDED FOR XPATH2: Query whether node's type is derived from a specific type
+   * 
+   * @param nodeHandle DTM Node Handle of Node to be queried
+   * @param namespace String containing URI of namespace for the type we're intersted in
+   * @param localname String containing local name for the type we're intersted in
+   * @return true if node has a Schema Type which equals or is derived from 
+   *    the specified type. False if the node has no type or that type is not
+   *    derived from the specified type.
+   */
+  public boolean isNodeSchemaType(int nodeHandle, String namespace, String localname)
+  {
+    int identity=makeNodeIdentity(nodeHandle);
+        
+    if(identity!=DTM.NULL)
+    {
+      XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
+      if(actualType==null)
+        actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
+      if(actualType!=null)
+        return actualType.derivedFrom(namespace,localname);
+    }
+        
+    return false;
+  }
+  
+  /** ADDED FOR XPATH2: Retrieve the typed value(s), based on the schema type
+   * 
+   * %REVIEW% That may not be 
+   * */
+  public DTMSequence getTypedValue(int nodeHandle)
+  {
+    // Determine whether instance of built-in type, or list thereof
+    // If so, map to corresponding Java type
+    // Retrieve string content (as always, for element this spans children
+    // If type was xs:string (or untyped?) just return that in a collection.
+    // Else parse into collection object, return that
+         
+    int identity=makeNodeIdentity(nodeHandle);
+    if(identity==DTM.NULL)
+      return DTMSequence.EMPTY;
+                
+    XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
+    if(actualType==null)
+      actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
+
+    if(actualType==null)
+      return DTMSequence.EMPTY;
+                
+        /* %REVIEW% Efficiency issues; value may be in FSB or scattered,
+        	 in which case generating a Java String may arguably be wasteful. 
+        	 And are we handling list types at all reasonably?
+        	 */
+        //GONK lists;
+        //GONK efficiency;
+        
+    // Gathers all text. Is that right? Should we not do if type is not known?
+    String textvalue=getStringValue(nodeHandle).toString();
+    
+    // DTM node should provide the namespace context.
+    // Do we have an existing encapulation for that concept?
+        
+    return actualType.typedValue(textvalue, 
+    	new org.apache.xml.dtm.ref.xni2dtm.NamespaceSupportAtDTMNode(this,nodeHandle));
+  }
+  
+  
+  //===========================================================================
+
+  /** OVERRIDDEN FOR XNI:
+   * 
+   * Ask the CoRoutine parser to terminate and clear the reference. If
+   * the parser has already been cleared, this will have no effect.
+   *
+   * @param callDoTerminate true if parsing should be terminated
+   */
+  public void clearCoRoutine(boolean callDoTerminate)
+  {
+
+    if (null != m_incrementalXNISource)
+    {
+      if (callDoTerminate)
+        m_incrementalXNISource.cleanup();
+
+      m_incrementalXNISource = null;
+    }
+  }
+
+  /** ADDED FOR XNI, REPLACES setIncrementalSAXSource:
+   * 
+   * Bind a IncrementalXNISource to this DTM. If we discover we need nodes
+   * that have not yet been built, we will ask this object to send us more
+   * events, and it will manage interactions with its data sources.
+   *
+   * Note that we do not actually build the IncrementalXNISource, since we don't
+   * know what source it's reading from, what thread that source will run in,
+   * or when it will run.
+   *
+   * @param incrementalXNISource The parser that we want to recieve events from
+   * on demand.
+   * @param appCoRID The CoRoutine ID for the application.
+   */
+  public void setIncrementalXNISource(XMLPullParserConfiguration incrementalXNISource)
+  {
+
+    // Establish coroutine link so we can request more data
+    //
+    // Note: It's possible that some versions of IncrementalXNISource may
+    // not actually use a CoroutineManager, and hence may not require
+    // that we obtain an Application Coroutine ID. (This relies on the
+    // coroutine transaction details having been encapsulated in the
+    // IncrementalXNISource.do...() methods.)
+    m_incrementalXNISource = incrementalXNISource;
+
+    // Establish XNI-stream link so we can receive the requested data
+    incrementalXNISource.setDocumentHandler(this);
+
+    // Are the following really needed? incrementalXNISource doesn't yet
+    // support them, and they're mostly no-ops here...
+    incrementalXNISource.setErrorHandler(this);
+    incrementalXNISource.setDTDHandler(this);
+  }
+
+  /** DISABLED FOR XNI:
+   * 
+   * getContentHandler returns "our SAX builder" -- the thing that
+   * someone else should send SAX events to in order to extend this
+   * DTM model.
+   * 
+   * %REVIEW% We _could_ leave SAX support in place and have a single model
+   * that handles both kinds of event streams. I've chosen to block it
+   * during development for better isolation of XNI support.
+   *
+   * @return null since this model doesn't respond to SAX events
+   */
+  public org.xml.sax.ContentHandler getContentHandler()
+  {
+    return null;
+  }
+
+  /**
+   * Return this DTM's lexical handler.
+   *
+   * %REVIEW% Should this return null if constrution already done/begun?
+   * 
+   * %REVIEW% We _could_ leave SAX support in place and have a single model
+   * that handles both kinds of event streams. I've chosen to block it
+   * during development for better isolation of XNI support.
+   *
+   * @return null since this model doesn't respond to SAX events
+   */
+  public org.xml.sax.ext.LexicalHandler getLexicalHandler()
+  {
+    return null;
+  }
+
+  /**
+   * Return this DTM's DTDHandler.
+   * 
+   * %REVIEW% We _could_ leave SAX support in place and have a single model
+   * that handles both kinds of event streams. I've chosen to block it
+   * during development for better isolation of XNI support.
+   *
+   * @return null since this model doesn't respond to SAX events
+   */
+  public org.xml.sax.DTDHandler getDTDHandler()
+  {
+    return null;
+  }
+
+  /**
+   * Return this DTM's ErrorHandler.
+   *
+   * @return null if this model doesn't respond to SAX error events.
+   */
+  public org.xml.sax.ErrorHandler getErrorHandler()
+  {
+    //return this;
+    return null;
+  }
+
+  /**
+   * Return this DTM's DeclHandler.
+   *
+   * @return null if this model doesn't respond to SAX Decl events.
+   */
+  public org.xml.sax.ext.DeclHandler getDeclHandler()
+  {
+    //return this;
+    return null;
+  }
+
+  /** OVERRIDDEN FOR XNI:
+   * 
+   * @return true iff we're building this model incrementally (eg
+   * we're partnered with a IncrementalXNISource) and thus require that the
+   * transformation and the parse run simultaneously. Guidance to the
+   * DTMManager.
+   */
+  public boolean needsTwoThreads()
+  {
+    return null != m_incrementalXNISource;
+  }
+
+  /** OVERRIDDEN FOR XNI:
+   * 
+   * This method should try and build one or more nodes in the table.
+   * 
+   * %REVIEW% Is it worth factoring out the actual request for more events
+   * into a subroutine, isolating it better? Consider if/when we re-merge
+   * with SAX2DTM.
+   *
+   * @return The true if a next node is found or false if
+   *         there are no more nodes.
+   */
+  protected boolean nextNode()
+  {
+
+    if (null == m_incrementalXNISource)
+      return false;
+
+    if (m_endDocumentOccured)
+    {
+      clearCoRoutine();
+
+      return false;
+    }
+
+    try
+    {
+      boolean gotMore = m_incrementalXNISource.parse(false);
+      if (!gotMore)
+      {
+        // EOF reached without satisfying the request
+        clearCoRoutine();  // Drop connection, stop trying
+        // %TBD% deregister as its listener?
+      }
+      return gotMore;
+    }
+    catch(RuntimeException e)
+    {
+      throw e;
+    }
+    catch(Exception e)
+    {
+      throw new WrappedRuntimeException(e);
+    }
+
+    // %REVIEW% dead code
+    //clearCoRoutine();
+    //return false;
+  }
+  
+  /** %REVIEW% XNI should let us support this better...
+   * 
+   * Return the public identifier of the external subset,
+   * normalized as described in 4.2.2 External Entities [XML]. If there is
+   * no external subset or if it has no public identifier, this property
+   * has no value.
+   *
+   * @param the document type declaration handle
+   *
+   * @return the public identifier String object, or null if there is none.
+   */
+  public String getDocumentTypeDeclarationPublicIdentifier()
+  {
+    return super.getDocumentTypeDeclarationPublicIdentifier();
+  }
+
+
+
+  ////////////////////////////////////////////////////////////////////
+  // Implementation of XNI XMLDocumentHandler interface.
+  //
+  // %REVIEW% Hand off the SAX2DTM SAX event code, or copy/adapt method
+  // bodies? Performance may favor latter approach, but former is no worse
+  // than what's been happening on the parser's side of the fence and
+  // simplifies maintainance.
+  ////////////////////////////////////////////////////////////////////
+
+  /**
+   * Receive notification of a notation declaration.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass if they wish to keep track of the notations
+   * declared in a document.</p>
+   *
+   * @param name The notation name.
+   * @param publicId The notation public identifier, or null if not
+   *                 available.
+   * @param systemId The notation system identifier.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.DTDHandler#notationDecl
+   *
+   * @throws XNIException
+   */
+  public void notationDecl(String name, String publicId, String systemId)
+    throws XNIException
+  {
+    // no op
+  }
+
+  /**
+   * Receive notification of an unparsed entity declaration.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass to keep track of the unparsed entities
+   * declared in a document.</p>
+   *
+   * @param name The entity name.
+   * @param publicId The entity public identifier, or null if not
+   *                 available.
+   * @param systemId The entity system identifier.
+   * @param notationName The name of the associated notation.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+   *
+   * @throws XNIException
+   */
+  public void unparsedEntityDecl(
+                                 String name, String publicId, String systemId, String notationName)
+    throws XNIException
+  {
+    try
+    {
+      super.unparsedEntityDecl(name,publicId,systemId,notationName);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive a Locator object for document events.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass if they wish to store the locator for use
+   * with other document events.</p>
+   *
+   * @param locator A locator for all XNI document events.
+   * @see org.xml.sax.ContentHandler#setDocumentLocator
+   * @see org.xml.sax.Locator
+   */
+  public void setDocumentLocator(XMLLocator locator)
+  {
+    m_locator_wrapper.setLocator(locator);
+    super.setDocumentLocator(m_locator_wrapper);
+  }
+
+  /**
+   * Receive notification of the beginning of the document.
+   *
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#startDocument
+   */
+  public void startDocument(XMLLocator locator,String encoding,Augmentations augs)
+    throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("startDocument");
+ 
+    try
+    {    
+      super.startDocument();
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of the end of the document.
+   *
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#endDocument
+   */
+  public void endDocument(Augmentations augs) throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("endDocument");
+      
+    try
+    {
+      super.endDocument();
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of the start of a Namespace mapping.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass to take specific actions at the start of
+   * each Namespace prefix scope (such as storing the prefix mapping).</p>
+   *
+   * @param prefix The Namespace prefix being declared.
+   * @param uri The Namespace URI mapped to the prefix.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#startPrefixMapping
+   */
+  public void startPrefixMapping(String prefix,String uri,Augmentations augs)
+    throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("startPrefixMapping: prefix: " + prefix + ", uri: "
+                         + uri);
+    try
+    {                        
+      if(augs!=null &&
+         null!=augs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE))
+      {
+        if (DEBUG)
+          System.out.println("\t***** Added by DTM2XNI; ignored here");
+                  
+        return; // Ignore it!
+      }
+                
+                  
+      super.startPrefixMapping(prefix,uri);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of the end of a Namespace mapping.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass to take specific actions at the end of
+   * each prefix mapping.</p>
+   *
+   * @param prefix The Namespace prefix being declared.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#endPrefixMapping
+   */
+  public void endPrefixMapping(String prefix, Augmentations augs) 
+    throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("endPrefixMapping: prefix: " + prefix);
+
+    try
+    {
+      if(augs!=null &&
+         null!=augs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE))
+      {
+        if (DEBUG)
+          System.out.println("\t***** Added by DTM2XNI; ignored here");
+                  
+        return; // Ignore it!
+      }
+                
+      super.endPrefixMapping(prefix);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of the start of an element.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass to take specific actions at the start of
+   * each element (such as allocating a new tree node or writing
+   * output to a file).</p>
+   *
+   * @param name The element type name.
+   *
+   * @param uri The Namespace URI, or the empty string if the
+   *        element has no Namespace URI or if Namespace
+   *        processing is not being performed.
+   * @param localName The local name (without prefix), or the
+   *        empty string if Namespace processing is not being
+   *        performed.
+   * @param qName The qualified name (with prefix), or the
+   *        empty string if qualified names are not available.
+   * @param attributes The specified or defaulted attributes.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#startElement
+   */
+  public void startElement(QName element, XMLAttributes attributes,
+                           Augmentations augs)
+    //String uri, String localName, String qName, Attributes attributes)
+    throws XNIException
+  {
+    // %REVIEW% I've copied this verbatim and altered it for XNI.
+    // Is that overkill? Can we hand any of it back to the SAX layer?
+    // (I suspect not, darn it....)
+    
+    if (DEBUG)
+    {
+      System.out.println("startElement: uri: " + element.uri + 
+                         ", localname: " + element.localpart + 
+                         ", qname: "+element.rawname+", atts: " + attributes);    
+    }
+      
+    boolean syntheticElement=false;
+        
+    // Augs might be null if schema support not turned on in parser. 
+    // Shouldn't arise in final operation (?); may arise during debugging
+    ElementPSVImpl elemPSVI=null;
+    XSTypeDefinition actualType =null;
+    XPath2Type xp2type=null;
+    if(augs!=null)
+    {
+      // Node added by DTM2XNI?
+      syntheticElement = null!=augs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE);
+        
+      // Extract Experimental Xerces PSVI data          
+      elemPSVI=(ElementPSVImpl)augs.getItem(org.apache.xerces.impl.Constants.ELEMENT_PSVI);
+      xp2type=new XPath2Type(elemPSVI,false);
+      actualType =
+        (elemPSVI==null) ? null : elemPSVI.getTypeDefinition();
+      if (DEBUG)
+      {
+        String actualExpandedQName=xp2type.getTargetNamespace()+":"+xp2type.getTypeName();
+
+        System.out.println("\ttypeDefinition (actual): "+ actualType +
+                           "\n\t\ttype expanded-qname: " + actualExpandedQName +
+//                           "\n\tDerived from builtin string: " + actualType.derivedFrom(SCHEMANS,"string") +
+                           "\n\tSynthesized by DTM2XNI: "+syntheticElement
+                           );
+      } //DEBUG
+    }// augs
+    
+    if(DEBUG && attributes!=null)  
+    {
+      int n = attributes.getLength();
+      if(n==0)
+        System.out.println("\tempty attribute list");
+      else for (int i = 0; i < n; i++)
+      {
+        System.out.println("\t attr: uri: " + attributes.getURI(i) +
+                           ", localname: " + attributes.getLocalName(i) +
+                           ", qname: " + attributes.getQName(i) +
+                           ", type: " + attributes.getType(i) +
+                           ", value: " + attributes.getValue(i)                                                                                                          
+                           );
+        // Experimental Xerces PSVI data
+        Augmentations attrAugs=attributes.getAugmentations(i);
+        AttributePSVImpl attrPSVI=(AttributePSVImpl)attrAugs.getItem(org.apache.xerces.impl.Constants.ATTRIBUTE_PSVI);
+        XPath2Type xp2attrtype=new XPath2Type(attrPSVI,true);
+        XSTypeDefinition actualAttrType=(attrPSVI==null) ? null : attrPSVI.getTypeDefinition();
+        String actualExpandedQName=(actualAttrType==null) ? null : actualAttrType.getNamespace()+":"+actualAttrType.getName();
+        // Node added by DTM2XNI?
+        boolean syntheticAttribute = null!=attrAugs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE);
+
+        actualExpandedQName=xp2attrtype.getTargetNamespace()+
+        	":"+ xp2attrtype.getTypeName();
+        
+        System.out.println("\t\ttypeDefinition (actual): "+ actualAttrType +
+                           "\n\t\t\ttype expanded-qname: " + actualExpandedQName
+                           );
+        if(actualAttrType!=null)                                                
+          System.out.println(
+                             "\n\t\tSynthesized by DTM2XNI: "+syntheticAttribute
+                             );
+      } // dump all attrs
+    } // DEBUG
+
+    
+    if(syntheticElement)
+    {
+      if (DEBUG)
+        System.out.println("\t***** Added by DTM2XNI; ignored here");
+      
+      return; // Ignore it!
+    }
+    
+    charactersFlush();
+
+
+    int exName = m_expandedNameTable.getExpandedTypeID(element.uri, element.localpart, DTM.ELEMENT_NODE);
+    String prefix = getPrefix(element.rawname, element.uri);
+    int prefixIndex = (null != element.prefix)
+      ? m_valuesOrPrefixes.stringToIndex(element.rawname) : 0;
+    int elemNode = addNode(DTM.ELEMENT_NODE, exName,
+                           m_parents.peek(), m_previous, prefixIndex, true,
+                           xp2type);
+
+    if(m_indexing)
+      indexNode(exName, elemNode);
+    
+    m_parents.push(elemNode);
+
+    int startDecls = m_contextIndexes.peek();
+    int nDecls = m_prefixMappings.size();
+    int prev = DTM.NULL;
+
+    if(!m_pastFirstElement)
+    {
+      // SPECIAL CASE: Implied declaration at root element
+      prefix="xml";
+      String declURL = "http://www.w3.org/XML/1998/namespace";
+      exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
+      int val = m_valuesOrPrefixes.stringToIndex(declURL);
+      // %REVIEW% I don't _think_ we need datatype on namespaces...?
+      prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode,
+                     prev, val, false);
+      m_pastFirstElement=true;
+    }
+                        
+    for (int i = startDecls; i < nDecls; i += 2)
+    {
+      prefix = (String) m_prefixMappings.elementAt(i);
+
+      if (prefix == null)
+        continue;
+
+      String declURL = (String) m_prefixMappings.elementAt(i + 1);
+
+      exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
+
+      int val = m_valuesOrPrefixes.stringToIndex(declURL);
+
+      // %REVIEW% I don't _think_ we need datatype on namespaces...?
+      prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode,
+                     prev, val, false);
+    }
+
+    int n = attributes.getLength();
+
+    for (int i = 0; i < n; i++)
+    {
+      String attrUri = attributes.getURI(i);
+      
+      
+      
+      String attrQName = attributes.getQName(i);
+      String valString = attributes.getValue(i);
+
+      prefix = getPrefix(attrQName, attrUri);
+
+      int nodeType;
+
+      if ((null != attrQName)
+          && (attrQName.equals("xmlns")
+              || attrQName.startsWith("xmlns:")))
+      {
+        if (declAlreadyDeclared(prefix))
+          continue;  // go to the next attribute.
+
+        nodeType = DTM.NAMESPACE_NODE;
+      } // NS special-handling
+      else
+      {
+        nodeType = DTM.ATTRIBUTE_NODE;
+
+        if (attributes.getType(i).equalsIgnoreCase("ID"))
+          setIDAttribute(valString, elemNode);
+      } // Attr/ID special handling
+      
+      
+      // Bit of a hack... if somehow valString is null, stringToIndex will 
+      // return -1, which will make things very unhappy.
+      if(null == valString)
+        valString = "";
+
+      int val = m_valuesOrPrefixes.stringToIndex(valString);
+      String attrLocalName = attributes.getLocalName(i);
+
+      if (null != prefix)
+      {
+        
+        prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
+
+        int dataIndex = m_data.size();
+
+        m_data.addElement(prefixIndex);
+        m_data.addElement(val);
+
+        val = -dataIndex;
+      } // Prefix handling
+
+      exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
+
+      // Experimental Xerces PSVI data
+      Augmentations attrAugs=attributes.getAugmentations(i);
+      boolean syntheticAttribute= null != attrAugs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE);
+      if(syntheticAttribute)
+      {
+        if (DEBUG)
+          System.out.println("\t***** Attr {"+attrUri+"}"+attrLocalName+" added by DTM2XNI; ignored here");
+        return; // Ignore it!
+      } // Synthetic suppression
+      
+      AttributePSVImpl attrPSVI=(AttributePSVImpl)attrAugs.getItem(org.apache.xerces.impl.Constants.ATTRIBUTE_PSVI);
+      XPath2Type xp2attrtype=new XPath2Type(attrPSVI,true);
+      
+      prev = addNode(nodeType, exName, elemNode, prev, val,
+                     false, xp2attrtype);
+    } // Attribute list loop
+    
+    
+    if(DTM2XNI.SUPPRESS_XSI_ATTRIBUTES)
+    {
+     	// Were any XNI attributes passed _around_ the validator,
+     	// using element augmentations? If so, magic them back
+     	// into being attributes.
+     	//
+     	// See comments in DTM2XNI. Is this trip REALLY necessary?)
+      	java.util.Vector v=(java.util.Vector)augs.getItem(DTM2XNI.SUPPRESSED_XSI);
+     	if(v!=null)
+     	{
+     		for(int i=v.size()-1;i>=0;--i)
+     		{
+     			Object[] ary=(Object[])v.elementAt(i); 	// {QName,"CDATA",value}
+     			QName aqq=(QName) ary[0];
+     			String valString=(String) ary[2]; 
+				if(null == valString)
+					valString = "";
+				int val = m_valuesOrPrefixes.stringToIndex(valString);
+		        exName = m_expandedNameTable.getExpandedTypeID(
+		        	aqq.uri,aqq.localpart, DTM.ATTRIBUTE_NODE);
+
+     			prev=addNode(DTM.ATTRIBUTE_NODE,exName,elemNode,prev,val,
+     						false,null);
+     		}
+     	}
+     	
+    }
+
+    if (DTM.NULL != prev)
+      m_nextsib.setElementAt(DTM.NULL,prev);
+
+    if (null != m_wsfilter)
+    {
+      short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
+      boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
+        ? getShouldStripWhitespace()
+        : (DTMWSFilter.STRIP == wsv);
+
+      pushShouldStripWhitespace(shouldStrip);
+    }
+
+    m_previous = DTM.NULL;
+
+    m_contextIndexes.push(m_prefixMappings.size());  // for the children.
+  }
+
+  /**
+   * Receive notification of the end of an element.
+   *
+   * @param name The element type name.
+   * @param attributes The specified or defaulted attributes.
+   *
+   * @param uri The Namespace URI, or the empty string if the
+   *        element has no Namespace URI or if Namespace
+   *        processing is not being performed.
+   * @param localName The local name (without prefix), or the
+   *        empty string if Namespace processing is not being
+   *        performed.
+   * @param qName The qualified XML 1.0 name (with prefix), or the
+   *        empty string if qualified names are not available.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#endElement
+   */
+  public void endElement(QName element,Augmentations augs) throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("endElement: uri: " + element.uri + 
+                         ", localname: " + element.localpart + ", qname: "+element.rawname);
+                         
+    if(null!=augs && null!=augs.getItem(DTM2XNI.DTM2XNI_ADDED_STRUCTURE))
+    {
+      if (DEBUG)
+        System.out.println("\t***** Added by DTM2XNI; ignored here");
+      
+      return; // Ignore it!
+    }
+
+    try
+    {
+      super.endElement(element.uri,element.localpart,element.rawname);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+
+	// Complication: Type information is obtained at startElement.
+	// VALIDITY isn't known 'till the endElement. XPath2 type is actually
+	// a combination of information from both. NOTE that this largely defeats
+	// attempts to implement XNI2DTM as a standard demand-mode DTM; we don't 
+	// know the node type until we _exit_ the node; the nextNode() logic
+	// would have to be rewritten to deal with that, and very little streaming
+	// would actually result.
+
+   	{
+  	   // After super.endElement, m_previous is the element we're ending.	
+   	  // Try to record as default for this nodetype, 
+   	  // using our type wrapper which records XPath2 resolved NS/localname
+      
+	  ItemPSVI elemPSVI=null;
+	  XPath2Type actualType =null;
+      if(augs!=null)
+      {
+        elemPSVI=(ItemPSVI) augs.getItem(org.apache.xerces.impl.Constants.ELEMENT_PSVI);
+        
+	  /** %BUG% Work around Xerces' bad habit of not telling us what the type was
+	   * at the time endElement() is called, and (obviously) not telling us
+ 	   * validity at the time startElement() is called. I hope to convince them
+	   * to change the former.
+	   * */
+		XSSimpleTypeDefinition member=elemPSVI.getMemberTypeDefinition();
+		XSTypeDefinition type=elemPSVI.getTypeDefinition();
+        
+		actualType =new XPath2Type(elemPSVI,member,type,false);
+      }
+
+      if(!m_expandedNameTable.setSchemaType(m_exptype.elementAt(m_previous),
+                                            actualType)
+         )
+      {
+        m_schemaTypeOverride.setElementAt(actualType,m_previous);
+      }
+    }
+    
+  }
+
+  /** An empty element.
+   * 
+   * @param element - The name of the element.
+   * @param attributes - The element attributes.
+   * @param augs - Additional information that may include infoset augmentations
+   * @throws XNIException - Thrown by handler to signal an error.
+   * */
+  public void emptyElement(QName element,
+                           XMLAttributes attributes,
+                           Augmentations augs)
+    throws XNIException
+  {
+    // %OPT% We could skip the pushes and pops and save some cycles...
+      startElement(element,attributes,augs);
+      endElement(element,augs);
+  }
+
+  /**
+   * Receive notification of character data inside an element.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method to take specific actions for each chunk of character data
+   * (such as adding the data to a node or buffer, or printing it to
+   * a file).</p>
+   *
+   * @param ch The characters.
+   * @param start The start position in the character array.
+   * @param length The number of characters to use from the
+   *               character array.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#characters
+   */
+  public void characters(org.apache.xerces.xni.XMLString text,Augmentations augs) throws XNIException
+  {
+    try
+    {
+      super.characters(text.ch, text.offset, text.length);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of ignorable whitespace in element content.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method to take specific actions for each chunk of ignorable
+   * whitespace (such as adding data to a node or buffer, or printing
+   * it to a file).</p>
+   *
+   * @param ch The whitespace characters.
+   * @param start The start position in the character array.
+   * @param length The number of characters to use from the
+   *               character array.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#ignorableWhitespace
+   */
+  public void ignorableWhitespace(org.apache.xerces.xni.XMLString text, Augmentations augs)
+    throws XNIException
+  {
+    // %OPT% We can probably take advantage of the fact that we know this 
+    // is whitespace... or has that been dealt with at the source?
+    try
+    {
+      super.characters(text.ch, text.offset, text.length);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Receive notification of a processing instruction.
+   *
+   * <p>By default, do nothing.  Application writers may override this
+   * method in a subclass to take specific actions for each
+   * processing instruction, such as setting status variables or
+   * invoking other methods.</p>
+   *
+   * @param target The processing instruction target.
+   * @param data The processing instruction data, or null if
+   *             none is supplied.
+   * @throws XNIException Any XNI exception, possibly
+   *            wrapping another exception.
+   * @see org.xml.sax.ContentHandler#processingInstruction
+   */
+  public void processingInstruction(String target,org.apache.xerces.xni.XMLString data,Augmentations augs)
+    throws XNIException
+  {
+    if (DEBUG)
+      System.out.println("processingInstruction: target: " + target +", data: "+data);
+
+    try
+    {
+      // %REVIEW% Can we avoid toString? I don't think so, given our 
+      // current data structures, but that bears reconsideration
+      super.processingInstruction(target,data.toString());
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Report the beginning of an entity in content.
+   *
+   * <p><strong>NOTE:</entity> entity references in attribute
+   * values -- and the start and end of the document entity --
+   * are never reported.</p>
+   *
+   * <p>The start and end of the external DTD subset are reported
+   * using the pseudo-name "[dtd]".  All other events must be
+   * properly nested within start/end entity events.</p>
+   *
+   * <p>Note that skipped entities will be reported through the
+   * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
+   * event, which is part of the ContentHandler interface.</p>
+   *
+   * @param name The name of the entity.  If it is a parameter
+   *        entity, the name will begin with '%'.
+   * @throws SAXException The application may raise an exception.
+   * @see #endEntity
+   * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
+   * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
+   */
+  public void startGeneralEntity(String name,XMLResourceIdentifier identifier,
+                                 String encoding,Augmentations augs) 
+    throws XNIException
+  {
+
+    // no op
+  }
+
+  /**
+   * Report the end of an entity.
+   *
+   * @param name The name of the entity that is ending.
+   * @throws SAXException The application may raise an exception.
+   * @see #startEntity
+   */
+  public void endGeneralEntity(String name,Augmentations augs) throws XNIException
+  {
+
+    // no op
+  }
+  
+  /** Notifies of the presence of an XMLDecl line in the document. 
+   * If present, this method will be called immediately following 
+   * the startDocument call.
+   * @param version - The XML version.
+   * @param encoding - The IANA encoding name of the document, or null if not
+   *    specified.
+   * @param standalone - The standalone value, or null if not specified.
+   * @param augs - Additional information that may include infoset augmentations
+   * @throws XNIException - Thrown by handler to signal an error.
+   * */
+  public void xmlDecl(String version,String encoding,String standalone,
+                      Augmentations augs)
+    throws XNIException
+  {
+
+    // no op
+  }
+             
+        
+  /** Notifies of the presence of a TextDecl line in an entity. If present, this
+   * method will be called immediately following the startEntity call. 
+   * 
+   * Note: This method will never be called for the document entity; it is only
+   * called for external general entities referenced in document content. 
+   * 
+   * Note: This method is not called for entity references appearing as part of
+   * attribute values.
+   * @param version - The XML version, or null if not specified.
+   * @param encoding - The IANA encoding name of the entity.
+   * @param augs - Additional information that may include infoset augmentations
+   * @throws XNIException - Thrown by handler to signal an error.
+   * */
+  public void textDecl(String version,String encoding,Augmentations augs)
+    throws XNIException
+  {
+
+    // no op
+  }
+              
+
+  /**
+   * Report the start of a CDATA section.
+   *
+   * <p>The contents of the CDATA section will be reported through
+   * the regular {@link org.xml.sax.ContentHandler#characters
+   * characters} event.</p>
+   *
+   * @throws SAXException The application may raise an exception.
+   * @see #endCDATA
+   */
+  public void startCDATA(Augmentations augs) throws XNIException
+  {
+    try
+    {
+      super.startCDATA();
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+        
+  }
+
+  /**
+   * Report the end of a CDATA section.
+   *
+   * @throws SAXException The application may raise an exception.
+   * @see #startCDATA
+   */
+  public void endCDATA(Augmentations augs) throws XNIException
+  {
+    try
+    {
+      super.endCDATA();
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+  /**
+   * Report an XML comment anywhere in the document.
+   *
+   * <p>This callback will be used for comments inside or outside the
+   * document element, including comments in the external DTD
+   * subset (if read).</p>
+   *
+   * @param ch An array holding the characters in the comment.
+   * @param start The starting position in the array.
+   * @param length The number of characters to use from the array.
+   * @throws SAXException The application may raise an exception.
+   */
+  public void comment(org.apache.xerces.xni.XMLString text,Augmentations augs) throws XNIException
+  {
+    try
+    {
+      super.comment(text.ch,text.offset,text.length);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+
+
+  /** Helper class: Present XNI Locator info as SAX Locator
+   * */
+  private class LocatorWrapper 
+    implements org.xml.sax.Locator
+  {
+    XMLLocator locator;
+    String publicId=null;
+    String systemId=null;
+        
+    public void setLocator(XMLLocator locator)
+    { this.locator=locator; }
+        
+    public void setPublicId(String publicId)
+    { this.publicId=publicId; }
+        
+    public void setSystemId(String systemId)
+    { this.systemId=systemId; }
+        
+    public int getColumnNumber() 
+    {
+      return locator.getColumnNumber();
+    }
+    public int getLineNumber() 
+    {
+      return locator.getLineNumber();
+    }
+    public String getPublicId() 
+    {
+      return publicId;
+    }
+    public String getSystemId()         
+    {
+      return systemId;
+    }
+  }
+  
+  /** Notifies of the presence of the DOCTYPE line in the document.
+         *  @param rootElement - The name of the root element.
+         * @param publicId - The public identifier if an external DTD or null if the
+         *        external DTD is specified using SYSTEM.
+         * @param systemId - The system identifier if an external DTD, null otherwise.
+         * @param augs - Additional information that may include infoset augmentations
+         * @throws XNIException - Thrown by handler to signal an error.
+         * */
+  public void doctypeDecl(String rootElement,String publicId,String systemId,
+                          Augmentations augs)
+    throws XNIException
+  {
+    // no op
+  }
+    
+  ////////////////////////////////////////////////////////////////////
+  // XNI error handler
+  
+  public void warning(java.lang.String domain,
+                      java.lang.String key,
+                      XMLParseException exception)
+    throws XNIException
+  {
+    // %REVIEW% Should be routed to the JAXP error listener, presumably.
+    // What's the easiest way to get that from here?
+    // It's available from the xctxt, but I'm not sure how to get that
+    // from the DTM structures; the connections mostly go the other way.
+    System.err.println(exception);
+  }
+  public void error(java.lang.String domain,
+                    java.lang.String key,
+                    XMLParseException exception)
+    throws XNIException
+  {
+    // %REVIEW% Should be routed to the JAXP error listener, presumably.
+    // see warning()
+     System.err.println(exception);
+  }
+  public void fatalError(java.lang.String domain,
+                         java.lang.String key,
+                         XMLParseException exception)
+    throws XNIException
+  {
+    // %REVIEW% Should be routed to the JAXP error listener, presumably.
+    // see warning()
+    throw exception;
+  }
+  
+  ////////////////////////////////////////////////////////////////////
+  // XNI DTD handler. Needed for unparsed entities, but to get that
+  // have to accept the other calls... which means we need to know the start
+  // and end of the DTD to prevent DTD comments from being taken as
+  // part of the main document.
+  
+  public void startDTD(XMLLocator locator,
+                       Augmentations augmentations)
+    throws XNIException
+  {
+    try
+    {
+      super.startDTD("unknownDocumentTypeName",locator.getPublicId(),locator.getLiteralSystemId());
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }
+  
+  public void startParameterEntity(java.lang.String name,
+                                   XMLResourceIdentifier identifier,
+                                   java.lang.String encoding,
+                                   Augmentations augmentations)
+    throws XNIException
+  {
+    // no op
+  }
+  
+  // textDecl already handled
+  
+  public void endParameterEntity(java.lang.String name,
+                                 Augmentations augmentations)
+    throws XNIException  
+  {
+    // no op
+  }
+  public void startExternalSubset(XMLResourceIdentifier resource,Augmentations augmentations)
+    throws XNIException  
+  {
+    // no op
+  }
+  public void endExternalSubset(Augmentations augmentations)
+    throws XNIException  
+  {
+    // no op
+  }  
+  
+  // comment already handled, including suppression during the DTD
+  // processing instruction already handled. NOT currently suppressed during DTD?
+  
+  public void elementDecl(java.lang.String name,
+                          java.lang.String contentModel,
+                          Augmentations augmentations)
+    throws XNIException
+  {
+    //no op
+  }
+  public void startAttlist(java.lang.String elementName,
+                           Augmentations augmentations)
+    throws XNIException
+  {
+    //no op
+  }
+  
+  public void attributeDecl(String elementName,String attributeName, 
+                            java.lang.String type, java.lang.String[] enumeration, 
+                            String defaultType, XMLString defaultValue,
+                            XMLString nonNormalizedDefaultValue, Augmentations augmentations)
+    throws XNIException
+  { 
+    // no op
+  }
+  
+  public void endAttlist(Augmentations augmentations)
+    throws XNIException  
+  {
+    //no op
+  }
+  public void internalEntityDecl(String name, XMLString text, 
+                                 XMLString nonNormalizedText,
+                                 Augmentations augmentations) 
+    throws XNIException
+  {
+    //no op
+  }
+  public void externalEntityDecl(java.lang.String name,
+                                 XMLResourceIdentifier identifier,
+                                 Augmentations augmentations)
+    throws XNIException
+  {
+    //no op
+  }
+  
+  public void unparsedEntityDecl(java.lang.String name,
+                                 XMLResourceIdentifier identifier,
+                                 java.lang.String notation,
+                                 Augmentations augmentations)
+    throws XNIException
+  {
+    // This one's the wnole point of the exercise...
+    try
+    {
+      super.unparsedEntityDecl(name,identifier.getPublicId(),identifier.getLiteralSystemId(),notation);
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }     
+ 
+  public void notationDecl(java.lang.String name,
+                           XMLResourceIdentifier identifier,
+                           Augmentations augmentations)
+    throws XNIException
+  {
+    // no op
+  }
+  public void startConditional(short type,
+                               Augmentations augmentations)
+    throws XNIException
+  {
+    // no op
+  }
+  
+  public void ignoredCharacters(XMLString text, Augmentations augmentations)
+    throws XNIException
+  {
+    // no op
+  }
+  public void endConditional(Augmentations augmentations)
+    throws XNIException
+  {
+    // no op
+  }
+  
+  public void endDTD(Augmentations augmentations)
+    throws XNIException
+  {
+    try
+    {
+      super.endDTD();
+    } 
+    catch(SAXException e)
+    {
+      throw new XNIException(e);
+    }
+  }     
+ 
+  ////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////
+  // %REVIEW% SAX APIs are currently _blocked_ for debugging purposes. We can
+  // re-enable them if/when we fold the XNI support back into the main SAX2DTM
+  ////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////
+  
+ 
+  // Implementation of DTDHandler interface.
+
+  // SAME AS XNI? OR DID WE RETAIN THEM ABOVE FOR OTHER REASONS?
+  //public void notationDecl(String name, String publicId, String systemId)
+  //        throws SAXException
+  // public void unparsedEntityDecl(
+  //        String name, String publicId, String systemId, String notationName)
+  //        throws SAXException
+
+  // Implementation of ContentHandler interface.
+
+  public void setDocumentLocator(org.xml.sax.Locator locator)
+  {
+    throw new RuntimeException(UNEXPECTED+"setDocumentLocator");
+  }
+  public void startDocument() throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"startDocument");
+  }
+  public void endDocument() throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"endDocument");
+  }
+  public void startPrefixMapping(String prefix, String uri)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"startPrefixMapping");
+  }
+  public void endPrefixMapping(String prefix) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"endPrefixMapping");
+  }
+  public void startElement(
+                           String uri, String localName, String qName, org.xml.sax.Attributes attributes)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"startElement");
+  }
+  public void endElement(String uri, String localName, String qName)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"endElement");
+  }
+  public void characters(char ch[], int start, int length) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"characters");
+  }
+  public void ignorableWhitespace(char ch[], int start, int length)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"ignorableWhitespace");
+  }
+  public void processingInstruction(String target, String data)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"processingInstruction");
+  }
+  public void skippedEntity(String name) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"skippedEntity");
+  }
+  
+  // Implementation of SAX error handler
+
+  public void warning(SAXParseException e) throws SAXException
+  {
+    // %REVIEW% Is there anyway to get the JAXP error listener here?
+    throw new SAXException(UNEXPECTED+"Warning: "+e.getMessage());
+  }
+  public void error(SAXParseException e) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"Error: "+e.getMessage());
+  }
+  public void fatalError(SAXParseException e) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"Fatal Error: "+e.getMessage());
+  }
+
+  // Implementation of SAX DeclHandler interface.
+  
+  public void elementDecl(String name, String model) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"elementDecl "+name);
+  }
+  public void attributeDecl(
+                            String eName, String aName, String type, String valueDefault, String value)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"attributeDecl "+aName);
+  }
+  public void internalEntityDecl(String name, String value)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"internalEntityDecl "+name);
+  }
+  public void externalEntityDecl(
+                                 String name, String publicId, String systemId) throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"externalEntityDecl "+name);
+  }
+
+  // Implementation of the LexicalHandler interface.
+  public void startDTD(String name, String publicId, String systemId)
+    throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"startDTD");
+  }
+  public void endDTD() throws SAXException
+  {
+    throw new SAXException(UNEXPECTED+"endDTD");
+  }
+
+} // XNI2DTM
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/XNISource.java b/src/org/apache/xml/dtm/ref/xni2dtm/XNISource.java
new file mode 100644
index 0000000..e630de6
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/XNISource.java
@@ -0,0 +1,326 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The name "Apache Software Foundation" must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission. For written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.sax.SAXSource;
+
+import java.lang.String;
+
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.xerces.xni.parser.XMLDocumentScanner;
+import org.apache.xerces.xni.parser.XMLDocumentSource;
+import org.apache.xerces.xni.parser.XMLInputSource;
+import org.apache.xerces.xni.XMLDocumentHandler;
+import org.apache.xerces.xni.parser.XMLErrorHandler;
+import org.apache.xerces.xni.parser.XMLParserConfiguration;
+
+/**
+ * Acts as an holder for XNI-style Source.
+ * Should be made more compatable with JAXP Source
+ *   (eg, accept JAXP InputSource and convert to XNI?)
+ * Should this be moved to javax.xml.transform?
+ */
+public class XNISource implements Source {
+	XMLDocumentScanner docScanner;
+	XMLDocumentSource eventSource;
+	XMLInputSource xniInputSource;
+	
+	// This should be
+	//	XMLParserConfiguration parserConfiguration;
+	// but the reset() operation is unfortunately _NOT_ part of the
+	// architecture of the Configuration!
+	DOMValidationConfigurationSwipedFromXerces parserConfiguration;
+	
+    /**
+     * If {@link javax.xml.transform.TransformerFactory#getFeature}
+     * returns true when passed this value as an argument,
+     * the Transformer supports Source input of this type.
+     */
+    public static final String FEATURE =
+        "http://org.apache.xml.dtm.ref.xni2dtm.XNISource/feature";
+
+    /**
+     * Zero-argument default constructor.  If this constructor
+     * is used, and no other method is called, the
+     * {@link javax.xml.transform.Transformer}
+     * assumes an empty input tree, with a default root node.
+     */
+    public XNISource() {}
+
+    /**
+     * Create a <code>XNISource</code>, using an {@link org.xml.XNI.XMLReader}
+     * and a XNI InputSource. The {@link javax.xml.transform.Transformer}
+     * or {@link javax.xml.transform.XNI.XNITransformerFactory} will set itself
+     * to be the reader's {@link org.xml.XNI.ContentHandler}, and then will call
+     * reader.parse(inputSource).
+     *
+     * @param reader An XMLReader to be used for the parse. Must also implement
+     * XMLParserConfiguration. (That may make this a non-useful method
+     * as it stands. %REVIEW%.)
+     * @param inputSource A XNI input source reference that must be non-null
+     * and that will be passed to the reader parse method.
+     */
+    public XNISource(XMLDocumentScanner reader, XMLInputSource inputSource) 
+    {
+    	this(reader,(XMLParserConfiguration)reader,reader,inputSource);
+    }
+
+    /**
+     * Create a <code>XNISource</code>, using an {@link org.xml.xni.XMLDocumentScanner}
+     * (which we will send the parse request to), an {@link org.xml.xni.XMLDocumentSource}
+     * (which we will expect the events from) and a XNI InputSource. The first two
+     * are separated because there might be a filtering pipeline between the
+     * scanner and our own immediate source.
+     * 
+     * The {@link javax.xml.transform.Transformer}
+     * or {@link javax.xml.transform.XNI.XNITransformerFactory} will set itself
+     * to be the reader's {@link org.xml.XNI.ContentHandler}, and then will call
+     * reader.parse(inputSource).
+     *
+     * @param reader An XMLReader to be used for the parse.
+     * @param inputSource A XNI input source reference that must be non-null
+     * and that will be passed to the reader parse method.
+     */
+    public XNISource(XMLDocumentScanner reader, 
+    	XMLParserConfiguration parserConfiguration,
+    	XMLDocumentSource eventSource,
+    	XMLInputSource inputSource) 
+    {
+        this.docScanner      = reader;
+        this.eventSource	= eventSource;
+        this.xniInputSource = inputSource;
+        // Sloppy, but XMLParserConfiguration has no reset() operation
+        // and reset _must_ be performed late (eg after setting the
+        // error handler).
+        this.parserConfiguration = (DOMValidationConfigurationSwipedFromXerces)parserConfiguration;
+    }
+
+
+
+    /**
+     * Create a <code>XNISource</code>, using a XNI <code>InputSource</code>.
+     * The {@link javax.xml.transform.Transformer} or
+     * {@link javax.xml.transform.XNI.XNITransformerFactory} creates a
+     * reader via {@link org.xml.XNI.helpers.XMLReaderFactory}
+     * (if setXMLReader is not used), sets itself as
+     * the reader's {@link org.xml.XNI.ContentHandler}, and calls
+     * reader.parse(inputSource).
+     *
+     * @param inputSource An input source reference that must be non-null
+     * and that will be passed to the parse method of the reader.
+     */
+    public XNISource(XMLInputSource inputSource) {
+        this.xniInputSource = inputSource;
+    }
+
+    /**
+	 * Convert SAX source to XNI source (by swiping its input)
+     *
+     * @param inputSource An input source reference that must be non-null
+     * and that will be passed to the parse method of the reader.
+     */
+    public XNISource(SAXSource saxSource) {
+        setInputSource(saxSource.getInputSource());
+    }
+    
+    /**
+	 * Read from SAX-style InputSource
+     *
+     * @param inputSource An input source reference that must be non-null
+     * and that will be passed to the parse method of the reader.
+     */
+    public void setInputSource(org.xml.sax.InputSource saxInputSource) {
+    	if(saxInputSource.getCharacterStream()!=null)
+			this.xniInputSource=new XMLInputSource(
+				saxInputSource.getPublicId(),
+				saxInputSource.getSystemId(),
+				null,
+				saxInputSource.getCharacterStream(),
+				saxInputSource.getEncoding()
+				);
+    	else if(saxInputSource.getByteStream()!=null)
+			this.xniInputSource=new XMLInputSource(
+				saxInputSource.getPublicId(),
+				saxInputSource.getSystemId(),
+				null,
+				saxInputSource.getByteStream(),
+				saxInputSource.getEncoding()
+				);
+    	else 
+			this.xniInputSource=new XMLInputSource(
+				saxInputSource.getPublicId(),
+				saxInputSource.getSystemId(),
+				null);
+    }
+
+    /**
+     * Set the XMLReader to be used for the Source.
+     * Be sure to set the document handler _after_ this.
+     * %REVIEW%: Should we save and reassert that value?
+     *
+     * @param reader A valid XMLReader or XMLFilter reference.
+     */
+    public void setXMLReader(org.apache.xerces.xni.parser.XMLDocumentScanner reader) {
+        this.docScanner = reader;
+    }
+
+    /**
+     * Set the XNI InputSource to be used for the Source.
+     *
+     * @param inputSource A valid InputSource reference.
+     */
+    public void setInputSource(XMLInputSource inputSource) {
+        this.xniInputSource = inputSource;
+    }
+
+    /**
+     * Get the XNI InputSource to be used for the Source.
+     *
+     * @return A valid InputSource reference, or null.
+     */
+    public XMLInputSource getInputSource() {
+        return xniInputSource;
+    }
+
+    /**
+     * Set the XNI DocumentHandler to receive our output. Note that
+     * this ties to the event source, which is not necessarily the
+     * scanner.
+     *
+     * @param inputSource A valid XMLDocumentHandler reference.
+     */
+	public void setDocumentHandler(XMLDocumentHandler target)
+	{
+			eventSource.setDocumentHandler(target);
+	}
+	
+    /**
+     * Set the XNI ErrorHandler to receive our output. Note that
+     * this ties to the parser configuration.
+     *
+     * @param inputSource A valid XMLDocumentHandler reference.
+     */
+	public void setErrorHandler(XMLErrorHandler target)
+	{
+			parserConfiguration.setErrorHandler(target);
+	}
+	
+    /**
+     * Start/resume parsing.
+     * Note that this gets passed to the scanner, which is not necessarily
+     * the immediate event source.
+     *
+     * @param toCompletion False for incremental parse, true to read the
+     * rest of the document.
+     */
+	public void reset() throws java.io.IOException
+	{
+			parserConfiguration.reset();	
+	}
+
+    /**
+     * Start/resume parsing.
+     * Note that this gets passed to the scanner, which is not necessarily
+     * the immediate event source.
+     *
+     * @param toCompletion False for incremental parse, true to read the
+     * rest of the document.
+     */
+	public void scanDocument(boolean toCompletion) throws java.io.IOException
+	{
+			docScanner.scanDocument(toCompletion);	
+	}
+
+
+    /**
+     * Set the system identifier for this Source.  If an input source
+     * has already been set, it will set the system ID or that
+     * input source, otherwise it will create a new input source.
+     *
+     * <p>The system identifier is optional if there is a byte stream
+     * or a character stream, but it is still useful to provide one,
+     * since the application can use it to resolve relative URIs
+     * and can include it in error messages and warnings (the parser
+     * will attempt to open a connection to the URI only if
+     * no byte stream or character stream is specified).</p>
+     *
+     * @param systemId The system identifier as a URI string.
+     */
+    public void setSystemId(String systemId) {
+
+        if (null == xniInputSource) {
+            xniInputSource = new XMLInputSource(null,systemId,null);
+        } else {
+            xniInputSource.setSystemId(systemId);
+        }
+    }
+
+    /**
+     * Get the base ID (URI or system ID) from where URIs
+     * will be resolved.
+     *
+     * @return Base URL for the Source, or null.
+     */
+    public String getSystemId() {
+
+        return (null != xniInputSource)
+               ? xniInputSource.getSystemId()
+               : null;
+    }
+}
+
diff --git a/src/org/apache/xml/dtm/ref/xni2dtm/XPath2Type.java b/src/org/apache/xml/dtm/ref/xni2dtm/XPath2Type.java
new file mode 100644
index 0000000..9f59f5f
--- /dev/null
+++ b/src/org/apache/xml/dtm/ref/xni2dtm/XPath2Type.java
@@ -0,0 +1,656 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.dtm.ref.xni2dtm;
+
+import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
+import org.apache.xerces.impl.dv.ValidatedInfo;
+import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
+import org.apache.xerces.impl.validation.ValidationState;
+import org.apache.xerces.impl.xs.XSTypeDecl;
+import org.apache.xerces.impl.xs.psvi.XSSimpleTypeDefinition;
+import org.apache.xerces.impl.xs.psvi.XSTypeDefinition;
+import org.apache.xerces.xni.NamespaceContext;
+import org.apache.xerces.xni.psvi.ItemPSVI;
+import org.apache.xml.dtm.DTMSequence;
+
+  /** The full XNI ItemPSVI is far too heavy-weight for
+   * our needs. But their XSTypeDecl isn't quite heavy enough; it gives
+   * us the actual member type, but that may be anonymous... so to get
+   * what XPath2 considers the proper typename, we need to examine
+   * additional fields as well. This class is an attempt to compromise by
+   * resolving the typename and storing that alongside the member type.
+   * 
+   * A more efficient solution undoubtedly exists. But since XNI's PSVI
+   * APIs are still in flux, and since I'm just trying to get an initial
+   * demo running, this will suffice for now.
+   * %REVIEW% periodically!
+   * */
+public class XPath2Type
+{
+  	public XSTypeDefinition m_xniType;
+  	public String m_namespace;
+  	public String m_localName;
+  	
+  	/** Constructor for our internal type representation
+  	 *   We will extract the low-level XSTypeDecl for the Member Type,
+  	 *   and determine the proper namespace and localname. Other data
+  	 *   can (hopefully) be GC'd after we're done. This is still NOT
+  	 *   a lightweight beast.
+  	 * 
+  	 * @param psvi XNI Post-Schema-Validation Infoset annotation.
+  	 * @param isAttr True iff we're defining type for an attribute.
+  	 * */
+  	public XPath2Type(ItemPSVI psvi, boolean isAttr)
+  	{
+  		// First get the member type.
+  		m_xniType= (psvi==null) ? null : psvi.getTypeDefinition();
+  	
+  		// Now resolve the typename.
+  		// There are some quibbles about algorithm; see comments on
+  		// the resolve methods.
+  		heavyResolveTypeName(psvi,isAttr);
+  	}
+  	  	
+  	/** Constructor for Xerces workaround
+	 * (Xerces isn't reminding us of type at the time it provides
+	 * validity, so XNI2DTM is passing that data around via a stack.
+	 * This is a kluge and I hope to convince Xerces to fix it.)
+  	 * 
+  	 * @param psvi XNI Post-Schema-Validation Infoset annotation.
+  	 * @param isAttr True iff we're defining type for an attribute.
+  	 * */
+  	public XPath2Type(ItemPSVI psvi, XSSimpleTypeDefinition member, XSTypeDefinition type,  boolean isAttr)
+  	{
+  		// First get the member type.
+  		m_xniType= (psvi==null) ? null : type;
+  	
+  		// Now resolve the typename.
+  		// There are some quibbles about algorithm; see comments on
+  		// the resolve methods.
+  		heavyResolveTypeName(psvi,member,type,isAttr);
+  	}
+
+  	/** Internal constructor to support getItemType and 
+  	 * AbstractSchema.lookUpType
+  	 * @param psvi XNI Post-Schema-Validation Infoset annotation.
+  	 * @param isAttr True iff we're defining type for an attribute.
+  	 * */
+  	public XPath2Type(XSTypeDefinition itemType, String namespace, String localName)
+  	{
+  		m_xniType=itemType;
+  		m_namespace=namespace;
+  		m_localName=localName;
+  	}
+  	
+  	/** Identity needs to be defined so we can do sparse storage.
+  	 * %REVIEW% I'm not sure all three fields need to be checked, but...
+  	 * */
+  	public boolean equals(XPath2Type other)
+  	{
+		// Could cache hashCode()'s result and use that to accelerate
+		// doesn't-equal testing at the cost of some storage and
+		// slowing down does-equal tests. Not convinced it's useful here.
+		// %REVIEW%
+  		return (m_xniType==other.m_xniType ||
+  			m_xniType!=null && m_xniType.equals(other.m_xniType)) &&
+  			// These two won't be null
+  			m_localName.equals(other.m_localName) && 
+  			m_namespace.equals(other.m_namespace);
+  	}
+  	  	
+  	/** Identity needs to be defined so we can do sparse storage.
+  	 * %REVIEW% I'm not sure all three fields need to be checked, but...
+  	 * */
+  	public int hashCode()
+  	{
+  		// Could cache hashCode(). See discussion in equals().
+  		// %REVIEW%
+  		return m_namespace.hashCode()+m_localName.hashCode()+
+  			(m_xniType==null ? 0 : m_xniType.hashCode());
+  	}
+  	
+  	public String getTargetNamespace() {return m_namespace;}
+  	public String getTypeName() {return m_localName;}
+  	
+  	public boolean derivedFrom(String namespace,String localname)
+  	{
+  		if(m_xniType instanceof XSTypeDecl)
+	  		return ((XSTypeDecl)m_xniType).derivedFrom(namespace,localname);
+	  	else
+	  	{
+	  		// Fallback in case no PSVI info was passed in: exact match
+	  		// (it's got to be the correct xsi:any*Type).
+		  	return(m_localName.equals(localname) && m_namespace.equals(namespace));
+	  	}
+  	}
+  	
+  /** Broken out into a subroutine so I can use it for debugging purposes.
+   * This logic is adapted from the Xerces SimpleTypeUsage.validateString() example.
+   * 
+   * %REVIEW% May be more efficient to fold it back in.
+   * 
+   * NOTE: Typed value depends on context information -- for example, a
+   * QName must be interpreted w/r/t a specific Namespace context. It's
+   * the caller's responisibility to pass down that information, since only
+   * the caller knows which context this operation is being performed in.
+   * 
+   * %REVIEW% Currently NS context comes down as a SAX accessor. Should we be
+   * able to take a DTM node directly as context? 
+   * 
+   * @param textValue Text content to be interpreted
+   * @param nsctxt SAX namespace context, which will be proxied as XNI.
+   * @return DTM_XSequence containing one or more Java values, as appropriate
+   *   to the Built-In Type we have inherited from -- or null if no such 
+   *   mapping exists (eg, if actualType was complex)
+   * */         
+  public DTMSequence typedValue(String textvalue, org.xml.sax.helpers.NamespaceSupport nsctxt)
+  {
+    Object value;
+    DTM_XSequence seq=null;
+
+    if(m_xniType instanceof XSSimpleTypeDefinition)
+    {           
+      //create an instance of 'ValidatedInfo' to get back information 
+      //(like actual value, normalizedValue etc..)after content is validated.
+      ValidatedInfo validatedInfo = new ValidatedInfo(); // %REVIEW% Can we reuse???
+
+      //get proper validation context. This is very important, since
+      // it's where we get data for resolving prefixes (in QNames),
+      // known IDs (for IDREFs and ID conflicts), entities, etc.
+      //Validation context passed is generally different while 
+      // validating content and creating simple type (applyFacets)
+      ValidationState validationState = new ValidationState();
+      if(nsctxt!=null)
+	      validationState.setNamespaceSupport(new XPath2NamespaceSupport(nsctxt));
+
+      // This may need to be bound to additional data using:
+      //validationState.setSymbolTable(....);
+      //validationState.setFacetChecking(...);
+      //validationState.setExtraChecking(...);        
+
+      // Validate and parse the string
+      try{
+        ((XSSimpleTypeDecl)m_xniType).validate(textvalue, validationState, validatedInfo);
+      } catch(InvalidDatatypeValueException ex){
+		// %REVIEW% Won't happen in prototype, where I'm only revalidating
+		// existing data. _WILL_ happen in production, when we start generating
+		// new typed data. Needs to be handled better at that time...
+        System.err.println(ex.getMessage());
+        ex.printStackTrace(System.err);
+      }
+
+      //now 'validatedInfo' object contains information
+
+      // for number types (decimal, double, float, and types derived from them),
+      // Object return is BigDecimal, Double, Float respectively.
+      // Boolean is handled similarly.
+      // Some types (string and derived) just return the string itself.
+      value = validatedInfo.actualValue;
+
+      //The normalized value of a string type
+      // (Should we check for stings and return this instead?)
+      String normalizedValue = validatedInfo.normalizedValue ;
+
+      // If the type is a union type, then the member type which
+      // actually validated the string value will be:
+      // XSSimpleType memberType = validatedInfo.memberType ;
+
+      // %REVIEW% I presume this handles lists by returning arrays...?
+                
+      seq=new DTM_XSequence(value,this);
+    }
+        
+    return seq==null ? DTMSequence.EMPTY : seq;
+  }
+  
+  /** @return individual element type, if this is a list-of; else null.
+   * %REVIEW% -- else self?
+   * */
+  public XPath2Type getItemType() 
+  {
+  	if(m_xniType instanceof XSSimpleTypeDefinition)
+  	{
+  		XSTypeDefinition itemType=((XSSimpleTypeDefinition)m_xniType).getItemType();
+  		if(itemType!=null)
+	 	 	return new XPath2Type(
+ 		 		itemType,
+ 		 		m_xniType.getNamespace(),
+ 	 			m_xniType.getName());
+  	}
+ 	return null;
+  }
+
+  /** Implementation of the XPath2 type-name resolution algorithm
+   * (data model 3.5). 
+   * 
+   * Code donated by Sandy Gao, using the new
+   * Heavy-Weight PSVI interfaces.
+   * Fractionated to deal with validity and type info not being
+   * simultaneously available in current Xerces.
+   * 
+   * @param psvi  the psvi information for the current node
+   * @param attr false for element (fallback is xs:anyType)
+   *              true for attribute (fallback is xs:anySimpleType)
+   * */  
+  protected void heavyResolveTypeName(ItemPSVI psvi, XSSimpleTypeDefinition member, XSTypeDefinition type, boolean attr)
+  {
+  	/* Not compatable with old light-weight schema APIs
+  	*/
+        // check whether the node is valid
+        if (psvi == null ||
+            psvi.getValidity() != ItemPSVI.VALIDITY_VALID) {
+            // if the node is not valid, then return xs:anyType
+            m_namespace = "http://www.w3.org/2001/XMLSchema";
+            m_localName = attr ? "anySimpleType" : "anyType";
+            return;
+        }
+        
+        // try provided member type definition, and return its name
+        if (member != null) {
+            m_namespace = member.getNamespace();
+            m_localName = member.getName();
+            return;
+        }
+        
+        // try provided type definition, and return its name
+        if (type != null) {
+            m_namespace = type.getNamespace();
+            m_localName = type.getName();
+            return;
+        }
+        
+        
+  	// Member type definitions promised to be available;
+  	// can't proceed to check names independently
+
+        // all failed, return xs:anyType
+        m_namespace = "http://www.w3.org/2001/XMLSchema";
+        m_localName = attr ? "anySimpleType" : "anyType";
+        return;
+  // throw new java.lang.UnsupportedOperationException("Xerces Heavyweight PSVI not yet avaialble"); /**/       
+  }
+
+  /** Implementation of the XPath2 type-name resolution algorithm
+   * (data model 3.5). 
+   * 
+   * Code donated by Sandy Gao, using the new
+   * Heavy-Weight PSVI interfaces
+   * This one works *ONLY* if type and validity are all known in the same
+   * PSVI, which is not the case in current Xerces.
+   * 
+   * @param psvi  the psvi information for the current node
+   * @param attr false for element (fallback is xs:anyType)
+   *              true for attribute (fallback is xs:anySimpleType)
+   * */  
+  protected void heavyResolveTypeName(ItemPSVI psvi, boolean attr)
+  {
+  	heavyResolveTypeName(psvi,psvi.getMemberTypeDefinition(),
+		psvi.getTypeDefinition(), attr);
+  }
+  
+  /** Modification of the XPath2 type-name resolution algorithm
+   * to reflect Sandy Gao's concerns about the official version
+   * not tolerating processors that implement the "lightweight" version
+   * of PSVI.
+   * 
+   * Code donated by Sandy Gao, using the new
+   * Heavy-Weight PSVI interfaces
+   * 
+   * @param psvi  the psvi information for the current node
+   * @param attr false for element (fallback is xs:anyType)
+   *              true for attribute (fallback is xs:anySimpleType)
+   * */  
+  protected void proposedHeavyResolveTypeName(ItemPSVI psvi, boolean attr)
+  {
+  	/* Not compatable with old light-weight schema APIs
+  	*/
+
+  	// NAME OF THIS CONSTANT IS IN FLUX
+  	int VALID=ItemPSVI.VALIDITY_VALID;
+  	//int VALID=ItemPSVI.VALID_VALIDITY;
+  	
+        // check whether the node is valid
+        if (psvi == null ||
+            psvi.getValidity() != VALID) {
+            // if the node is not valid, then return xs:anyType
+            m_namespace = "http://www.w3.org/2001/XMLSchema";
+	        m_localName = attr ? "anySimpleType" : "anyType";
+            return;
+        }
+        
+        // try to get the member type definition, and return its name
+        XSSimpleTypeDefinition member = psvi.getMemberTypeDefinition();
+        if (member != null && member.getName() != null) {
+            m_namespace = member.getNamespace();
+            m_localName = member.getName();
+            return;
+        }
+        
+        // try to get the type definition, and return its name
+        XSTypeDefinition type = psvi.getTypeDefinition();
+        if (type != null && type.getName() != null) {
+            m_namespace = type.getNamespace();
+            m_localName = type.getName();
+            return;
+        }
+        
+  	// Member type definitions promised to be available;
+  	// can't proceed to check names independently
+
+        // all failed, return xs:anyType
+        m_namespace = "http://www.w3.org/2001/XMLSchema";
+        m_localName = attr ? "anySimpleType" : "anyType";
+        return;
+  // throw new java.lang.UnsupportedOperationException("Xerces Heavyweight PSVI not yet avaialble"); /**/       
+  }
+  
+  /** Attempt to write a simplified version of the type resolution
+   * algorithm (data model 3.5) using only the Light-Weight PSVI
+   * interfaces previously supported in Xerces (which I believe will be
+   * phased out when heavyweight come into play).
+   * 
+   * Based on code donated by Sandy Gao.
+   * 
+   * @param psvi  the psvi information for the current node
+   * @param ret   a String array with size 2
+   *              index 0 is used to return the namespace name;
+   *              index 1 is used to return the local name.
+   * @param attr false for element (fallback is xs:anyType)
+   *              true for attribute (fallback is xs:anySimpleType)
+   * */  
+  protected void lightResolveTypeName(ItemPSVI psvi, boolean attr)
+  {
+  	/* Not compatable with new heavy-weight schema APIs
+  	//
+  	
+  	int VALID=ItemPSVI.VALID_VALIDITY;
+  	
+        // check whether the node is valid
+        if (psvi == null ||
+            psvi.getValidity() != VALID) {
+            // if the node is not valid, then return xs:anyType
+            m_namespace = "http://www.w3.org/2001/XMLSchema";
+            m_localName = attr ? "anySimpleType" : "anyType";
+            return;
+        }
+        
+	  	// Member type definitions promised NOT to be available;
+ 	 	// proceed to check names independently
+
+		// Need the second test, apparently
+        if (!psvi.isMemberTypeAnonymous() && null!=psvi.getMemberTypeName() ) {
+            m_namespace = psvi.getMemberTypeNamespace();
+            m_localName = psvi.getMemberTypeName();
+            return;
+        }
+        
+		// Need the second test, apparently
+        if (!psvi.isTypeAnonymous() && null!=psvi.getTypeName()) {
+            m_namespace = psvi.getTypeNamespace();
+            m_localName = psvi.getTypeName();
+            return;
+        }
+        
+        // all failed, return xs:anyType
+        m_namespace = "http://www.w3.org/2001/XMLSchema";
+        m_localName = attr ? "anySimpleType" : "anyType";
+        return;
+  */ throw new java.lang.UnsupportedOperationException("Xerces Lightweight PSVI phased out"); /**/
+  }
+  
+  
+  //---------------------------------------------------------------------
+  /** Bridge from Xalan/SAX namespace context to XNI namespace context
+   */
+  class XPath2NamespaceSupport 
+    extends org.apache.xerces.util.NamespaceSupport
+  {
+	org.xml.sax.helpers.NamespaceSupport saxNamespaceSupport;
+
+    /** Default constructor, not useful in this wrapper. */
+    public XPath2NamespaceSupport() {
+		throw new UnsupportedOperationException("Wrong c'tor call");    	
+    } // <init>()
+
+    /** 
+     * Constructs a namespace context object and initializes it with
+     * the prefixes declared in the specified context. Not useful in this
+     * wrapper.
+     */
+    public XPath2NamespaceSupport(org.apache.xerces.xni.NamespaceContext context) {
+		throw new UnsupportedOperationException("Wrong c'tor call");    	
+    } // <init>(xni.NamespaceContext)
+    
+    /** 
+     * Constructs a namespace context object and initializes it with
+     * a SAX NamespaceSupport object. Use this c'tor.
+     * */
+    public XPath2NamespaceSupport(org.xml.sax.helpers.NamespaceSupport saxNS) {
+		saxNamespaceSupport=saxNS;
+    } // <init>(sax.helpers.NamespaceSupport)
+    
+    //
+    // Public methods
+    //
+
+    // context management
+    
+    /**
+     * Reset this Namespace support object for reuse.
+     *
+     * <p>It is necessary to invoke this method before reusing the
+     * Namespace support object for a new session.</p>
+     */
+    public void reset(org.apache.xerces.util.SymbolTable symbolTable) {
+    	// no-op
+    } // reset(SymbolTable)
+
+    /**
+     * Start a new Namespace context.
+     * <p>
+     * Normally, you should push a new context at the beginning
+     * of each XML element: the new context will automatically inherit
+     * the declarations of its parent context, but it will also keep
+     * track of which declarations were made within this context.
+     * <p>
+     * The Namespace support object always starts with a base context
+     * already in force: in this context, only the "xml" prefix is
+     * declared.
+     *
+     * @see #popContext
+     */
+    public void pushContext() {
+    	// I don't know if this will ever be used during validation...
+    	saxNamespaceSupport.pushContext();
+    } // pushContext()
+
+
+    /**
+     * Revert to the previous Namespace context.
+     * <p>
+     * Normally, you should pop the context at the end of each
+     * XML element.  After popping the context, all Namespace prefix
+     * mappings that were previously in force are restored.
+     * <p>
+     * You must not attempt to declare additional Namespace
+     * prefixes after popping a context, unless you push another
+     * context first.
+     *
+     * @see #pushContext
+     */
+    public void popContext() {
+    	// I don't know if this will ever be used during validation...
+    	saxNamespaceSupport.popContext();
+    } // popContext()
+
+    // operations within a context.
+
+    /**
+     * Declare a Namespace prefix.
+     * <p>
+     * This method declares a prefix in the current Namespace
+     * context; the prefix will remain in force until this context
+     * is popped, unless it is shadowed in a descendant context.
+     * <p>
+     * To declare a default Namespace, use the empty string.  The
+     * prefix must not be "xml" or "xmlns".
+     * <p>
+     * Note that you must <em>not</em> declare a prefix after
+     * you've pushed and popped another Namespace.
+     *
+     * @param prefix The prefix to declare, or null for the empty
+     *        string.
+     * @param uri The Namespace URI to associate with the prefix.
+     *
+     * @return true if the prefix was legal, false otherwise
+     *
+     * @see #getURI
+     * @see #getDeclaredPrefixAt
+     */
+    public boolean declarePrefix(String prefix, String uri) {
+    	// I don't know if this will ever be used during validation...
+    	return saxNamespaceSupport.declarePrefix(prefix,uri);
+    } // declarePrefix(String,String):boolean
+
+    /**
+     * Look up a prefix and get the currently-mapped Namespace URI.
+     * <p>
+     * This method looks up the prefix in the current context.
+     * Use the empty string ("") for the default Namespace.
+     *
+     * @param prefix The prefix to look up.
+     *
+     * @return The associated Namespace URI, or null if the prefix
+     *         is undeclared in this context.
+     *
+     * @see #getDeclaredPrefixAt
+     */
+    public String getURI(String prefix) {
+    	return saxNamespaceSupport.getURI(prefix);
+    } // getURI(String):String
+
+
+
+    /**
+     * Look up a namespace URI and get one of the mapped prefix.
+     * <p>
+     * This method looks up the namespace URI in the current context.
+     *
+     * @param uri The namespace URI to look up.
+     *
+     * @return one of the associated prefixes, or null if the uri
+     *         does not map to any prefix.
+     *
+     * @see #getPrefix
+     */
+    public String getPrefix(String uri) {
+    	return saxNamespaceSupport.getPrefix(uri);
+    } // getURI(String):String
+
+
+    /**
+     * Return a count of all prefixes currently declared, including
+     * the default prefix if bound.
+     */
+    public int getDeclaredPrefixCount() {
+    	java.util.Enumeration e=saxNamespaceSupport.getDeclaredPrefixes();
+		int count=0;
+		while(e.hasMoreElements())
+		{
+			++count;
+			e.nextElement();
+		}
+		return count;
+    } // getDeclaredPrefixCount():int
+
+    /** 
+     * Returns the prefix at the specified index in the current context.
+     * %REVIEW% Massively inefficient in this implementation.
+     */
+    public String getDeclaredPrefixAt(int index) {
+    	java.util.Enumeration e=saxNamespaceSupport.getDeclaredPrefixes();
+    	String result=null;
+		for(; index>=0;--index)
+		{
+			if(e.hasMoreElements())
+				result=(String)e.nextElement();
+			else
+				return null;
+		}
+		return result;
+    } // getDeclaredPrefixAt(int):String
+
+    /**
+     * Returns the parent namespace context or null if there is no
+     * parent context. The total depth of the namespace contexts 
+     * matches the element depth in the document.
+     * <p>
+     * <strong>Note:</strong> This method <em>may</em> return the same 
+     * NamespaceContext object reference. The caller is responsible for
+     * saving the declared prefix mappings before calling this method.
+     */
+    public NamespaceContext getParentContext() {
+    	// I suppose I could construct a new XPath2NamespaceSupport
+    	// wrapped around the SAX parent context. I'd rather not
+    	// unless I must.
+		throw new UnsupportedOperationException("Not supported; involves further crossing XNI/SAX boundaries");    	
+    } // getParentContext():NamespaceContext
+
+  } // class XPath2NamespaceSupport
+  
+} // XPath2Type
+
diff --git a/src/org/apache/xml/utils/CharacterBlockEnumeration.java b/src/org/apache/xml/utils/CharacterBlockEnumeration.java
new file mode 100644
index 0000000..9e5872d
--- /dev/null
+++ b/src/org/apache/xml/utils/CharacterBlockEnumeration.java
@@ -0,0 +1,253 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.xml.utils;
+
+/** CharacterBlockEnumeration yields a series of {char[], int, int} triplets.
+ * Its primary use is returning a low-level representation of text scattered
+ * across multiple storage units, eg one or more FastStringBuffer "chunks",
+ * so they can be processed without first converting them to a single Java
+ * String or StringBuffer.
+ * 
+ * Note that the values are displayed on this object rather than being
+ * returned as elements as in the standard Java Enumeration
+ * When constructed, the CharacterBlockEnumeration will immediately
+ * display the first available set of values;  hasMoreElements() can be
+ * used to test whether another set is available, and nextElement() can
+ * be used to step to the next set.
+ * 
+ * This class directly implements the basic functionality for a single 
+ * string or character array; it can be subclassed to handle non-contiguous
+ * types such as FastStringBuffer. Obviously, in those cases it is the user's
+ * responsibility not to alter the data structure while it is being
+ * enumerated, except in ways that may (or may not) be explicitly permitted
+ * by those specific implementation classes. Even for this simple version,
+ * alterations to the source after enumeration begins are not guaranteed 
+ * to be correctly reflected in the enumerated view.
+ * 
+ * %REVIEW% An argument can be made for making this
+ * an interface. Since it's a transient, I'm not sure the extra fields
+ * are really enough of a nuisance to justify doing so.
+ * */
+public class CharacterBlockEnumeration 
+// implements java.util.Enumeration, but see nextElement's comments
+{
+	protected char[] _chars=null;
+	protected int _start;
+	protected int _length;
+	protected String _string=null;
+	
+	static final protected char[] EMPTY=new char[0];
+	
+	/** Create an empty enumeration. */
+	public CharacterBlockEnumeration()
+	{
+	}
+	
+	/** Construct a CharacterBlockEnumeration to represent the content
+	 * of a Java string.
+	 * 
+	 * @param s The String whose content is to be returned.
+	 * */
+	public CharacterBlockEnumeration(String s)
+	{
+		_string=s;
+		_length=s.length();
+	}
+	
+	/** Construct a CharacterBlockEnumeration to represent part of the content
+	 * of a Java string.
+	 * 
+	 * @param s The String whose content is to be returned.
+	 * @param start Starting offset of the substring. If greater than
+	 *   or equal to the length of the string, we will deliver zero characters
+	 * @param length Number of characters in the substring. This will be
+	 *   truncated to not exceed the length of the string.
+	 * */
+	public CharacterBlockEnumeration(String s, int start, int length)
+	{
+		_string=s;
+		int l=s.length();
+		if(start<=l)
+		{
+			_start=start;
+			int max=l-start;
+			_length=(length<max) ? length : max;
+		}
+	}
+	
+	/** Construct a CharacterBlockEnumeration to represent the content
+	 * of a Java character array
+	 * 
+	 * @param ch The char array whose content is to be returned.
+	 * */
+	public CharacterBlockEnumeration(char[] ch)
+	{
+		_chars=ch;
+		_length=ch.length;
+	}
+
+
+	/** Construct a CharacterBlockEnumeration to represent part of the content
+	 * of a Java character array
+	 * 
+	 * @param ch The char array whose content is to be returned.
+	 * @param start Starting offset of the substring. If greater than
+	 *   or equal to the length of the array, we will deliver zero characters
+	 * @param length Number of characters in the substring. This will be
+	 *   truncated to not exceed the length of the array.
+	 * */
+	public CharacterBlockEnumeration(char[] ch, int start, int length)
+	{
+		_chars=ch;
+		int l=ch.length;
+		if(start<=l)
+		{
+			_start=start;
+			int max=l-start;
+			_length=(length<max) ? length : max;
+		}
+	}
+	
+	/** @return true if another character block can be accessed by calling
+	 * nextElement()
+	 */
+	public boolean hasMoreElements()
+	{
+		return false;
+	}
+	
+	/** Advance to the next character block. 
+	 * 
+	 * @returns either this CharacterBlockEnumeration object (as a
+	 * transient accessor to the "element") or null if no more elements are available.
+	 * This is a bit of a kluge, but it allows us to claim that we
+	 * implement the Java Enumeration interface if we want to do so, and
+	 * it seems to be as good or bad as any other return value.
+	 * */
+	public Object nextElement()
+	{
+		_chars=null;
+		_string=null;
+		return null;
+	}
+	
+	
+	/** @return the starting offset in the current block's character array
+	 * */
+	public int getStart()
+	{
+		return _start;
+	}
+
+	/** @return the length of the the current block
+	 * */
+	public int getLength()
+	{
+		return _length;
+	}
+
+	/** 
+	 * @return the current block's character array. Data will begin at
+	 * offset {start}.
+	 * */
+	public char[] getChars()
+	{
+		// Implementation note for this particular version of the class: 
+		// In a JVM which optimizes String.toCharArray() by deferring 
+		// dissociation of the array from the String (sharing storage until
+		// and unless the user attempts to modify the array), this may be 
+		// significantly faster than the version which returns the selected 
+		// characters into a user-supplied array. In others, it may be 
+		// significantly slower. 
+
+		if(_chars==null)
+		{
+			if(_string!=null)
+				_chars=_string.toCharArray();
+			else
+				_chars=EMPTY;
+		}
+		return _chars;		
+	}
+
+	/** @param target A char[] to be copied into. If a buffer is not supplied
+	 * we will create one.
+	 *
+	 * @param targetStart Offset in the target at which copying should begin.
+	 * 
+	 * @return the buffer, filled with {length} characters starting at offset
+	 * {targetStart}. Characters before or after that block should be unaffected.
+	 * */
+	public char[] getChars(char[] target, int targetStart)
+	{
+		// See performance issues discussion above. But note that they
+		// apply only to this version of the class, not necessarily to
+		// subclasses such as the FSB version.
+		if(target==null)
+			target=new char[targetStart+_length];
+			
+		if(_chars==null)
+			_string.getChars(_start,_start+_length,
+				target,targetStart);
+		else
+			System.arraycopy(_chars,_start,target,targetStart,_length);
+			
+		return target;
+	}
+	
+}
+
diff --git a/src/org/apache/xml/utils/DateTimeObj.java b/src/org/apache/xml/utils/DateTimeObj.java
new file mode 100644
index 0000000..061c148
--- /dev/null
+++ b/src/org/apache/xml/utils/DateTimeObj.java
@@ -0,0 +1,1101 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.xml.utils;
+
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.xml.transform.TransformerException;
+import org.apache.xml.dtm.XType;
+
+/**
+ * <meta name="usage" content="general"/>
+ * This class contains a duration object.
+ */
+
+public class DateTimeObj
+{
+    // Datetime formats (era and zone handled separately).
+    public static final String dt1 = "yyyy-MM-dd'T'HH:mm:ss.ss";
+    public static final String dt2 = "yyyy-MM-dd'T'HH:mm:ss";
+    public static final String d = "yyyy-MM-dd";
+    public static final String gym = "yyyy-MM";
+    public static final String gy = "yyyy";
+    public static final String gmd = "MM-dd";
+    public static final String gm = "MM";
+    public static final String gd = "dd";
+    public static final String t1 = "HH:mm:ss.ss";
+    public static final String t2 = "HH:mm:ss";
+    
+    private int m_year;
+    private int m_month;
+    private int m_day;
+    private int m_T;
+    private int m_hour;
+    private int m_minute;
+    private double m_second;
+    private String m_zone;
+    private Date m_date;
+    private String m_dateTime;
+    private int m_size;
+    private boolean m_signed = false;
+    
+    /**
+     * The duration string must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnD, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public DateTimeObj(String dateTimeIn) throws TransformerException
+    {
+    	this(dateTimeIn, new String[]{dt2});
+    }
+    
+    public DateTimeObj(String dateTimeIn, String[] formatsIn) throws TransformerException
+    {
+    	try {
+    	
+    	int i;
+    	
+    	m_size = dateTimeIn.length();
+    	// Remember our Time separator
+    	m_T = (i = dateTimeIn.indexOf("T")) != -1 ? i : m_size ;
+    	// boundary check??
+      String[] edz = getEraDatetimeZone(dateTimeIn);
+      m_signed = edz[0].length() >0;
+      m_dateTime = edz[1];
+      m_zone = edz[2];
+      if (m_dateTime == null || m_zone == null) 
+        return;
+                    
+      m_date = testFormats(m_dateTime, formatsIn);
+      int index = dateTimeIn.indexOf('.');
+    	double dec = (index <0) ? 0 :Double.parseDouble(m_dateTime.substring(index));
+    	
+      SimpleDateFormat dateFormat = new SimpleDateFormat(dt1);
+      dateFormat.setLenient(false);
+      Calendar cal = Calendar.getInstance();
+      cal.setTime(m_date);
+      m_year = cal.get(Calendar.YEAR);
+      m_month = cal.get(Calendar.MONTH) + 1; // Calendar returns months starting at 0... 
+      m_day = cal.get(Calendar.DATE);
+      m_hour = cal.get(Calendar.HOUR);
+      m_minute = cal.get(Calendar.MINUTE);
+      m_second = (index <0) ? cal.get(Calendar.SECOND) 
+                            : cal.get(Calendar.SECOND) + Double.parseDouble(m_dateTime.substring(index)); 
+    	}
+    	catch (Exception ex)
+    	{
+    		throw new TransformerException(ex);
+    	}  
+                  
+    }
+    
+    public DateTimeObj(Date date, String formatOut) throws TransformerException
+    {
+      //m_zone = date.getTimezoneOffset();
+      SimpleDateFormat dateFormat = new SimpleDateFormat(formatOut);
+      dateFormat.setLenient(false);
+      m_dateTime = dateFormat.format(date);
+      m_date = date;
+
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(date);
+
+      m_signed = (cal.get(Calendar.ERA) == GregorianCalendar.BC);
+      m_year = cal.get(Calendar.YEAR);
+     // String monthStr = m_dateTime.substring(5, 7);
+     // m_month = Integer.valueOf(monthStr).intValue();
+     // String dayStr = m_dateTime.substring(8, 10);
+     // m_day = Integer.valueOf(dayStr).intValue();
+      m_month = cal.get(Calendar.MONTH) + 1;
+      m_day = cal.get(Calendar.DATE); 
+      m_hour = cal.get(Calendar.HOUR);
+      m_minute = cal.get(Calendar.MINUTE);
+      m_second = cal.get(Calendar.SECOND);
+
+      //      m_year = date.getYear();
+      // m_month = date.getMonth();
+      //      m_day = date.getDay();
+      //      m_hour = date.getHours();
+      //      m_minute = date.getMinutes();
+      //      m_second = date.getSeconds(); 
+    }
+
+	/** Added by JJK to support Xerces' stopgap internal representation
+	 * as delivered through DTMSequence. We should work with them to
+	 * converge on a shared time/date/duration object compatable with
+	 * the schema spec.
+	 * 
+	 * %BUG% They return some bogus fields due to normalization
+	 * side-effects (they use a pseudodate of 2000/1/15 or something
+	 * like that). To fix that we need to check the schema-type
+	 * and ignore those fields...
+	 * 
+	 * %BUG% No idea what format I should be using for m_dateTime!
+	 * */
+     public DateTimeObj(int[] xercesdate,String typeLocalName)
+    {
+    	try
+    	{
+          m_year = Math.abs(xercesdate[0]);
+          m_month = xercesdate[1];
+          m_day = xercesdate[2];
+          m_hour = xercesdate[3];
+          m_minute = xercesdate[4];
+          m_second = xercesdate[5]+(xercesdate[6]/1000);
+          //m_zone = xercesdate[6]; // not sure how encoded
+          
+          m_signed = (xercesdate[0] < 0);
+          
+          /* Works, but gives slightly different results. Need to
+           * investigate... 
+         int type = XType.getTypeFromLocalName(typeLocalName);
+         String format;
+         switch (type)
+         {
+         	case XType.DATE:
+         	format = d;
+         	break;
+         	case XType.TIME:
+         	format = t1;
+         	break;
+         	default:
+         	format = dt1;
+         }
+         Calendar cal = Calendar.getInstance();
+         cal.set(m_year,(m_month-1),m_day,m_hour,m_minute,(int)m_second);
+          
+          m_date = cal.getTime();
+          SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+          dateFormat.setLenient(false);
+          m_dateTime = dateFormat.format(m_date);
+          */
+          
+          // Don't particularly like constructing this string,
+          // but will do for now. Need to investigate why Date or 
+          // Calendar don't work here...
+          
+         m_dateTime = formatYears(m_year) + "-" + formatDigits(m_month) + "-" + formatDigits(m_day);
+         //  m_dateTime = m_year + "-" + m_month + "-" + m_day;
+         if (m_hour != 0 && m_minute != 0 && m_second != 0)
+            m_dateTime = m_dateTime + "T" + formatDigits(m_hour) + ":" + formatDigits(m_minute) + ":" + m_second; 
+          String[] formatsIn = {dt2, d, t2};
+          m_date = testFormats(m_dateTime, formatsIn);
+          
+         if (m_signed)
+             m_dateTime = "-" + m_dateTime;
+             
+        }
+    	catch (Exception ex)
+    	{
+    		throw new WrappedRuntimeException(ex);
+    	}  
+      
+
+	  // This is wrong but I'm not sure what format I should be using!
+      //SimpleDateFormat dateFormat = new SimpleDateFormat();
+      //dateFormat.setLenient(false);
+      //m_dateTime=dateFormat.format(m_date);
+    }
+    
+    /**
+     * Attempt to parse an input string with the allowed formats, returning
+     * null if none of the formats work. Input formats are passed in longest to shortest,
+     * so if any parse operation fails with a parse error in the string, can
+     * immediately return null.
+     */
+    private static Date testFormats (String in, String[] formats)
+      throws ParseException
+    {
+    	
+      for (int i = 0; i <formats.length; i++)
+      {
+      	try
+    	{        
+          SimpleDateFormat dateFormat = new SimpleDateFormat(formats[i]);
+          dateFormat.setLenient(false);          
+          return dateFormat.parse(in);
+          }
+    	catch (ParseException pe)
+    	{
+    		if ( i == formats.length -1)
+    		throw pe;
+    	}
+        
+      }
+      return null;
+    	
+    }
+    
+    /**
+     * Returns an array with the 3 components that a datetime input string 
+     * may contain: - (for BC era), datetime, and zone. If the zone is not
+     * valid, return null for that component.
+     */
+    private  String[] getEraDatetimeZone(String in) throws TransformerException
+    {
+      String leader = "";
+      String datetime = in;
+      String zone = "";
+      if (in.charAt(0)=='-')
+      {
+        leader = "-"; //  '+' is implicit , not allowed
+        datetime = in.substring(1);
+      }
+      int z = getZoneStart(datetime);
+      if (z > 0)
+      {
+        zone = datetime.substring(z);
+        datetime = datetime.substring(0, z);
+      }
+      else if (z == -2)
+        zone = null;
+      //System.out.println("'" + leader + "' " + datetime + " " + zone);
+      return new String[]{leader, datetime, zone};  
+    }
+    
+    /**
+     * Returns an array with the 3 components that a datetime input string 
+     * may contain: - (for BC era), datetime, and zone. If the zone is not
+     * valid, return null for that component.
+     */
+    private  Date normalizeDate(Date date, String zone)
+    {
+      if (zone == null || zone.length()==0 || zone.equals("Z") || zone.equals("00:00") )
+      return date;
+      else
+      {
+      	int sign = 1;
+      	if (zone.startsWith("-"))
+      	{
+      		sign = -1;
+      	}
+      	int index = zone.indexOf(":");
+      	int hr = sign * (Integer.parseInt(zone.substring(1, index)));
+      	int min = sign * (Integer.parseInt(zone.substring(index+1))); 
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.add(Calendar.HOUR, hr);
+        cal.add(Calendar.MINUTE, min);
+        return cal.getTime();
+      }  
+    }        
+    
+    /**
+     * Get the start of zone information if the input ends
+     * with 'Z' or +/-hh:mm. If a zone string is not
+     * found, return -1; if the zone string is invalid,
+     * return -2.
+     */
+    private int getZoneStart (String datetime) throws TransformerException
+    {
+      if (datetime.indexOf("Z") == datetime.length()-1)
+        return datetime.indexOf("Z");
+      else if (
+               (datetime.lastIndexOf("-") == datetime.length()-6 &&
+                datetime.charAt(datetime.length()-3) == ':')               
+                || 
+                (datetime.indexOf("+") == datetime.length() -6)
+              )
+      {
+        try
+        {
+          SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
+          dateFormat.setLenient(false);
+          Date d = dateFormat.parse(datetime.substring(datetime.length() -5));
+          return datetime.length()-6;
+        }
+        catch (ParseException pe)
+        {
+          throw new TransformerException(pe);
+          //return -2; // Invalid.
+        }
+
+      }
+        return -1; // No zone information.
+    }
+    
+    /**
+     * See dateTime.
+     */
+    public static DateTimeObj date() throws TransformerException
+    {
+      return currentDateTime(d);
+    }
+    
+   
+   /**
+     * The date:date function returns the date specified in the date/time string given 
+     * as the argument. If no argument is given, then the current local date/time, as 
+     * returned by date:date-time is used as a default argument. 
+     * The date/time string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:dateTime in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * If the argument is not in either of these formats, date:date returns an empty string (''). 
+     * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult 
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details. 
+     * The date is returned as a string with a lexical representation as defined for xs:date in 
+     * [3.2.9 date] of [XML Schema Part 2: Datatypes]. The date format is basically CCYY-MM-DD, 
+     * although implementers should consult [XML Schema Part 2: Datatypes] and [ISO 8601] for details.
+     * If no argument is given or the argument date/time specifies a time zone, then the date string 
+     * format must include a time zone, either a Z to indicate Coordinated Universal Time or a + or - 
+     * followed by the difference between the difference from UTC represented as hh:mm. If an argument 
+     * is specified and it does not specify a time zone, then the date string format must not include 
+     * a time zone. 
+     */
+    public static DateTimeObj date(String dateIn) throws TransformerException
+    {
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{d});
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj date(Date dateIn) throws TransformerException
+    {
+    	DateTimeObj dt = new DateTimeObj (dateIn, d);
+              
+      return dt;
+    }
+    
+    
+    /**
+     * The date:time function returns the time specified in the time string given 
+     * as the argument.  
+     * The time string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:time in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#time">[3.2.7 time]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>. 
+     * If the argument string is not in this format, date:time returns an empty string (''). 
+     * The time format is basically hh:mm:ss, although implementers should consult 
+     * If no argument is given or the argument time specifies a time zone, then the time string 
+     * format must include a time zone, the difference from UTC represented as hh:mm. If an argument 
+     * is specified and it does not specify a time zone, then the time string format must not include 
+     * a time zone. 
+     */
+    public static DateTimeObj time() throws TransformerException
+    {
+    	return currentDateTime(t1);
+    }
+    
+    
+    public static DateTimeObj time(String timeIn) throws TransformerException
+    {
+    	DateTimeObj dt = new DateTimeObj (timeIn, new String[]{t1, t2});
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj time(Date timeIn) throws TransformerException
+    {
+    	DateTimeObj dt = new DateTimeObj (timeIn, t1);
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj gYearMonth(String dateIn) throws TransformerException
+    {
+    	// Check on java g Date stuff...
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{gym});
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj gYear(String dateIn) throws TransformerException
+    {
+    	// Check on java g Date stuff...
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{gy});
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj gMonth(String dateIn) throws TransformerException
+    {
+    	// Check on java g Date stuff...
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{gm});
+              
+      return dt;
+    }
+    
+    public static DateTimeObj gMonthDay(String dateIn) throws TransformerException
+    {
+    	// Check on java g Date stuff...
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{gmd});
+              
+      return dt;
+    }
+    
+    
+    public static DateTimeObj gDay(String dateIn) throws TransformerException
+    {
+    	// Check on java g Date stuff...
+    	DateTimeObj dt = new DateTimeObj (dateIn, new String[]{gd});
+              
+      return dt;
+    }
+    
+    
+    /**
+     * The date:date-time function returns the current date and time as a date/time string. 
+     * The date/time string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:dateTime in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     * The date/time string format must include a time zone, either a Z to indicate Coordinated 
+     * Universal Time or a + or - followed by the difference between the difference from UTC 
+     * represented as hh:mm. 
+     */   
+    public static DateTimeObj currentDateTime(String pattern) throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      Date datetime = cal.getTime();
+      DateTimeObj dt = new DateTimeObj(datetime, pattern);
+      
+      int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
+      // If there is no offset, we have "Coordinated
+      // Universal Time."
+      if (offset == 0)
+        dt.setZone("Z");
+      else
+      {
+        // Convert milliseconds to hours and minutes
+        int hrs = offset/(60*60*1000);
+        // In a few cases, the time zone may be +/-hh:30.
+        int min = offset%(60*60*1000);
+        char posneg = hrs < 0? '-': '+';
+        dt.setZone(posneg + formatDigits(hrs) + ':' + formatDigits(min));
+      }
+      return dt;
+    }
+    
+    
+    /**
+     * See above
+     */
+    public static DateTimeObj dateTime() throws TransformerException
+    {
+    	return dateTime(dt1);
+    }
+    
+    
+    /**
+     * The date:date-time function returns the date and time specified in the date/time 
+     * string given as the argument.. 
+     * The date/time string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:dateTime in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">[3.2.7 dateTime]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The date/time format is basically CCYY-MM-DDThh:mm:ss, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     * The date/time string format must include a time zone, either a Z to indicate Coordinated 
+     * Universal Time or a + or - followed by the difference between the difference from UTC 
+     * represented as hh:mm. 
+     */
+    public static DateTimeObj dateTime(String dateTimeIn)
+      throws TransformerException
+    {
+    	return new DateTimeObj(dateTimeIn);
+    }
+    
+    /**
+     * Represent the hours and minutes with two-digit strings.
+     * @param q hrs or minutes.
+     * @return two-digit String representation of hrs or minutes.
+     */
+    private static String formatDigits(int q)
+    {
+      String dd = String.valueOf(Math.abs(q));
+      return dd.length() == 1 ? "0" + dd : dd;
+    }
+    
+    /**
+     * Represent the hours and minutes with two-digit strings.
+     * @param q hrs or minutes.
+     * @return two-digit String representation of hrs or minutes.
+     */
+    private static String formatYears(int q)
+    {
+      String dd = String.valueOf(Math.abs(q));
+      int len = dd.length();
+      for (int i=len; i<4; i++)
+        dd = "0" + dd;
+      return dd;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMn, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public Duration getYMDuration(DateTimeObj dt) throws TransformerException
+    {
+    	Duration du = null;
+     double secs = new Long((m_date.getTime() - dt.m_date.getTime())/1000).doubleValue(); 
+      
+      String sign = secs <0 ? "-" : "";
+     double days = Math.abs(((secs/60)/60)/24);
+     double months = days/31 + (days%31 <15.5 ? 0 : 1);
+     int monthDu = new Double(months%12).intValue();
+     int yearDu = new Double(months/12).intValue();
+     
+     return new Duration(sign + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")
+        + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "") ); 
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMn, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public Duration getDTDuration(DateTimeObj dt) throws TransformerException
+    {
+    	Duration du = null;
+     double secs = new Long((m_date.getTime() - dt.m_date.getTime())/1000).doubleValue(); 
+      
+      String sign = secs <0 ? "-" : "";
+      secs = Math.abs(secs);
+     double secDu = secs%60;
+     int mins = (new Double(secs)).intValue()/60;
+     int mnDu = mins%60;
+     int hours = mins/60;
+     int hourDu = hours%24;
+     int dayDu = hours/24;
+     
+     return new Duration(sign + "P" + (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")
+        + ((hourDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "")  
+        + (hourDu != 0 ? (Integer.toString(hourDu) + "H") : "")         
+        + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+        + (secDu != 0 ? (Double.toString(secDu) + "S") : "")  ); 
+    }
+    
+        
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean lessThan(DateTimeObj dt)
+    {
+    	if (m_zone.equals(dt.m_zone))
+    	{
+    		if( m_date.before(dt.m_date))
+    	/*
+    	if ((m_year < dt.m_year || (m_year == 0 && dt.m_year == 0)) &&
+    	(m_month < dt.m_month || (m_month == 0 && dt.m_month == 0)) &&
+    	(m_day < dt.m_day || (m_day ==0 && dt.m_day == 0)) &&
+    	(m_hour < dt.m_hour || (m_hour == 0 && dt.m_hour == 0)) &&
+    	(m_minute < m_minute || (m_minute == 0 && m_minute == 0)) &&
+    	(m_second < dt.m_second || (m_second == 0 && dt.m_second == 0)) )
+    	*/
+    	      return true;
+    	    else 
+    	      return false;
+    	}
+    	else
+    	{
+    		Date date1 = normalizeDate(m_date, m_zone);
+    		Date date2 = normalizeDate(dt.m_date, dt.m_zone);
+    		if (date1.before(date2))
+    		return true;
+    		else
+    		return false;
+    	}
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean lessThanOrEqual(DateTimeObj dt)
+    {
+    	return (lessThan(dt) || equals(dt));
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean greaterThan(DateTimeObj dt)
+    {
+    	return dt.lessThan(this);
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean greaterThanOrEqual(DateTimeObj dt)
+    {
+    	return (greaterThan(dt) || equals(dt));
+    }
+    
+   
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean equals(DateTimeObj dt)
+    {
+    	if (m_zone.equals(dt.m_zone))
+    	{
+    	   if (m_year == dt.m_year &&
+    	    m_month == dt.m_month &&
+    	    m_day == dt.m_day &&
+    	    m_hour == dt.m_hour &&
+    	    m_minute == dt.m_minute &&
+    	    m_second == dt.m_second)
+    	return true;
+    	else 
+    	return false;
+    	}
+    	else
+    	{
+    		Date date1 = normalizeDate(m_date, m_zone);
+    		Date date2 = normalizeDate(dt.m_date, dt.m_zone);
+    	   if (date1.before(date2) || date2.before(date1))
+    	    return false;
+    	   else 
+    	    return true;
+    	}
+    }
+    
+    
+    public DateTimeObj addDays(double days)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+      cal.add(Calendar.DATE, new Double(days).intValue());
+        
+     DateTimeObj dateTime = date(cal.getTime());
+     dateTime.setZone(m_zone);  
+     return dateTime;
+        
+    }
+    
+    
+    
+    public DateTimeObj addYMDurationToDateTime(Duration d)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? -1 : 1;
+      cal.add(Calendar.YEAR, sign * (d.getYears()));
+      cal.add(Calendar.MONTH, sign * (d.getMonths()));
+        
+     DateTimeObj dateTime = new DateTimeObj(cal.getTime(), dt2 ); 
+     dateTime.setZone(m_zone);  
+     return dateTime;
+        
+    }
+    
+    public DateTimeObj addYMDurationToDate(Duration d)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? -1 : 1;
+      cal.add(Calendar.YEAR, sign * (d.getYears()));
+      cal.add(Calendar.MONTH, sign * (d.getMonths()));  
+     DateTimeObj dt = date(cal.getTime()); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    public DateTimeObj subtractYMDurationFromDateTime(Duration d)
+    throws TransformerException
+    {
+    	Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? 1 : -1;
+      cal.add(Calendar.MONTH, sign * (d.getMonths() + (d.getYears() * 12)));
+        
+     DateTimeObj dateTime = new DateTimeObj(cal.getTime(), dt1); 
+     dateTime.setZone(m_zone);  
+     return dateTime; 
+        
+    }
+    
+    public DateTimeObj subtractYMDurationFromDate(Duration d)
+    throws TransformerException
+    {
+    	Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? 1 : -1;
+      cal.add(Calendar.MONTH, sign * (d.getMonths() + (d.getYears() * 12)));
+        
+     DateTimeObj dt = date(cal.getTime()); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    
+    public DateTimeObj addDTDurationToDateTime(Duration d)
+    throws TransformerException
+    {
+    	Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? -1 : 1;
+     double secs = d.getSeconds() + (((((d.getDays() * 24) + d.getHours()) * 60) + d.getMinutes()) * 60);
+     int intVal = new Double(secs).intValue();
+      cal.add(Calendar.SECOND , sign * intVal);
+      
+      Date date = cal.getTime();
+      SimpleDateFormat dateFormat = new SimpleDateFormat(dt2);
+      dateFormat.setLenient(false);
+      String dateTime = dateFormat.format(date);
+      if (secs - intVal != 0)
+      {
+      String val = Double.toString(secs);
+      int index = val.indexOf('.');
+      dateTime = (index<0) ? dateTime : dateTime + val.substring(index); 
+      }
+      //DateTimeObj dt = new DateTimeObj(cal.getTime(), dt2); 
+      DateTimeObj dt = new DateTimeObj(dateTime); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    
+    
+    public DateTimeObj addDTDurationToDate(Duration d)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? -1 : 1;
+     cal.add(Calendar.MONTH, sign * (d.getMonths()));
+      cal.add(Calendar.DATE, sign * (d.getDays()));
+       
+      DateTimeObj dt = date(cal.getTime()); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+        
+    public DateTimeObj addDTDurationToTime(Duration d)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? -1 : 1;
+     double secs = d.getSeconds() + ((((d.getHours()) * 60) + d.getMinutes()) * 60);
+     int intVal = new Double(secs).intValue();
+      cal.add(Calendar.SECOND , sign * intVal);
+      
+      Date date = cal.getTime();
+      SimpleDateFormat dateFormat = new SimpleDateFormat(t2);
+      dateFormat.setLenient(false);
+      String dateTime = dateFormat.format(date);
+      if (secs - intVal != 0)
+      {
+      String val = Double.toString(secs);
+      int index = val.indexOf('.');
+      dateTime = (index<0) ? dateTime : dateTime + val.substring(index); 
+      }
+      DateTimeObj dt = time(dateTime); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    
+    public DateTimeObj subtractDTDurationFromDateTime(Duration d)
+    throws TransformerException
+    {
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? 1 : -1;
+     double secs = d.getSeconds() + (((((d.getDays() * 24) + d.getHours()) * 60) + d.getMinutes()) * 60);
+      cal.add(Calendar.SECOND , sign * (new Double (Math.floor(secs)).intValue()));
+       
+      DateTimeObj dt = new DateTimeObj(cal.getTime(), dt1); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    	
+    public DateTimeObj subtractDTDurationFromDate(Duration d)
+    throws TransformerException
+    {
+    	
+      Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? 1 : -1;
+     // subtracting 1 from the number of days, because counting
+     // from end of given day, so it counts for day 1  
+      // cal.add(Calendar.DATE, sign * (d.getDays()-1));
+      // "(date('2002-08-05')-duration('P42D'))+duration('P42D') = date('2002-08-05')"
+      // doesn't work if you do the -1.  It sure feels like that is wrong.
+      // -sb
+     double secs = d.getSeconds() + (((((d.getDays() * 24) + d.getHours()) * 60) + d.getMinutes()) * 60);
+      cal.add(Calendar.SECOND , sign * (new Double (Math.floor(secs)).intValue()));
+       
+      DateTimeObj dt = date(cal.getTime()); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    /**
+     * Method subtractDateFromDate.
+     * @param date2
+     * @return Duration
+     * @throws TransformerException
+     */
+    public Duration subtractDateFromDate(DateTimeObj date2)
+    throws TransformerException
+    {
+      
+      /*Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+       
+      int year = m_year - date2.m_year;
+      int month = m_month - date2.m_month;
+      int day = m_day - date2.m_day;
+      int hour = m_hour - date2.m_hour;
+      int minute = m_minute - date2.m_minute;
+      double second = m_second - date2.m_second;
+      
+      Duration dur = new Duration(year, month, day, hour, minute, second);
+       
+     return dur;*/
+     return getDTDuration(date2);
+    }
+
+    	
+    	
+    public DateTimeObj subtractDTDurationFromTime(Duration d)
+    throws TransformerException
+    {
+    	Calendar cal = Calendar.getInstance();
+      cal.setLenient(false);
+      cal.setTime(m_date);
+     int sign = (d.getSigned()) ? 1 : -1;
+     double secs = d.getSeconds() + ((((d.getHours()) * 60) + d.getMinutes()) * 60);
+      cal.add(Calendar.SECOND , sign * (new Double(Math.floor(secs)).intValue()));
+       
+      DateTimeObj dt = time(cal.getTime()); 
+      dt.setZone(m_zone);  
+     return dt;
+    }
+    
+    
+    
+    public void setYears(int years)
+    {
+    	m_year = years;
+    }
+    
+    public int getYears()
+    {
+    	return m_year;
+    }
+    
+    public void setMonths(int months)
+    {
+    	m_month = months;
+    }
+    
+    public int getMonths()
+    {
+    	return m_month;
+    }
+    
+    public void setDays(int days)
+    {
+    	m_day = days;
+    }
+    
+    public int getDays()
+    {
+    	return m_day;
+    }
+    
+    public void setHours(int hours)
+    {
+    	m_hour = hours;
+    }
+    
+    public int getHours()
+    {
+    	return m_hour;
+    }
+    
+    public void setSeconds(double secs)
+    {
+    	m_second = secs;
+    }
+    
+    public double getSeconds()
+    {
+    	return m_second;
+    }
+    
+    public void setMinutes(int mts)
+    {
+    	m_minute = mts;
+    }
+    
+    public int getMinutes()
+    {
+    	return m_minute;
+    }
+    
+    public void setZone(String zone)
+    {
+    	m_zone = zone;
+    }
+    
+    public String getZone()
+    {
+    	if (m_zone.equals("Z") )
+    	return ("00:00");
+    	else
+    	return m_zone;
+    }
+    
+    public Date getDate()
+    {
+    	return m_date;
+    }
+    
+    public String toString()
+    {
+    	return (m_dateTime + (m_zone == null ? "" : m_zone));
+    }
+    
+    
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xml/utils/DefaultErrorHandler.java b/src/org/apache/xml/utils/DefaultErrorHandler.java
index af40946..849fabe 100644
--- a/src/org/apache/xml/utils/DefaultErrorHandler.java
+++ b/src/org/apache/xml/utils/DefaultErrorHandler.java
@@ -60,10 +60,6 @@
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.SourceLocator;
-
-import org.apache.xalan.res.XSLMessages;
-import org.apache.xalan.res.XSLTErrorResources;
- 
 import java.io.PrintWriter;
 import java.io.PrintStream;
 
@@ -338,12 +334,12 @@
       String id = (null != locator.getPublicId() )
                   ? locator.getPublicId()
                     : (null != locator.getSystemId())
-                      ? locator.getSystemId() : XSLMessages.createMessage(XSLTErrorResources.ER_SYSTEMID_UNKNOWN, null); //"SystemId Unknown";
+                      ? locator.getSystemId() : "SystemId Unknown";
 
-      pw.print(id + "; " +XSLMessages.createMessage("line", null) + locator.getLineNumber()
-                         + "; " +XSLMessages.createMessage("column", null) + locator.getColumnNumber()+"; ");
+      pw.print(id + "; Line " + locator.getLineNumber()
+                         + "; Column " + locator.getColumnNumber()+"; ");
     }
     else
-      pw.print("("+XSLMessages.createMessage(XSLTErrorResources.ER_LOCATION_UNKNOWN, null)+")");
+      pw.print("(Location of error unknown)");
   }
 }
diff --git a/src/org/apache/xml/utils/Duration.java b/src/org/apache/xml/utils/Duration.java
new file mode 100644
index 0000000..23ef80c
--- /dev/null
+++ b/src/org/apache/xml/utils/Duration.java
@@ -0,0 +1,863 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, Lotus
+ * Development Corporation., http://www.lotus.com.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.xml.utils;
+
+
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.Calendar;
+import java.text.SimpleDateFormat;
+import java.text.DateFormat;
+import java.text.ParseException;
+import javax.xml.transform.TransformerException;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.objects.XDouble;
+import org.apache.xpath.objects.XBoolean;
+import org.apache.xpath.objects.XObject;
+
+/**
+ * <meta name="usage" content="general"/>
+ * This class contains a duration object.
+ */
+
+public class Duration
+{
+        
+    // Duration format
+    public static final String du = "PnYnMnDTnHnMn.nS";
+    
+    private int m_year;
+    private int m_month;
+    private int m_day;
+    private static int m_T;
+    private int m_hour;
+    private int m_minute;
+    private double m_second;
+    private boolean m_signed;
+    private String m_sign = "-";
+    private String m_duration;
+    private int m_size;
+    
+    /**
+     * The duration string must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnD, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public Duration(String duration) throws TransformerException
+    {
+    	m_duration = duration;
+    	int i;
+    	m_size = duration.length();
+    	m_signed = duration.startsWith("-");
+    	int offset;
+    	int start = offset = (m_signed ? 2 : 1); // Bypass the P
+    	// Remember our Time separator
+    	m_T = (i = duration.indexOf("T")) != -1 ? i : m_size ;
+    	// boundary check??
+    	// Maybe I can avoid doing string operations here if I will not need
+    	// the individual values?? ie: int nY = ( (i = duration.indexOf("Y")) != -1) ? i - start : 0; 
+    	String nY = ( (i = duration.indexOf("Y")) != -1) ? duration.substring(start, i) :"";
+    	start = (i > 0) ? (i + 1) : start ;
+        String nM = ((i = duration.substring(0,m_T).indexOf("M")) != -1 ) ? duration.substring(start, i) :"";
+        start = (i > 0) ? (i + 1) : start ;
+        String nD = ( (i = duration.indexOf("D")) != -1) ? duration.substring(start, i) :"";
+                 
+       try{
+        m_year = nY.length() >0 ? Integer.parseInt(nY) :0;
+        m_month = nM.length() >0 ? Integer.parseInt(nM) :0;
+        m_day = nD.length() >0 ? Integer.parseInt(nD) :0;
+        
+       if (m_T < m_size)
+        {
+        start = (m_T < m_size) ? m_T + 1 : start;
+        String nH = ( (i = duration.indexOf("H")) != -1) ? duration.substring(start, i) :"";
+        start = (i > 0) ? (i + 1) : start ;
+        String nMt = ( (i = duration.substring(m_T, m_size).indexOf("M")) != -1) ? duration.substring(start, i+=m_T) :"";
+        start = (i > 0) ? (i + 1) : start ;
+        String nS = ( (i = duration.indexOf("S")) != -1) ? duration.substring(start, i) :"";
+        
+        m_hour = nH.length() >0 ? Integer.parseInt(nH) :0;
+        m_minute = nMt.length() >0 ? Integer.parseInt(nMt) :0;
+        m_second = nS.length() >0 ? Double.valueOf(nS).doubleValue() :0;
+        }
+        }
+        catch (NumberFormatException nfe)
+        {
+        throw new TransformerException(nfe);
+        }
+      
+    }
+    
+	/** Added by JJK to support Xerces' stopgap internal representation
+	 * as delivered through DTMSequence. We should work with them to
+	 * converge on a shared time/date/duration object compatable with
+	 * the schema spec.
+	 * */
+    public Duration(int[] xercesduration)
+    {
+ 		// I'm not sure how they're representing negative durations!?
+        m_year = xercesduration[0];
+        m_month = xercesduration[1];
+        m_day = xercesduration[2];
+        m_hour = xercesduration[3];
+        m_minute = xercesduration[4];
+        m_second = xercesduration[5]+(xercesduration[6]/1000);
+        // xercesduration[8] is timezone related; ignore it.    	
+    }
+
+    public Duration(int year, int month, int day, int hour, int minute, double second)
+    {
+    // I'm not sure how they're representing negative durations!?
+        m_year = year;
+        m_month = month;
+        m_day = day;
+        m_hour = hour;
+        m_minute = minute;
+        m_second = second;
+        
+        if(year < 0)
+          m_signed = true;
+        // xercesduration[8] is timezone related; ignore it.      
+    }
+    
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public static Duration duration(Duration du)
+    {
+    	//Duration du = new Duration (duration);
+    	int len = du.m_size;
+              
+      if (!du.m_duration.startsWith("P", (du.m_signed ? 1 : 0)) ||
+          (du.m_year == 0 && du.m_month == 0 && du.m_day == 0 && du.m_hour == 0 && du.m_minute == 0 && du.m_second == 0) ||
+          (m_T == len && (du.m_hour != 0 || du.m_minute != 0 || du.m_second != 0)) ||
+          m_T == len -1) 
+        return null;
+                    
+      return du;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMn, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public static Duration YMDuration(String duration) throws TransformerException
+    {
+    	Duration du = duration(new Duration (duration));
+    	if (du == null)
+    	return null;
+              
+      if (!duration.startsWith("P", (du.m_signed ? 1 : 0)) ||
+           (du.m_day != 0 || du.m_hour != 0 || du.m_minute != 0 || du.m_second != 0) ||
+          (du.m_year == 0 && du.m_month == 0) ) 
+        return null;
+                    
+      return du;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMn, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public static Duration YMDurationFromMonths(int months) throws TransformerException
+    {
+    	String sign = (months > 0) ? "" : "-";
+    	months = Math.abs(months);
+    	int monthDu = months%12;
+       int yearDu = months/12;  
+    	return new Duration ( sign + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")  + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "")); 
+      
+    }
+    
+    public static Duration DTDuration(String duration) throws TransformerException
+    {
+    	Duration du = duration(new Duration (duration));
+              
+      if (!duration.startsWith("P", (du.m_signed ? 1 : 0)) ||
+          (du.m_year != 0 || du.m_month != 0) ||
+          (du.m_day == 0 && du.m_hour == 0 && du.m_minute == 0 && du.m_second == 0) ) 
+        return null;
+                    
+      return du;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMn, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public static Duration DTDurationFromSecs(double secs) throws TransformerException
+    {
+    	String sign = (secs > 0) ? "" : "-"; 
+    	secs = Math.abs(secs);
+    	double secDu = secs%60;
+       int mins = (new Double(secs)).intValue()/60;
+       int mnDu = mins%60;
+       int hours = mins/60;
+       int hourDu = hours%24;
+       int dayDu = hours/24;
+    	return new Duration ( sign + "P" 
+    	+ (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")
+        + ((hourDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "")  
+        + (hourDu != 0 ? (Integer.toString(hourDu) + "H") : "")         
+        + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+        + (secDu != 0 ? (Double.toString(secDu) + "S") : "")  ); 
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean DTEqual(Duration du)
+    {
+    	if ((m_signed == du.m_signed) &&
+    	m_day == du.m_day &&
+    	m_hour == du.m_hour &&
+    	m_minute == du.m_minute &&
+    	m_second == du.m_second)
+    	return true;
+    	else 
+    	return false;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean DTLessThan(Duration du)
+    {
+    	int sign = (m_signed) ? -1 : 1;
+    	int hrs = m_hour + (m_day * 24);
+    	int mns = m_minute + (hrs * 60);
+       double secs = (m_second + (mns * 60)) * sign;
+        
+        sign = (du.m_signed) ? -1 : 1;
+    	hrs = du.m_hour + (du.m_day * 24);
+    	mns = du.m_minute + (hrs * 60);
+       double secs2 = (du.m_second + (mns * 60)) * sign;
+        
+    	
+    	if (secs < secs2) 
+    	return true;
+    	else 
+    	return false;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean DTLessThanOrEqual(Duration du)
+    {
+    	 
+    	return (DTLessThan(du) || DTEqual(du));
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean DTGreaterThan(Duration du)
+    {
+    	return du.DTLessThan(this);
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean DTGreaterThanOrEqual(Duration du)
+    {
+    	 
+    	return (DTGreaterThan(du) || DTEqual(du));
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean YMEqual(Duration du)
+    {
+    	if ((m_signed == du.m_signed) &&
+    	m_year == du.m_year &&
+    	m_month == du.m_month)
+    	return true;
+    	else 
+    	return false;
+    }
+    
+     /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean YMLessThan(Duration du)
+    {
+    	int sign = (m_signed) ? -1 : 1;
+       int months = (m_month + (m_year * 12)) * sign;
+       
+        sign = (du.m_signed) ? -1 : 1;
+       int months2 = (du.m_month + (du.m_year * 12)) * sign;
+       
+        if (months < months2)
+    	return true;
+    	else 
+    	return false;
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean YMLessThanOrEqual(Duration du)
+    {
+    	 
+    	return (YMLessThan(du) || YMEqual(du));
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean YMGreaterThan(Duration du)
+    {
+    	return du.YMLessThan(this);
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean YMGreaterThanOrEqual(Duration du)
+    {
+    	 
+    	return (YMGreaterThan(du) || YMEqual(du));
+    }
+    
+    /**
+     * The duration function returns the duration specified in the duration 
+     * string given as the argument.. 
+     * The duration string that's returned must be a string in the format defined as the 
+     * lexical representation of xs:duration in 
+     * <a href="http://www.w3.org/TR/xmlschema-2/#duration">[3.2.6 duration]</a> of
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a>.
+     * The duration format is basically PnYnMnDTnHnMnS, although implementers should consult
+     * <a href="http://www.w3.org/TR/xmlschema-2/">[XML Schema Part 2: Datatypes]</a> and 
+     * <a href="http://www.iso.ch/markete/8601.pdf">[ISO 8601]</a> for details.
+     */
+    public boolean equals(Duration du)
+    {
+    	if ((m_signed == du.m_signed) &&
+    	m_year == du.m_year &&
+    	m_month == du.m_month &&
+    	m_day == du.m_day &&
+    	m_hour == du.m_hour &&
+    	m_minute == du.m_minute &&
+    	m_second == du.m_second)
+    	return true;
+    	else 
+    	return false;
+    }
+    
+    
+    
+    public Duration addYMDuration(Duration d)
+    throws TransformerException
+    {
+    	
+        String sign;
+        int monthDu, yearDu;
+        if (m_signed == d.m_signed) //!signed1 && !signed1 || signed1 && signed2)
+        {
+        	sign = (m_signed) ? m_sign : "";
+           int months = m_month + d.m_month;
+            monthDu = months%12;
+            yearDu = months/12 + m_year + d.m_year;  
+        }
+        else
+        {
+        	int y1 = m_year;
+        	int y2 = d.m_year;
+        	int y = (m_signed) ? y2 - y1 : y1 - y2;
+        	
+        	int m1 = m_month;
+        	int m2 = d.m_month;
+        	int months = (m_signed) ? m2 - m1 + (y*12)  : m1 - m2 + (y*12);
+        	sign = months > 0 ? "" : "-";
+        	 
+        	months = Math.abs(months);
+        	monthDu = months%12;
+        	yearDu = months/12;  
+        	
+        }
+        
+        return new Duration(sign + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")  + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "")); 
+        
+    }
+    
+    public Duration subtractYMDuration(Duration d)
+    throws TransformerException
+    {
+    	
+        String sign;
+        int monthDu, yearDu;
+        
+       if (m_signed == d.m_signed)
+        {
+        	int y1 = m_year;
+        	int y2 = d.m_year;
+        	int y = (m_signed) ? y2 - y1 : y1 - y2;
+        	
+        	int m1 = m_month;
+        	int m2 = d.m_month;
+        	int months = (m_signed) ? m2 - m1 + (y*12)  : m1 - m2 + (y*12);
+        	sign = months > 0 ? "" : m_sign;
+        	
+        	months = Math.abs(months); 
+        	monthDu = months%12;
+        	yearDu = months/12;  
+        	
+        }
+        else
+        {
+        	sign = (m_signed) ? m_sign : "";
+           int months = m_month + d.m_month;
+            monthDu = months%12;
+            yearDu = months/12 + m_year + d.m_year;  
+        }
+        
+        return new Duration(sign + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")  + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "")); 
+        
+    }
+    
+    public Duration multiplyYMDuration(double dec)
+    throws TransformerException
+    {
+    	int sign = (m_signed) ? -1 : 1;
+       double months = (m_month + (m_year * 12)) * dec * sign;
+        months = Math.floor(months + .5);
+        
+        //months = (new Double(Math.floor(new Integer(months).doubleValue()))).intValue()
+        
+       double ms = Math.abs(months);   
+       int monthDu = (new Double(ms%12)).intValue();
+       int yearDu = (new Double(ms/12)).intValue();
+       //new Double(Math.floor(new Integer(months/12).doubleValue())).intValue();
+       
+        return new Duration((months > 0 ? "" : m_sign) + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")  + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "")); 
+        
+    	}
+    
+    public Duration divideYMDuration(double dec)
+    throws TransformerException
+    {int sign = (m_signed) ? -1 : 1;
+       double months = (m_month + (m_year * 12)) / dec * sign;
+        months = Math.floor(months + .5);
+        
+      double ms = Math.abs(months);    
+       int monthDu = (new Double(ms%12)).intValue();
+       int yearDu = (new Double(ms/12)).intValue();
+       //new Double(Math.floor(new Integer(months/12).doubleValue())).intValue();
+       
+       return new Duration((months > 0 ? "" : m_sign) + "P" + (yearDu != 0 ? (Integer.toString(yearDu) + "Y") : "")  + (monthDu != 0 ? (Integer.toString(monthDu) + "M") : "")); 
+        }
+    
+    public Duration addDTDuration(Duration du)
+    throws TransformerException
+    {
+    	String sign;
+        int dayDu, hourDu, mnDu;
+        double secDu;
+        if (m_signed == du.m_signed) //!signed1 && !signed1 || signed1 && signed2)
+        {
+        	sign = (m_signed) ? m_sign : "";
+        	double secs = m_second + du.m_second;
+        	secDu = secs%60;
+        	int mins = (new Double(secs)).intValue()/60 + m_minute + du.m_minute;
+        	mnDu = mins%60;
+        	int hours = mins/60 + m_hour + du.m_hour;
+        	hourDu = hours%24;
+            dayDu = hours/24 + m_day + du.m_day;
+        }
+        else
+        {
+        	int d1 = m_day;
+        	int d2 = du.m_day;
+        	int d = (m_signed) ? d2 - d1 : d1 - d2;
+        	
+        	int h1 = m_hour;
+        	int h2 = du.m_hour;
+        	int h = (m_signed) ? h2 - h1 + (d*24)  : h1 - h2 + (d*24);
+        	
+        	int m1 = m_minute;
+        	int m2 = du.m_minute;
+        	int m = (m_signed) ? m2 - m1 + (h*60)  : m1 - m2 + (h*60);
+        	
+        	double s1 = m_second;
+        	double s2 = du.m_second;
+        	double s = (m_signed) ? s2 - s1 + (m*60)  : s1 - s2 + (m*60);
+        	sign = s > 0 ? "" : m_sign;
+        	
+        	s = Math.abs(s); 
+        	secDu = s%60;
+        	m = (new Double(s)).intValue()/60;
+        	mnDu = m%60;
+        	h = m/60;
+        	hourDu = h%24;
+        	dayDu = h/24;  
+        	
+        }
+        
+        return new Duration(sign + "P" + (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")
+        + ((hourDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "")  
+        + (hourDu != 0 ? (Integer.toString(hourDu) + "H") : "")         
+        + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+        + (secDu != 0 ? (Double.toString(secDu) + "S") : "")  ); 
+        }
+    
+    public Duration subtractDTDuration(Duration du)
+    throws TransformerException
+    {
+    	String sign;
+        int dayDu, hourDu, mnDu;
+         double secDu;
+        if (m_signed == du.m_signed) 
+        {
+        	int d1 = m_day;
+        	int d2 = du.m_day;
+        	int d = (m_signed) ? d2 - d1 : d1 - d2;
+        	
+        	int h1 = m_hour;
+        	int h2 = du.m_hour;
+        	int h = (m_signed) ? h2 - h1 + (d*24)  : h1 - h2 + (d*24);
+        	
+        	int m1 = m_minute;
+        	int m2 = du.m_minute;
+        	int m = (m_signed) ? m2 - m1 + (h*60)  : m1 - m2 + (h*60);
+        	
+        	double s1 = m_second;
+        	double s2 = du.m_second;
+        	double s = (m_signed) ? s2 - s1 + (m*60)  : s1 - s2 + (m*60);
+        	sign = s > 0 ? "" : m_sign;
+        	
+        	s = Math.abs(s); 
+        	secDu = s%60;
+        	m = (new Double(s)).intValue()/60;
+        	mnDu = m%60;
+        	h = m/60;
+        	hourDu = h%24;
+        	dayDu = h/24;  
+        	
+        }
+        else
+        {
+        	sign = (m_signed) ? m_sign : "";
+        	double secs = m_second + du.m_second;
+        	secDu = secs%60;
+        	int mins = (new Double(secs)).intValue()/60 + m_minute + du.m_minute;
+        	mnDu = mins%60;
+        	int hours = mins/60 + m_hour + du.m_hour;
+        	hourDu = hours%24;
+            dayDu = hours/24 + m_day + du.m_day;
+        }
+        
+        
+        return new Duration(sign + "P" + (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")
+        + ((hourDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "")  
+        + (hourDu != 0 ? (Integer.toString(hourDu) + "H") : "")         
+        + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+        + (secDu != 0 ? (Double.toString(secDu) + "S") : "")  ); 
+    	}
+    
+    public Duration multiplyDTDuration(double dec)
+    throws TransformerException
+    {
+    	int sign = (m_signed) ? -1 : 1;
+    	int hrs = m_hour + (m_day * 24);
+    	int mns = m_minute + (hrs * 60);
+       double secs = (m_second + (mns * 60)) * dec * sign;
+        
+        double s = Math.abs(secs);   
+       double secDu = s%60;
+        mns = (new Double(s/60)).intValue();
+       int mnDu = mns%60;
+        hrs = mns/60;
+       int hrDu = hrs%24;
+       int dayDu = hrs/24;
+       
+       return new Duration((secs > 0 ? "" : m_sign) + "P" + (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")  
+       + ((hrDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "") 
+       + (hrDu != 0 ? (Integer.toString(hrDu) + "H") : "")
+       + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+       + (secDu != 0 ? (Double.toString(secDu) + "S") : "")); 
+        
+    	}
+    
+    public Duration divideDTDuration(double dec)
+    throws TransformerException
+    {
+    	int sign = (m_signed) ? -1 : 1;       
+    	int hrs = m_hour + (m_day * 24);
+    	int mns = m_minute + (hrs * 60);
+       double secs = Math.floor(((m_second + (mns * 60)) / dec) + .5) * sign;
+        secs = Math.floor(secs);
+       
+       double s = Math.abs(secs);    
+       double secDu = s%60;
+        mns = (new Double(s/60)).intValue();
+       int mnDu = mns%60;
+        hrs = mns/60;
+       int hrDu = hrs%24;
+       int dayDu = hrs/24;
+       return new Duration((secs > 0 ? "" : m_sign) + "P" + (dayDu != 0 ? (Integer.toString(dayDu) + "D") : "")  
+       + ((hrDu != 0 || mnDu != 0 || secDu != 0) ? "T" : "") 
+       + (hrDu != 0 ? (Integer.toString(hrDu) + "H") : "")
+       + (mnDu != 0 ? (Integer.toString(mnDu) + "M") : "")
+       + (secDu != 0 ? (Double.toString(secDu) + "S") : "")); 
+             }
+    
+    public void setYears(int years)
+    {
+    	m_year = years;
+    }
+    
+    public int getYears()
+    {
+    	return m_year;
+    }
+    
+    public void setMonths(int months)
+    {
+    	m_month = months;
+    }
+    
+    public int getMonths()
+    {
+    	return m_month;
+    }
+    
+    public void setDays(int days)
+    {
+    	m_day = days;
+    }
+    
+    public int getDays()
+    {
+    	return m_day;
+    }
+    
+    public void setHours(int hours)
+    {
+    	m_hour = hours;
+    }
+    
+    public int getHours()
+    {
+    	return m_hour;
+    }
+    
+    public void setSeconds(double secs)
+    {
+    	m_second = secs;
+    }
+    
+    public double getSeconds()
+    {
+    	return m_second;
+    }
+    
+    public void setMinutes(int mts)
+    {
+    	m_minute = mts;
+    }
+    
+    public int getMinutes()
+    {
+    	return m_minute;
+    }
+    
+    public boolean getSigned()
+    {
+    	return m_signed;
+    }
+    
+    public String toString()
+    {
+      if (null == m_duration)
+      {
+        m_duration =
+          (m_signed ? m_sign : "")
+            + "P"
+            + ((m_year > 0) ? m_year + "Y" : "")
+            + ((m_month > 0) ? m_month + "M" : "")
+            + ((m_day > 0) ? m_day +"D": "")
+            + ((m_hour != 0 || m_minute != 0 || m_second != 0) ? "T" : "")
+            + ((m_hour != 0) ? m_hour + "H" : "")
+            + ((m_minute != 0) ? m_minute + "M" : "")
+            + ((m_second != 0) ? m_second + "S" : "");
+      }
+        
+      return m_duration;
+    	// return m_duration;
+    }
+    
+    
+
+}
\ No newline at end of file
diff --git a/src/org/apache/xml/utils/FastStringBuffer.java b/src/org/apache/xml/utils/FastStringBuffer.java
index 05a8d9f..71c0c98 100644
--- a/src/org/apache/xml/utils/FastStringBuffer.java
+++ b/src/org/apache/xml/utils/FastStringBuffer.java
@@ -1373,4 +1373,162 @@
     source.m_chunkSize = 1 << (source.m_chunkBits);
     source.m_chunkMask = source.m_chunkSize - 1;
   }
+
+	/** Support for DTM2XNI. Rather than push XNI awareness into this class,
+	 * (as we did for SAX in sendSAX*), yield the content in a reasonably
+	 * efficient manner for the caller to pass along.
+	 * */
+  public CharacterBlockEnumeration enumerateCharacterBlocks(int start, int length)
+  {
+  	return new FSBCharacterBlockEnumeration(start,length);
+  }
+  
+	/** Support for DTM2XNI. Rather than push XNI awareness into this class,
+	 * (as we did for SAX in sendSAX*), yield the content in a reasonably
+	 * efficient manner for the caller to pass along.
+	 * 
+	 * %BUG% %REVIEW% Currently does _NOT_ support inner FSBs.
+	 * We need to either rearchitect those or get rid of 'em...
+	 * */
+  protected class FSBCharacterBlockEnumeration
+  extends CharacterBlockEnumeration
+  {
+  	int f_remaining;
+  	int f_chunk;
+  	
+  	FSBCharacterBlockEnumeration(int start,int length)
+  	{
+  		if(m_innerFSB!=null)
+			throw new UnsupportedOperationException("Can't handle innerFSBs yet");
+  		
+  		int l=length();
+  		if(start>l)
+  		{
+  			// Don't start off end -- take that as empty
+  			_start=_length=f_remaining=0;
+  			_chars=m_array[0];
+  		}
+  		else
+  		{
+  			// Don't run off end -- truncate to fit
+	  		l-=start;
+ 	 		f_remaining = (l>length) ? length : l;
+ 	 		
+ 	 		// Set up first chunk
+ 	 		f_chunk=start>>>m_chunkBits;
+ 	 		
+ 	 		_start=start & m_chunkMask;
+ 	 		
+ 	 		l=m_chunkSize-start;
+ 	 		_length = (l>f_remaining) ? f_remaining : l;
+ 	 		
+  			f_remaining -= _length;
+  		}
+  	}
+
+  	/** Not supported in this implementaton */
+	public FSBCharacterBlockEnumeration()
+	{
+		throw new UnsupportedOperationException("Not supported in this implementaton");
+	}
+	
+  	/** Not supported in this implementaton */
+	public FSBCharacterBlockEnumeration(String s)
+	{
+		throw new UnsupportedOperationException("Not supported in this implementaton");
+	}
+	
+  	/** Not supported in this implementaton */
+	public FSBCharacterBlockEnumeration(String s, int start, int length)
+	{
+		throw new UnsupportedOperationException("Not supported in this implementaton");
+	}
+	
+  	/** Not supported in this implementaton */
+	public FSBCharacterBlockEnumeration(char[] ch)
+	{
+		throw new UnsupportedOperationException("Not supported in this implementaton");
+	}
+
+  	/** Not supported in this implementaton */
+	public FSBCharacterBlockEnumeration(char[] ch, int start, int length)
+	{
+		throw new UnsupportedOperationException("Not supported in this implementaton");
+	}
+	
+	/** @return true if another character block can be accessed by calling
+	 * nextElement()
+	 */
+	public boolean hasMoreElements()
+	{
+		return f_remaining>0;
+	}
+	
+	/** Advance to the next character block. 
+	 * 
+	 * @returns either this CharacterBlockEnumeration object (as a
+	 * transient accessor to the "element") or null if no more elements are available.
+	 * This is a bit of a kluge, but it allows us to claim that we
+	 * implement the Java Enumeration interface if we want to do so, and
+	 * it seems to be as good or bad as any other return value.
+	 * */
+	public Object nextElement()
+	{
+		if(f_remaining==0)
+			return null;
+			
+		// Next chunk
+		++f_chunk;
+		_start=0;
+ 		_length = (m_chunkSize>f_remaining) ? f_remaining : m_chunkSize;
+		f_remaining -= _length;
+		return this;
+	}
+	
+	
+	/** @return the starting offset in the current block's character array
+	 * */
+	public int getStart()
+	{
+		return _start;
+	}
+
+	/** @return the length of the the current block
+	 * */
+	public int getLength()
+	{
+		return _length;
+	}
+
+	/** 
+	 * @return the current block's character array. Data will begin at
+	 * offset {start}.
+	 * */
+	public char[] getChars()
+	{
+		char[] ch=(_length>0)
+			? m_array[f_chunk] 
+			: EMPTY;
+		return ch;
+	}
+
+	/** @param target A char[] to be copied into. If a buffer is not supplied
+	 * we will create one.
+	 *
+	 * @param targetStart Offset in the target at which copying should begin.
+	 * 
+	 * @return the buffer, filled with {length} characters starting at offset
+	 * {targetStart}. Characters before or after that block should be unaffected.
+	 * */
+	public char[] getChars(char[] target, int targetStart)
+	{
+		if(_length>0)
+		{
+			System.arraycopy(m_array[f_chunk],_start,target,targetStart,_length);
+		}
+			
+		return target;
+	}
+  	
+  }
 }
diff --git a/src/org/apache/xml/utils/ListingErrorHandler.java b/src/org/apache/xml/utils/ListingErrorHandler.java
index 5b977f7..750eb3c 100644
--- a/src/org/apache/xml/utils/ListingErrorHandler.java
+++ b/src/org/apache/xml/utils/ListingErrorHandler.java
@@ -57,22 +57,19 @@
 
 package org.apache.xml.utils;
 
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import org.xml.sax.*;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.SourceLocator;
 import java.io.PrintWriter;
-import java.net.MalformedURLException;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.net.URL;
 import java.net.URLConnection;
-
-import javax.xml.transform.ErrorListener;
-import javax.xml.transform.SourceLocator;
-import javax.xml.transform.TransformerException;
-import org.apache.xalan.res.XSLMessages;
-import org.apache.xalan.res.XSLTErrorResources;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
+import java.io.InputStream;
+import org.apache.xml.utils.SystemIDResolver;
 
 
 /**
@@ -97,8 +94,7 @@
     public ListingErrorHandler(PrintWriter pw)
     {
         if (null == pw)
-            throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_ERRORHANDLER_CREATED_WITH_NULL_PRINTWRITER, null));
-            // "ListingErrorHandler created with null PrintWriter!");
+            throw new NullPointerException("ListingErrorHandler created with null PrintWriter!");
             
         m_pw = pw;
     }
diff --git a/src/org/apache/xml/utils/QName.java b/src/org/apache/xml/utils/QName.java
index aeee751..ed6c353 100644
--- a/src/org/apache/xml/utils/QName.java
+++ b/src/org/apache/xml/utils/QName.java
@@ -125,41 +125,16 @@
    */
   public QName(String namespaceURI, String localName)
   {
-    this(namespaceURI, localName, false); 
-  }
 
-  /**
-   * Constructs a new QName with the specified namespace URI and
-   * local name.
-   *
-   * @param namespaceURI The namespace URI if known, or null
-   * @param localName The local name
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String namespaceURI, String localName, boolean validate) 
-  {
-
-    // This check was already here.  So, for now, I will not add it to the validation
-    // that is done when the validate parameter is true.
     if (localName == null)
       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
             XPATHErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
 
-    if (validate) 
-    {
-        if (!XMLChar.isValidNCName(localName))
-        {
-            throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-    }
-    
     _namespaceURI = namespaceURI;
     _localName = localName;
-    m_hashCode = toString().hashCode();
+    m_hashCode = calcHashCode();
   }
-  
+
   /**
    * Constructs a new QName with the specified namespace URI, prefix
    * and local name.
@@ -167,94 +142,37 @@
    * @param namespaceURI The namespace URI if known, or null
    * @param prefix The namespace prefix is known, or null
    * @param localName The local name
-   * 
    */
   public QName(String namespaceURI, String prefix, String localName)
   {
-     this(namespaceURI, prefix, localName, false);
-  }
-  
- /**
-   * Constructs a new QName with the specified namespace URI, prefix
-   * and local name.
-   *
-   * @param namespaceURI The namespace URI if known, or null
-   * @param prefix The namespace prefix is known, or null
-   * @param localName The local name
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String namespaceURI, String prefix, String localName, boolean validate)
-  {
 
-    // This check was already here.  So, for now, I will not add it to the validation
-    // that is done when the validate parameter is true.
     if (localName == null)
       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
             XPATHErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
 
-    if (validate)
-    {    
-        if (!XMLChar.isValidNCName(localName))
-        {
-            throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-
-        if ((null != prefix) && (!XMLChar.isValidNCName(prefix)))
-        {
-            throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_PREFIX_INVALID,null )); //"Argument 'prefix' not a valid NCName");
-        }
-
-    }
     _namespaceURI = namespaceURI;
     _prefix = prefix;
     _localName = localName;
-    m_hashCode = toString().hashCode();
-  }  
+    m_hashCode = calcHashCode();
+  }
 
   /**
    * Construct a QName from a string, without namespace resolution.  Good
    * for a few odd cases.
    *
    * @param localName Local part of qualified name
-   * 
    */
   public QName(String localName)
   {
-    this(localName, false);
-  }
-  
-  /**
-   * Construct a QName from a string, without namespace resolution.  Good
-   * for a few odd cases.
-   *
-   * @param localName Local part of qualified name
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String localName, boolean validate)
-  {
 
-    // This check was already here.  So, for now, I will not add it to the validation
-    // that is done when the validate parameter is true.
     if (localName == null)
       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
             XPATHErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
 
-    if (validate)
-    {    
-        if (!XMLChar.isValidNCName(localName))
-        {
-            throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-    }
     _namespaceURI = null;
     _localName = localName;
-    m_hashCode = toString().hashCode();
-  }  
+    m_hashCode = calcHashCode();
+  }
 
   /**
    * Construct a QName from a string, resolving the prefix
@@ -266,21 +184,6 @@
    */
   public QName(String qname, Stack namespaces)
   {
-    this(qname, namespaces, false);
-  }
-
-  /**
-   * Construct a QName from a string, resolving the prefix
-   * using the given namespace stack. The default namespace is
-   * not resolved.
-   *
-   * @param qname Qualified name to resolve
-   * @param namespaces Namespace stack to use to resolve namespace
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String qname, Stack namespaces, boolean validate)
-  {
 
     String namespace = null;
     String prefix = null;
@@ -294,7 +197,6 @@
       {
         namespace = S_XMLNAMESPACEURI;
       }
-      // Do we want this?
       else if (prefix.equals("xmlns"))
       {
         return;
@@ -333,18 +235,9 @@
 
     _localName = (indexOfNSSep < 0)
                  ? qname : qname.substring(indexOfNSSep + 1);
-                 
-    if (validate)
-    {
-        if ((_localName == null) || (!XMLChar.isValidNCName(_localName))) 
-        {
-           throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-    }                 
     _namespaceURI = namespace;
     _prefix = prefix;
-    m_hashCode = toString().hashCode();
+    m_hashCode = calcHashCode();
   }
 
   /**
@@ -359,23 +252,6 @@
   public QName(String qname, Element namespaceContext,
                PrefixResolver resolver)
   {
-      this(qname, namespaceContext, resolver, false);
-  }
-
-  /**
-   * Construct a QName from a string, resolving the prefix
-   * using the given namespace context and prefix resolver. 
-   * The default namespace is not resolved.
-   * 
-   * @param qname Qualified name to resolve
-   * @param namespaceContext Namespace Context to use
-   * @param resolver Prefix resolver for this context
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String qname, Element namespaceContext,
-               PrefixResolver resolver, boolean validate)
-  {
 
     _namespaceURI = null;
 
@@ -393,12 +269,6 @@
         {
           _namespaceURI = S_XMLNAMESPACEURI;
         }
-        
-        // Do we want this?
-        else if (prefix.equals("xmlns"))
-        {
-          return;
-        }
         else
         {
           _namespaceURI = resolver.getNamespaceForPrefix(prefix,
@@ -422,20 +292,9 @@
 
     _localName = (indexOfNSSep < 0)
                  ? qname : qname.substring(indexOfNSSep + 1);
-
-    if (validate)
-    {
-        if ((_localName == null) || (!XMLChar.isValidNCName(_localName))) 
-        {
-           throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-    }                 
-                 
-    m_hashCode = toString().hashCode();
+    m_hashCode = calcHashCode();
   }
 
-
   /**
    * Construct a QName from a string, resolving the prefix
    * using the given namespace stack. The default namespace is
@@ -446,38 +305,26 @@
    */
   public QName(String qname, PrefixResolver resolver)
   {
-    this(qname, resolver, false);
-  }
 
-  /**
-   * Construct a QName from a string, resolving the prefix
-   * using the given namespace stack. The default namespace is
-   * not resolved.
-   *
-   * @param qname Qualified name to resolve
-   * @param resolver Prefix resolver for this context
-   * @param validate If true the new QName will be validated and an IllegalArgumentException will
-   *                 be thrown if it is invalid.
-   */
-  public QName(String qname, PrefixResolver resolver, boolean validate)
-  {
-
-	String prefix = null;
     _namespaceURI = null;
 
     int indexOfNSSep = qname.indexOf(':');
 
     if (indexOfNSSep > 0)
     {
-      prefix = qname.substring(0, indexOfNSSep);
-
+      String prefix = qname.substring(0, indexOfNSSep);
+      _prefix = prefix;
+      
       if (prefix.equals("xml"))
       {
         _namespaceURI = S_XMLNAMESPACEURI;
       }
       else
       {
-        _namespaceURI = resolver.getNamespaceForPrefix(prefix);
+        if(null != resolver) // Bad idea, I know.  -sb
+          _namespaceURI = resolver.getNamespaceForPrefix(prefix);
+        else
+          _namespaceURI = prefix;
       }
 
       if (null == _namespaceURI)
@@ -489,21 +336,9 @@
       }
     }
 
-	_localName = (indexOfNSSep < 0)
-                 ? qname : qname.substring(indexOfNSSep + 1);   
-                 
-    if (validate)
-    {
-        if ((_localName == null) || (!XMLChar.isValidNCName(_localName))) 
-        {
-           throw new IllegalArgumentException(XSLMessages.createXPATHMessage(
-            XPATHErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
-        }
-    }                 
-
-              
-    m_hashCode = toString().hashCode();
-    _prefix = prefix;
+    _localName = (indexOfNSSep < 0)
+                 ? qname : qname.substring(indexOfNSSep + 1);
+    m_hashCode = calcHashCode();
   }
 
   /**
@@ -588,6 +423,15 @@
   {
     return getLocalName();
   }
+  
+  /**
+   * Calculate the hash code for this object.
+   * @return int The hashcode to be used.
+   */
+  int calcHashCode()
+  {
+    return _localName.hashCode();
+  }
 
   /**
    * Return the cached hashcode of the qualified name.
diff --git a/src/org/apache/xml/utils/SparseVector.java b/src/org/apache/xml/utils/SparseVector.java
new file mode 100644
index 0000000..d1fdfe3
--- /dev/null
+++ b/src/org/apache/xml/utils/SparseVector.java
@@ -0,0 +1,173 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999,2000 The Apache Software Foundation.  All rights 
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:  
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xerces" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written 
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.xml.utils;
+
+// %REVIEW% Should this be based on SuballocatedIntVector instead?
+// (Unclear. Pools will rarely be huge. But if they ever are...)
+import org.apache.xml.utils.IntVector;
+import java.util.Vector;
+
+/** <p>SparseVector can be thought of as a replacement for
+ * Hashtable, using int-value hashcodes/keys directly rather than requiring
+ * that they be objectified as Integers.
+ * (A standard Hashtable is relatively
+ * inefficient at manipulating primitives as either keys or values.)</p>
+ *
+ * Note similarity to SparseVector, though that assigns its own keys
+ * (allowing it to use internal position as an implied additional column)
+ * and puts heavier emphasis on bidirectional mapping.
+ *
+ * <p>Design Priorities:
+ * <li>Index-to-Object lookup speed is critical.</li>
+ * <li>Object-to-index lookup speed is not.</li>
+ * <li>Threadsafety is not guaranteed at this level.
+ * Enforce that in the application if needed.</li>
+ * <li>Storage efficiency is a major issue; that's why we're using
+ * a sparse vector rather than a standard one.</li>
+ * <li>I'm assuming a relatively small number of values will be stored;
+ * the current primary use for this is xsi:type overrides in XNI2DTM,
+ * and it is hoped these will be infrequent. To make this more general
+ * it would need to be adaptive to size demands, as is Java's Hashtable.
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * Status: Not unit-tested.
+ * */
+public class SparseVector
+{
+  Vector m_values;
+  IntVector m_keys;
+  static final int HASHPRIME=101;
+  int[] m_hashStart=new int[HASHPRIME];
+  IntVector m_hashChain;
+  static final int NULL=-1;
+
+  public SparseVector()
+    {
+      m_values=new Vector();
+      m_keys=new IntVector();
+      m_hashChain=new IntVector(512);
+      removeAllElements();
+    }
+  
+  public void removeAllElements()
+    {
+      m_values.removeAllElements();
+      m_keys.removeAllElements();
+      for(int i=0;i<HASHPRIME;++i)
+        m_hashStart[i]=NULL;
+      m_hashChain.removeAllElements();
+    }
+
+  /** 
+   * @param value to be stored
+   * @param index to store it at
+   * @return previous value at that index (may be null), or null if none.
+   * */    
+  public Object setElementAt(Object value,int index)
+  {
+  	return maybeSetElementAt(value,index,true);
+  }
+
+  /** 
+   * @param index to retrieve
+   * @return current value at that index (may be null), or null if none.
+   * */    
+  public Object elementAt(int index)
+  {
+  	return maybeSetElementAt(null,index,false);
+  }
+
+  protected Object maybeSetElementAt(Object value, int index,boolean set)
+    {
+      int hashslot=index%HASHPRIME;
+      if(hashslot<0) hashslot=-hashslot;
+
+      // Is it one we already know?
+      int hashlast=m_hashStart[hashslot];
+      int hashcandidate=hashlast;
+      while(hashcandidate!=NULL)
+        {
+          if(m_keys.elementAt(hashcandidate)==index)
+          {
+          	// Found existing; update it
+          	Object ret=m_values.elementAt(hashcandidate);
+          	if(set)
+	          	m_values.setElementAt(value,hashcandidate);
+			return ret;          
+          }
+          hashlast=hashcandidate;
+          hashcandidate=m_hashChain.elementAt(hashcandidate);
+        }
+        
+      if(set)
+      {
+      	// New value. Add to tables.
+        int newIndex=m_values.size();
+        m_values.addElement(value);
+        m_keys.addElement(index);
+        m_hashChain.addElement(NULL);	// Initialize to no-following-same-hash
+        if(hashlast==NULL)  // First for this hash
+          m_hashStart[hashslot]=newIndex;
+        else // Link from previous with same hash
+          m_hashChain.setElementAt(newIndex,hashlast);
+      }
+      return null;
+    }
+}
diff --git a/src/org/apache/xml/utils/StringToIntTable.java b/src/org/apache/xml/utils/StringToIntTable.java
index fdcc944..16888c1 100644
--- a/src/org/apache/xml/utils/StringToIntTable.java
+++ b/src/org/apache/xml/utils/StringToIntTable.java
@@ -64,8 +64,6 @@
 public class StringToIntTable
 {
 
-  public static final int INVALID_KEY = -10000;
-  
   /** Block size to allocate          */
   private int m_blocksize;
 
@@ -157,8 +155,7 @@
    *
    * @param key String to look for
    *
-   * @return The String's int value
-   * 
+   * @return The String's int value or a bogus value if not found 
    */
   public final int get(String key)
   {
@@ -169,7 +166,7 @@
         return m_values[i];
     }
 
-	return INVALID_KEY;
+    return -10000;  // Bogus value, needs to throw exception.
   }
 
   /**
@@ -177,13 +174,13 @@
    *
    * @param key String to look for
    *
-   * @return The string's int value
+   * @return The string's int value, or a bogus value if not found
    */
   public final int getIgnoreCase(String key)
   {
 
     if (null == key)
-        return INVALID_KEY;
+      return -10000;  // Bogus value, needs to throw exception.
 
     for (int i = 0; i < m_firstFree; i++)
     {
@@ -191,7 +188,7 @@
         return m_values[i];
     }
 
-    return INVALID_KEY;
+    return -10000;  // Bogus value, needs to throw exception.
   }
 
   /**
@@ -212,21 +209,4 @@
 
     return false;
   }
-  
-  /**
-   * Return array of keys in the table.
-   * 
-   * @return Array of strings
-   */
-  public final String[] keys()
-  {
-    String [] keysArr = new String[m_firstFree];
-
-    for (int i = 0; i < m_firstFree; i++)
-    {
-      keysArr[i] = m_map[i];
-    }
-
-    return keysArr;
-  }  
 }
diff --git a/src/org/apache/xml/utils/SystemIDResolver.java b/src/org/apache/xml/utils/SystemIDResolver.java
index 7f2691c..9d295e5 100644
--- a/src/org/apache/xml/utils/SystemIDResolver.java
+++ b/src/org/apache/xml/utils/SystemIDResolver.java
@@ -263,8 +263,8 @@
     // Not so sure if this is good.  But, for now, I'll try it. We really must 
     // make sure the return from this function is a URL!
     if((Character.isLetter(uriStr.charAt(0)) && (uriStr.charAt(1) == ':') 
-     && (uriStr.charAt(2) == '/') && (uriStr.length() == 3 || uriStr.charAt(3) != '/'))
-       || ((uriStr.charAt(0) == '/') && (uriStr.length() == 1 || uriStr.charAt(1) != '/')))
+     && (uriStr.charAt(2) == '/') && (uriStr.charAt(3) != '/'))
+       || ((uriStr.charAt(0) == '/') && (uriStr.charAt(1) != '/')))
     {
     	uriStr = "file:///"+uriStr;
     }
diff --git a/src/org/apache/xml/utils/TreeWalker.java b/src/org/apache/xml/utils/TreeWalker.java
index 7eed85d..7457a6c 100644
--- a/src/org/apache/xml/utils/TreeWalker.java
+++ b/src/org/apache/xml/utils/TreeWalker.java
@@ -71,7 +71,6 @@
  * This class does a pre-order walk of the DOM tree, calling a ContentHandler
  * interface as it goes.
  */
-
 public class TreeWalker
 {
 
@@ -168,13 +167,8 @@
   }
 
   /**
-   * Perform a pre-order traversal non-recursive style.  
+   * Perform a pre-order traversal non-recursive style.
    *
-   * Note that TreeWalker assumes that the subtree is intended to represent 
-   * a complete (though not necessarily well-formed) document and, during a 
-   * traversal, startDocument and endDocument will always be issued to the 
-   * SAX listener.
-   *  
    * @param pos Node in the tree where to start traversal
    *
    * @throws TransformerException
@@ -182,8 +176,6 @@
   public void traverse(Node pos) throws org.xml.sax.SAXException
   {
 
-   	this.m_contentHandler.startDocument();
-
     Node top = pos;
 
     while (null != pos)
@@ -219,16 +211,10 @@
 
       pos = nextNode;
     }
-    this.m_contentHandler.endDocument();
   }
 
   /**
    * Perform a pre-order traversal non-recursive style.
-
-   * Note that TreeWalker assumes that the subtree is intended to represent 
-   * a complete (though not necessarily well-formed) document and, during a 
-   * traversal, startDocument and endDocument will always be issued to the 
-   * SAX listener.
    *
    * @param pos Node in the tree where to start traversal
    * @param top Node in the tree where to end traversal
@@ -238,8 +224,6 @@
   public void traverse(Node pos, Node top) throws org.xml.sax.SAXException
   {
 
-	this.m_contentHandler.startDocument();
-	
     while (null != pos)
     {
       startNode(pos);
@@ -270,7 +254,6 @@
 
       pos = nextNode;
     }
-    this.m_contentHandler.endDocument();
   }
 
   /** Flag indicating whether following text to be processed is raw text          */
@@ -342,7 +325,7 @@
       // ??;
       break;
     case Node.DOCUMENT_NODE :
-    
+      this.m_contentHandler.startDocument();
       break;
     case Node.ELEMENT_NODE :
       NamedNodeMap atts = ((Element) node).getAttributes();
@@ -471,8 +454,8 @@
     switch (node.getNodeType())
     {
     case Node.DOCUMENT_NODE :
+      this.m_contentHandler.endDocument();
       break;
-      
     case Node.ELEMENT_NODE :
       String ns = m_dh.getNamespaceOfNode(node);
       if(null == ns)
diff --git a/src/org/apache/xml/utils/URI.java b/src/org/apache/xml/utils/URI.java
index e4ae1a2..30b142f 100644
--- a/src/org/apache/xml/utils/URI.java
+++ b/src/org/apache/xml/utils/URI.java
@@ -91,6 +91,7 @@
  * default port for a specific scheme). Rather, it only knows the
  * grammar and basic set of operations that can be applied to a URI.
  *
+ * @version  $Id$
  *
  */
 public class URI implements Serializable
diff --git a/src/org/apache/xml/utils/synthetic/JavaUtils.java b/src/org/apache/xml/utils/synthetic/JavaUtils.java
index a0a9267..b397454 100644
--- a/src/org/apache/xml/utils/synthetic/JavaUtils.java
+++ b/src/org/apache/xml/utils/synthetic/JavaUtils.java
@@ -54,6 +54,7 @@
  * information on the Apache Software Foundation, please see
  * <http://www.apache.org/>. 
  *
+ * $Id$ 
  */
 
 package org.apache.xml.utils.synthetic;