blob: 6b75daabc6e9eca2d06d03d77f658bc5daed7f51 [file] [log] [blame]
/*
* 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 java.util.Hashtable;
import java.util.Vector;
import javax.xml.transform.Source;
import javax.xml.transform.SourceLocator;
import org.apache.xalan.transformer.XalanProperties;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.res.XSLMessages;
import org.apache.xml.dtm.*;
import org.apache.xml.dtm.ref.*;
import org.apache.xml.utils.StringVector;
import org.apache.xml.utils.IntVector;
import org.apache.xml.utils.FastStringBuffer;
import org.apache.xml.utils.IntStack;
import org.apache.xml.utils.SuballocatedIntVector;
import org.apache.xml.utils.SystemIDResolver;
import org.apache.xml.utils.WrappedRuntimeException;
import org.apache.xml.utils.XMLCharacterRecognizer;
import org.apache.xml.utils.SparseVector;
//import org.xml.sax.*;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
//import org.xml.sax.ext.*;
import org.apache.xerces.xni.*;
import org.apache.xerces.xni.psvi.*;
import org.apache.xerces.xni.parser.XMLPullParserConfiguration;
import org.apache.xerces.xni.parser.XMLErrorHandler;
import org.apache.xerces.xni.parser.XMLParseException;
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.validation.ValidationContext;
import org.apache.xerces.impl.validation.ValidationState;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
/**
* 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.
*
* 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 SAX2DTM?
* Should we merge that with SAX2RTFDTM? "And what about Naomi?"
*/
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 = true;
/** %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 expectedType Xerces Schema type object as declared in the schema
* %REVIEW% NOTE that the 3/28/03 query datamodel no longer records the
* type-as-declared, so this field can probably be eliminated!
* @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
* */
public XSequence 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 XSequence.EMPTY;
XPath2Type actualType=(XPath2Type)m_schemaTypeOverride.elementAt(identity);
if(actualType==null)
actualType=(XPath2Type)m_expandedNameTable.getSchemaType(m_exptype.elementAt(identity));
if(actualType==null)
return XSequence.EMPTY;
/* %REVIEW% Efficiency issues; value may be in FSB, in which case
generating a Java String may arguably be wasteful. */
//GONK lists;
//GONK efficiency;
String textvalue=getNodeValue(nodeHandle);
return actualType.typedValue(textvalue);
}
//===========================================================================
/** 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;
XSTypeDecl 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();
org.apache.xerces.impl.xs.XSElementDecl expectedDecl = // %REVIEW% OBSOLETE?
(elemPSVI==null) ? null : elemPSVI.getElementDecl();
XSTypeDecl expectedType = // %REVIEW% OBSOLETE?
(expectedDecl==null) ? actualType : expectedDecl.fType;
if (DEBUG)
{
String actualExpandedQName=xp2type.getTargetNamespace()+":"+xp2type.getTypeName();
System.out.println("\ttypeDefinition (actual): "+ actualType +
"\n\t\ttype expanded-qname: " + actualExpandedQName +
"\n\telementDecl (expected): " + expectedDecl +
"\n\tDerived from expected (after null recovery): " + actualType.derivedFrom(expectedType) +
"\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);
XSTypeDecl actualAttrType=(attrPSVI==null) ? null : attrPSVI.getTypeDefinition();
org.apache.xerces.impl.xs.XSAttributeDecl expectedAttrDecl= // %REVIEW% Obsolete?
(attrPSVI==null) ? null : attrPSVI.getAttributeDecl();
XSTypeDecl expectedType=(expectedAttrDecl==null) ? actualAttrType : expectedAttrDecl.fType;
String actualExpandedQName=(actualAttrType==null) ? null : actualAttrType.getTargetNamespace()+":"+actualAttrType.getTypeName();
// 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 +
"\n\t\tattrDecl (expected): " + expectedAttrDecl
);
if(actualAttrType!=null)
System.out.println("\n\t\tDerived from expected (after null recovery): " + actualAttrType.derivedFrom(expectedType) +
"\n\t\tDerived from builtin string: "+ actualAttrType.derivedFrom(SCHEMANS,"string") +
"\n\t\tTyped value: " + xp2attrtype.typedValue(attributes.getValue(i))+
"\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;
}
else
{
nodeType = DTM.ATTRIBUTE_NODE;
if (attributes.getType(i).equalsIgnoreCase("ID"))
setIDAttribute(valString, elemNode);
}
// 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;
}
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!
}
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);
}
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.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each element (such as finalising a tree node or writing
* output to a file).</p>
*
* @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);
}
// 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.
{
// After super.endElement, m_previous is the element we're ending.
// Try to record as default for this nodetype
ElementPSVImpl elemPSVI=null;
XSTypeDecl actualType =null;
if(augs!=null)
{
elemPSVI=(ElementPSVImpl)augs.getItem(org.apache.xerces.impl.Constants.ELEMENT_PSVI);
actualType =
(elemPSVI==null) ? null : elemPSVI.getTypeDefinition();
}
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% Is there anyway to get the JAXP error listener here?
System.err.println(exception);
}
public void error(java.lang.String domain,
java.lang.String key,
XMLParseException exception)
throws XNIException
{
throw exception;
}
public void fatalError(java.lang.String domain,
java.lang.String key,
XMLParseException exception)
throws XNIException
{
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(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");
}
//============================================================/
/** Inner class: 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!
* */
protected class XPath2Type
{
public XSTypeDecl 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. Need to go down a level...
// not sure whether there's a shared interface
if(psvi==null)
m_xniType=null;
else if(!isAttr)
m_xniType=((ElementPSVImpl)psvi).getTypeDefinition();
else
m_xniType=((AttributePSVImpl)psvi).getTypeDefinition();
// Now resolve the typename.
// There are some quibbles about algorithm; see comments on
// the resolve methods.
lightResolveTypeName(psvi,isAttr);
}
/** 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_namespace.equals(other.m_namespace) &&
m_localName.equals(other.m_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 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!=null)
return m_xniType.derivedFrom(namespace,localname);
// Fallback in case no PSVI info was passed in: exact match
// (it's got to be the correct m_any*Type).
else return(m_namespace.equals(namespace) && m_localName.equals(localname));
}
/** 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.
*
* @param actualType Xerces PSVI type declaration object
* @param textValue Text content to be interpreted
* @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 XSequence typedValue(String textvalue)
{
Object value;
DTM_XSequence seq=null;
if(m_xniType instanceof XSSimpleTypeDecl)
{
//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 we need to get appropriate validation context while validating content
//validation context passed is generally different while validating content and creating simple type (applyFacets)
ValidationContext validationState = new ValidationState();
// This may need to be refined using:
//validationState.setNamespaceSupport(...);
//validationState.setSymbolTable(....);
//validationState.setFacetChecking(true);
//validationState.setExtraChecking(false);
// Validate and parse the string
try{
((XSSimpleTypeDecl)m_xniType).validate(textvalue, validationState, validatedInfo);
} catch(InvalidDatatypeValueException ex){
// Should never happen, since we've already validated...?
System.err.println(ex.getMessage());
ex.printStackTrace();
}
//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,(XSSimpleTypeDecl)m_xniType);
}
return seq==null ? XSequence.EMPTY : seq;
}
/** Implementation of the XPath2 type-name resolution algorithm
* (data model 3.5).
*
* Code donated by Sandy Gao, using the proposed
* Heavy-Weight PSVI interfaces (not yet implemented in 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)
{
/* 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) {
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) {
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"); /**/
}
/** 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 proposed
* Heavy-Weight PSVI interfaces (not yet implemented in 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 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 currently supported in Xerces (which I believe will be
* phased out when heavyweight come into play).
*
* Basd 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"); /**/
}
} // XPath2Type
} // XNI2DTM