blob: 0f318a8eaa98d05084079399cd06feb51b7e9937 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 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 "Apache" 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
* XMLBeans", 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) 2000-2003 BEA Systems
* Inc., <http://www.bea.com/>. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xmlbeans.impl.store;
import java.lang.reflect.Method;
import org.apache.xmlbeans.impl.common.EncodingMap;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.common.XMLNameHelper;
import org.apache.xmlbeans.impl.store.Splay.Finish;
import org.apache.xmlbeans.impl.values.NamespaceManager;
import org.apache.xmlbeans.impl.values.XmlStore;
import org.apache.xmlbeans.impl.values.TypeStoreFactory;
import org.apache.xmlbeans.QNameCache;
import org.apache.xmlbeans.QNameSet;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeLoader;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlCursor.XmlBookmark;
import org.apache.xmlbeans.XmlDocumentProperties;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlLineNumber;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlRuntimeException;
import org.apache.xmlbeans.XmlSaxHandler;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import weblogic.xml.stream.Attribute;
import weblogic.xml.stream.AttributeIterator;
import weblogic.xml.stream.CharacterData;
import weblogic.xml.stream.Location;
import weblogic.xml.stream.ProcessingInstruction;
import weblogic.xml.stream.Space;
import weblogic.xml.stream.StartDocument;
import weblogic.xml.stream.StartElement;
import weblogic.xml.stream.XMLEvent;
import weblogic.xml.stream.XMLInputStream;
import weblogic.xml.stream.XMLName;
import weblogic.xml.stream.XMLStreamException;
import javax.xml.namespace.QName;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
public final class Root extends Finish implements XmlStore
{
public Root ( SchemaTypeLoader stl, SchemaType type, XmlOptions options )
{
super( ROOT );
assert stl != null;
_schemaTypeSystem = stl;
_leftOnly = true;
_props = new DocProps();
_doc = new Doc( this, null );
_leftSplay = _doc;
_doc._parentSplay = this;
adjustCdocBeginLeft( _doc.getCdocBegin() );
_text = new Text();
SchemaType sType = null;
options = XmlOptions.maskNull( options );
if (options.hasOption( XmlOptions.DOCUMENT_TYPE ))
sType = (SchemaType) options.get( XmlOptions.DOCUMENT_TYPE );
if (sType == null)
sType = type;
if (sType == null)
sType = XmlObject.type;
_validateOnSet = options.hasOption( XmlOptions.VALIDATE_ON_SET );
_factory = (TypeStoreFactory) options.get( TypeStoreFactory.KEY );
_doc.setType( this, sType );
}
public static XmlStore newStore ( SchemaTypeLoader stl, SchemaType type, XmlOptions options )
{
return new Root( stl, type, options );
}
public XmlDocumentProperties documentProperties ( )
{
return _props;
}
public XmlCursor createCursor ( )
{
assert validate();
return new Cursor( this, _doc );
}
Container getContainer ( ) { return _doc; }
boolean validateOnSet ( ) { return _validateOnSet; }
public XmlObject getObject ( )
{
Type t = _doc.peekType();
return t == null ? null : t.getXmlObject();
}
public SchemaTypeLoader getSchemaTypeLoader ( )
{
return _schemaTypeSystem;
}
boolean isEmpty ( )
{
return _leftSplay == _doc && _doc._rightSplay == null && _doc.isValid();
}
boolean isLeftOnly ( ) { return _leftOnly; }
void ensureEmpty ( )
{
if (!isEmpty())
_doc.removeContent( this, true );
assert isEmpty();
assert validate();
assert _leftOnly;
assert getCchLeft() == 0;
assert _text.length() == 0;
assert getCdocBeginLeft() == 1;
assert _doc != null && _leftSplay == _doc;
}
void updateCch ( Splay s, int deltaCch )
{
assert !s.isRoot();
if (deltaCch != 0)
{
s.splay( this, this );
s.adjustCch( deltaCch );
adjustCchLeft( deltaCch );
}
}
int getCp ( Splay s )
{
//
// A left only tree has the nice property that _cchLeft is
// also the cp!
//
if (!_leftOnly && s != this)
s.splay( this, this );
return s.getCchLeft();
}
int getDocBeginIndex ( Splay s )
{
//
// A left only tree has the nice property that cdocBeginLeft is
// also the pos!
//
if (!_leftOnly)
s.splay( this, this );
return s.getCdocBeginLeft();
}
Begin findNthBegin ( Splay parent, QName name, QNameSet set, int n )
{
// only one of (set or name) is not null
// or both are null for a wildcard
assert ( name == null || set == null );
assert n >= 0;
if (parent == null || parent.isLeaf())
return null;
int da = _nthCache_A.distance( parent, name, set, n );
int db = _nthCache_B.distance( parent, name, set, n );
Begin b =
da <= db
? _nthCache_A.fetch( parent, name, set, n )
: _nthCache_B.fetch( parent, name, set, n );
if (da == db)
{
nthCache temp = _nthCache_A;
_nthCache_A = _nthCache_B;
_nthCache_B = temp;
}
return b;
}
int count ( Container parent, QName name, QNameSet set )
{
Splay s = findNthBegin( parent, name, set, 0 );
if (s == null)
return 0;
int n = 0;
for ( ; ; s = s.nextSplay() )
{
if (s.isFinish())
break;
if (!s.isBegin())
continue;
if (set == null)
{
if (s.getName().equals(name))
n++;
}
else
{
if (set.contains(s.getName()))
n++;
}
s = s.getFinishSplay();
}
return n;
}
/**
* Set up strong type information based on this schema type system.
*/
private boolean namespacesSame ( QName n1, QName n2 )
{
if (n1 == n2)
return true;
if (n1 == null || n2 == null)
return false;
if (n1.getNamespaceURI() == n2.getNamespaceURI())
return true;
if (n1.getNamespaceURI() == null || n2.getNamespaceURI() == null)
return false;
return n1.getNamespaceURI().equals( n2.getNamespaceURI() );
}
private void addNamespace ( StringBuffer sb, QName name )
{
if (name.getNamespaceURI() == null)
sb.append( "<no namespace>" );
else
{
sb.append( "\"" );
sb.append( name.getNamespaceURI() );
sb.append( "\"" );
}
}
XmlObject autoTypedDocument (
SchemaType factoryType, XmlOptions options )
throws XmlException
{
// The type in the options has highest precidence because it is
// supplied by the user.
SchemaType overrideType =
(SchemaType) XmlOptions.safeGet( options, XmlOptions.DOCUMENT_TYPE );
// precedence is given to the override above all
SchemaType theType = overrideType;
// Document and attribute types have no name
if (theType == null &&
(factoryType == null ||
(!factoryType.isDocumentType() &&
!factoryType.isAttributeType())))
{
// infer type from xsi:type
QName typeName = _doc.getXsiTypeName( this );
SchemaType sniffedType =
typeName == null
? null
: _schemaTypeSystem.findType( typeName );
if (factoryType == null ||
factoryType.isAssignableFrom( sniffedType ))
{
theType = sniffedType;
}
}
// todo:
// use the following when implementing subst groups:
// factoryType == null || expectedType.isDocumentType()
if (factoryType == null || factoryType.isDocumentType())
{
if (theType == null)
{
// infer type based on root elt
QName docElemName = null;
XmlCursor c = createCursor();
if (c.toFirstChild() && !c.toNextSibling())
docElemName = c.getName();
c.dispose();
if (docElemName != null)
theType = _schemaTypeSystem.findDocumentType( docElemName );
// verify elt inheritance when implementing subst groups
if (factoryType != null && theType != null)
{
QName factoryElemName = factoryType.getDocumentElementName();
if (!factoryElemName.equals(docElemName) &&
!factoryType.isValidSubstitution(docElemName))
throw new XmlException("Element " + QNameHelper.pretty(docElemName) +
" is not a valid " + QNameHelper.pretty(factoryElemName) +
" document or a valid substitution.");
}
}
if (theType == null)
{
// infer type based on root attr
QName attrName = null;
XmlCursor c = createCursor();
if (c.toFirstAttribute() && !c.toNextAttribute())
attrName = c.getName();
c.dispose();
if (attrName != null)
theType = _schemaTypeSystem.findAttributeType( attrName );
}
}
// sniffing doesn't say anything: assume the expected type
if (theType == null)
theType = factoryType;
// Still nothing: the no type.
if (theType == null)
theType = XmlBeans.NO_TYPE;
// assign type
_doc.setType( this, theType );
// todo: Have a similar attribute type check
if (factoryType != null)
{
if (theType.isDocumentType())
verifyDocumentType( theType.getDocumentElementName() );
else if (theType.isAttributeType())
verifyAttributeType( theType.getAttributeTypeAttributeName() );
}
//
// If a type was passed in, usually from generated code which needs the
// type to be something specific because of a pending cast, then check
// the resulting type and throw a nice exception.
//
if (factoryType != null && !factoryType.isAssignableFrom(theType))
{
/*
System.out.println("Factory type = " + factoryType);
System.out.println("The type = " + theType);
System.out.println("basetype of the type = " + theType.getBaseType());
*/
throw
new XmlException( "XML object is not of type " + factoryType );
}
return getObject();
}
private void verifyDocumentType ( QName docElemName )
throws XmlException
{
XmlCursor c = createCursor();
try
{
StringBuffer sb = null;
if (!c.toFirstChild() || c.toNextSibling())
{
sb = new StringBuffer();
sb.append( "The document is not a " );
sb.append( QNameHelper.pretty( docElemName ) );
if (c.currentTokenType().isStartdoc())
sb.append( ": no document element" );
else
sb.append( ": multiple document elements" );
}
else
{
QName name = c.getName();
if (!name.equals( docElemName ))
{
sb = new StringBuffer();
sb.append( "The document is not a " );
sb.append( QNameHelper.pretty( docElemName ) );
if (docElemName.getLocalPart().equals( name.getLocalPart() ))
{
sb.append( ": document element namespace mismatch " );
sb.append( "expected " );
addNamespace( sb, docElemName );
sb.append( " got " );
addNamespace(sb, name );
}
else if (namespacesSame( docElemName, name ))
{
sb.append( ": document element local name mismatch " );
sb.append( "expected " + docElemName.getLocalPart() );
sb.append( " got " + name.getLocalPart() );
}
else
{
sb.append( ": document element mismatch " );
sb.append( "got " );
sb.append( QNameHelper.pretty( name ) );
}
}
}
if (sb != null)
{
XmlError err = XmlError.forCursor(sb.toString(), c.newCursor());
throw new XmlException( err.toString(), null, err );
}
}
finally
{
c.dispose();
}
}
private void verifyAttributeType ( QName attrName )
throws XmlException
{
XmlCursor c = createCursor();
try
{
StringBuffer sb = null;
if (!c.toFirstAttribute() || c.toNextAttribute())
{
sb = new StringBuffer();
sb.append( "The document is not a " );
sb.append( QNameHelper.pretty( attrName ) );
if (c.currentTokenType().isStartdoc())
sb.append( ": no attributes" );
else
sb.append( ": multiple attributes" );
}
else
{
QName name = c.getName();
if (!name.equals( attrName ))
{
sb = new StringBuffer();
sb.append( "The document is not a " );
sb.append( QNameHelper.pretty( attrName ) );
if (attrName.getLocalPart().equals( name.getLocalPart() ))
{
sb.append( ": attribute namespace mismatch " );
sb.append( "expected " );
addNamespace( sb, attrName );
sb.append( " got " );
addNamespace(sb, name );
}
else if (namespacesSame( attrName, name ))
{
sb.append( ": attribute local name mismatch " );
sb.append( "expected " + attrName.getLocalPart() );
sb.append( " got " + name.getLocalPart() );
}
else
{
sb.append( ": attribute element mismatch " );
sb.append( "got " );
sb.append( QNameHelper.pretty( name ) );
}
}
}
if (sb != null)
{
XmlError err = XmlError.forCursor(sb.toString(), c.newCursor());
throw new XmlException( err.toString(), null, err );
}
}
finally
{
c.dispose();
}
}
//
//
//
private static ThreadLocal tl_SaxLoaders =
new ThreadLocal()
{
protected Object initialValue()
{
SaxLoader sl = PiccoloSaxLoader.newInstance();
if (sl == null)
sl = DefaultSaxLoader.newInstance();
if (sl == null)
throw new RuntimeException( "Can't find an XML parser" );
return sl;
}
};
private static SaxLoader getSaxLoader ( )
{
return (SaxLoader) tl_SaxLoaders.get();
}
private static class PiccoloSaxLoader extends SaxLoader
{
public static SaxLoader newInstance ( )
{
try
{
Class pc = Class.forName( "com.bluecast.xml.Piccolo" );
XMLReader xr = (XMLReader) pc.newInstance();
Method m_getEncoding = pc.getMethod( "getEncoding", null );
Method m_getVersion = pc.getMethod( "getVersion", null );
Method m_getStartLocator = pc.getMethod( "getStartLocator", null );
Locator startLocator =
(Locator) m_getStartLocator.invoke( xr, null );
return new PiccoloSaxLoader( xr, startLocator, m_getEncoding, m_getVersion );
}
catch ( ClassNotFoundException e )
{
return null;
}
catch ( Exception e )
{
throw new RuntimeException( e.getMessage(), e );
}
}
protected void postLoad ( Root r )
{
try
{
r._props.setEncoding( (String) _m_getEncoding.invoke( _xr, null ) );
r._props.setVersion ( (String) _m_getVersion .invoke( _xr, null ) );
}
catch ( Exception e )
{
throw new RuntimeException( e.getMessage(), e );
}
}
private PiccoloSaxLoader (
XMLReader xr, Locator startLocator, Method m_getEncoding, Method m_getVersion )
{
super( xr, startLocator );
_m_getEncoding = m_getEncoding;
_m_getVersion = m_getVersion;
}
private Method _m_getEncoding;
private Method _m_getVersion;
}
private static class DefaultSaxLoader extends SaxLoader
{
public static SaxLoader newInstance ( )
{
try
{
return
new DefaultSaxLoader(
SAXParserFactory.newInstance().newSAXParser().getXMLReader() );
}
catch ( Throwable e )
{
throw new RuntimeException( e.getMessage(), e );
}
}
private DefaultSaxLoader ( XMLReader xr )
{
super( xr, null );
}
}
private static class SaxLoader
implements ContentHandler, LexicalHandler, ErrorHandler, EntityResolver
{
protected SaxLoader ( XMLReader xr, Locator startLocator )
{
_xr = xr;
_startLocator = startLocator;
if (xr != null)
{
try
{
xr.setFeature( "http://xml.org/sax/features/namespace-prefixes", true );
xr.setFeature( "http://xml.org/sax/features/namespaces", true );
xr.setFeature( "http://xml.org/sax/features/validation", false );
xr.setProperty( "http://xml.org/sax/properties/lexical-handler", this );
xr.setContentHandler( this );
xr.setErrorHandler( this );
xr.setEntityResolver( this );
}
catch ( Throwable e )
{
throw new RuntimeException( e.getMessage(), e );
}
}
}
protected void setContext ( LoadContext context, XmlOptions options )
{
_context = context;
_wantLineNumbers =
XmlOptions.maskNull(
options ).hasOption( XmlOptions.LOAD_LINE_NUMBERS ) &&
_startLocator != null;
}
protected void postLoad ( Root r )
{
}
public void load ( Root r, InputSource inputSource, XmlOptions options )
throws IOException, XmlException
{
LoadContext context = new LoadContext( r, options );
setContext( context, options );
try
{
assert r.disableStoreValidation();
_xr.parse( inputSource );
postLoad( r );
// // Piccolo specific access to encoding and version
// _props.setEncoding( piccolo.getEncoding() );
// _props.setVersion( piccolo.getVersion() );
context.finish();
r.associateSourceName( options );
}
catch ( XmlRuntimeException e )
{
context.abort();
throw new XmlException( e );
}
catch ( SAXParseException e )
{
context.abort();
XmlError err =
XmlError.forLocation(
e.getMessage(),
(String) XmlOptions.safeGet( options, XmlOptions.DOCUMENT_SOURCE_NAME ),
e.getLineNumber(), e.getColumnNumber(), -1 );
throw new XmlException( err.toString(), e, err );
}
catch ( SAXException e )
{
context.abort();
XmlError err = XmlError.forMessage( e.getMessage() );
throw new XmlException( err.toString(), e, err );
}
catch ( RuntimeException e )
{
context.abort();
throw e;
}
finally
{
assert r.enableStoreValidation();
}
}
// Sax ContentHandler
public void startDocument ( ) throws SAXException
{
}
public void endDocument ( ) throws SAXException
{
// Set context to null
// This prevents the handler (which is held in TLS from keeping
// the entire document in memory
_context = null;
}
public void startElement (
String namespaceURI, String localName,
String qName, Attributes atts )
throws SAXException
{
if (localName.length() == 0)
localName = qName;
// Out current parser (Piccolo) does not error when a
// namespace is used and not defined. Check for these here
if (qName.indexOf( ':' ) >= 0 && namespaceURI.length() == 0)
{
XmlError err =
XmlError.forMessage(
"Use of undefined namespace prefix: " +
qName.substring( 0, qName.indexOf( ':' ) ));
throw new XmlRuntimeException( err.toString(), null, err );
}
_context.begin( localName, namespaceURI );
// BUGBUG - do more of the following to get line number for
// as many parts of the XML as we can
if (_wantLineNumbers)
{
_context.lineNumberAnnotation(
_startLocator.getLineNumber(),
_startLocator.getColumnNumber(),
-1 );
}
for ( int i = 0, len = atts.getLength() ; i < len ; i++ )
{
String aqn = atts.getQName( i );
if (aqn.equals( "xmlns" ))
{
_context.xmlns( "", atts.getValue( i ) );
}
else if (aqn.startsWith( "xmlns:" ))
{
String prefix = aqn.substring( 6 );
if (prefix.length() == 0)
{
XmlError err =
XmlError.forMessage( "Prefix not specified", XmlError.SEVERITY_ERROR );
throw new XmlRuntimeException( err.toString(), null, err );
}
String uri = atts.getValue( i );
if (uri.length() == 0)
{
XmlError err =
XmlError.forMessage(
"Prefix can't be mapped to no namespace: " + prefix,
XmlError.SEVERITY_ERROR );
throw new XmlRuntimeException( err.toString(), null, err );
}
_context.xmlns( prefix, uri );
}
else
{
String attrUri = atts.getURI( i );
String attrLocal = atts.getLocalName( i );
if (attrLocal.length() == 0)
attrLocal = aqn;
// given the doc <a x:y='z'/>, piccolo will report the uri of the y
// attribute as 'x'! Bad Piccolo. Thus, I can't perform the undefined
// prefix check here.
//
// if (aqn.indexOf( ':' ) >= 0 && attrUri.length() == 0)
// {
// XmlError err =
// new CursorXmlError(
// "Use of undefined namespace prefix: " +
// aqn.substring( 0, aqn.indexOf( ':' ) ),
// XmlError.SEVERITY_ERROR,
// null );
//
// throw
// new XmlRuntimeException(
// err.toString(), null, err );
// }
_context.attr( attrLocal, attrUri, atts.getValue( i ) );
}
}
}
public void endElement (
String namespaceURI, String localName, String qName )
throws SAXException
{
_context.end();
}
public void characters ( char ch[], int start, int length )
throws SAXException
{
_context.text( ch, start, length );
}
public void ignorableWhitespace ( char ch[], int start, int length )
throws SAXException
{
_context.text( ch, start, length );
}
public void comment ( char ch[], int start, int length )
throws SAXException
{
_context.comment( ch, start, length );
}
public void processingInstruction ( String target, String data )
throws SAXException
{
_context.procinst( target, data );
}
public void startDTD ( String name, String publicId, String systemId )
throws SAXException
{
_context.doctype( name, publicId, systemId );
}
public void endDTD ( ) throws SAXException
{
}
// Error Handling
public void fatalError ( SAXParseException e ) throws SAXException
{
throw e;
}
public void error ( SAXParseException e ) throws SAXException
{
XmlError err =
XmlError.forMessage( "Error: " + e.getMessage(), XmlError.SEVERITY_ERROR );
throw new XmlRuntimeException( err.toString(), null, err );
}
public void warning ( SAXParseException e ) throws SAXException
{
// Throw away warings for now
}
// Entity Resolver
public InputSource resolveEntity( String publicId, String systemId )
{
// System.out.println("public id = " + publicId);
// System.out.println("system id = " + systemId);
return new InputSource( new StringReader( "" ) );
}
public void setDocumentLocator ( Locator locator )
{
_locator = locator;
}
public void startPrefixMapping ( String prefix, String uri )
throws SAXException
{
if (beginsWithXml( prefix ) &&
! ( "xml".equals( prefix ) && _xml1998Uri.equals( uri ) ))
{
XmlError err =
XmlError.forMessage(
"Prefix can't begin with XML: " + prefix,
XmlError.SEVERITY_ERROR );
throw
new XmlRuntimeException(
err.toString(), null, err );
}
}
// Ignored
public void endPrefixMapping ( String prefix ) throws SAXException {}
public void skippedEntity ( String name ) throws SAXException {}
public void startCDATA ( ) throws SAXException { }
public void endCDATA ( ) throws SAXException { }
public void startEntity ( String name ) throws SAXException { }
public void endEntity ( String name ) throws SAXException { }
protected XMLReader _xr;
private Locator _locator;
private LoadContext _context;
private boolean _wantLineNumbers;
private Locator _startLocator;
}
//
//
//
public XmlObject loadXml ( InputStream in, SchemaType type, XmlOptions options )
throws IOException, XmlException
{
String encodingOverride =
(String) XmlOptions.safeGet( options, XmlOptions.CHARACTER_ENCODING );
if (encodingOverride != null)
{
String javaEncoding = EncodingMap.getIANA2JavaMapping( encodingOverride );
if (javaEncoding == null)
javaEncoding = encodingOverride;
return loadXml( new InputStreamReader( in, javaEncoding ), type, options );
}
return loadXml( new InputSource( in ), type, options );
}
public XmlObject loadXml ( Reader r, SchemaType type, XmlOptions options )
throws IOException, XmlException
{
return loadXml( new InputSource( r ), type, options );
}
public XmlObject loadXml ( InputSource is, SchemaType type, XmlOptions options )
throws IOException, XmlException
{
is.setSystemId( "file://" );
getSaxLoader().load( this, is, options );
return autoTypedDocument( type, options );
}
public XmlObject loadXml ( String s, SchemaType type, XmlOptions options )
throws XmlException
{
Reader r = new StringReader( s );
try
{
return loadXml( r, type, options );
}
catch ( IOException e )
{
assert false: "StringReader should not throw IOException";
throw new XmlException( e.getMessage(), e );
}
finally
{
try { r.close(); } catch ( IOException e ) { }
}
}
private void associateSourceName ( XmlOptions options )
{
String sourceName =
(String) XmlOptions.safeGet(
options, XmlOptions.DOCUMENT_SOURCE_NAME );
if (sourceName != null)
_props.setSourceName( sourceName );
}
//
// XmlSaxHandler is returned to a user so that user may obtain the content
// and lexical handlers to push content and then get the XmlObject at the
// end of the parse push.
//
private class XmlSaxHandlerImpl extends SaxLoader implements XmlSaxHandler
{
XmlSaxHandlerImpl ( SchemaType type, XmlOptions options )
{
super( null, null );
assert isEmpty();
_options = options;
_type = type;
_context = new LoadContext( Root.this, options );
setContext( _context, options );
}
public ContentHandler getContentHandler ( )
{
return _context == null ? null : this;
}
public LexicalHandler getLexicalHandler ( )
{
return _context == null ? null : this;
}
public XmlObject getObject ( ) throws XmlException
{
if (_context == null)
return null;
_context.finish();
_context = null;
Root.this.associateSourceName( _options );
return Root.this.autoTypedDocument( _type, _options );
}
private LoadContext _context;
private SchemaType _type;
private XmlOptions _options;
}
public XmlSaxHandler newSaxHandler ( SchemaType type, XmlOptions options )
{
return new XmlSaxHandlerImpl( type, options );
}
//
//
//
private void newParseSax ( InputSource in, XmlOptions options )
{
LoadContext context = new LoadContext( this, options );
}
//
// Helper object for creating documents in a "load" kinda way
//
static final class LoadContext
{
LoadContext ( Root root, XmlOptions options )
{
assert root != null;
_options = options = XmlOptions.maskNull( options );
_qnameCache = XmlBeans.getQNameCache();
if (options.hasOption( XmlOptions.LOAD_REPLACE_DOCUMENT_ELEMENT ))
{
QName name = (QName) options.get( XmlOptions.LOAD_REPLACE_DOCUMENT_ELEMENT );
if (name != null && name.getLocalPart().length() == 0)
{
throw
new IllegalArgumentException(
"Load Replace Document Element: Invalid name, local part empty" );
}
_discardDocElem = true;
_replaceDocElem = name;
}
_stripWhitespace = options.hasOption(XmlOptions.LOAD_STRIP_WHITESPACE);
_stripComments = options.hasOption(XmlOptions.LOAD_STRIP_COMMENTS);
_stripProcinsts = options.hasOption(XmlOptions.LOAD_STRIP_PROCINSTS);
_substituteNamespaces =
(Map) options.get(XmlOptions.LOAD_SUBSTITUTE_NAMESPACES);
_additionalNamespaces =
(Map) options.get(XmlOptions.LOAD_ADDITIONAL_NAMESPACES);
_root = root;
_root.ensureEmpty();
_lastNonAttr = _root._doc;
_lastSplay = _root._doc;
_lastPos = 0;
_frontier = _root._doc;
}
private Root getRoot ( )
{
return _root;
}
private int getCp ( Splay s )
{
assert _root.isLeftOnly();
assert dv > 0 || s.getCpSlow() == s.getCchLeft();
return s.getCchLeft();
}
private void adjustCch ( Splay s, int delta )
{
assert _root.isLeftOnly();
s.adjustCch( delta );
// There may be attrs after this splay which need their cchLeft's
// to be updated. To avoid splaying, update them by hand.
for ( s = s.nextSplay() ; s != null ; s = s.nextSplay() )
{
assert s.isAttr() || s.isRoot();
s.adjustCchLeft( delta );
}
}
private void insert ( Splay s )
{
assert !_finished;
assert s.getCch() == 0;
_root.insertSplay( s, _root._leftSplay );
_lastSplay = s;
_lastPos = 0;
if (!s.isAttr())
_lastNonAttr = s;
}
private void insert ( Splay s, char[] buf, int off, int cch )
{
assert !_finished;
assert s.getCch() == 0;
insert( s );
_root._text.insert( getCp( s ), buf, off, cch );
adjustCch( s, cch );
}
private void insert ( Splay s, String text )
{
assert !_finished;
assert s.getCch() == 0;
insert( s );
_root._text.insert( getCp( s ), text );
adjustCch( s, text.length() );
}
private void stripLeadingWhitespace ( )
{
int cchAfter = _lastNonAttr.getCchAfter();
if (cchAfter > 0)
{
int cch = cchAfter;
int cpAfter =
_lastNonAttr.getCpForPos(
_root, _lastNonAttr.getPosAfter() );
int off = _root._text.unObscure( cpAfter, cch );
for ( ; cch > 0 ; cch-- )
{
if (!isWhiteSpace( _root._text._buf[ off + cch - 1 ]))
break;
}
int delta = cch - cchAfter;
if (delta < 0)
{
_root._text.remove( cpAfter + cchAfter + delta, - delta );
_lastNonAttr.adjustCchAfter( delta );
adjustCch( _lastNonAttr, delta );
}
}
}
void abort ( )
{
// The shit must have hit the fan ...
// Close all elements
while ( _frontier != _root._doc )
end();
try
{
finish();
}
catch ( XmlException e )
{
assert false;
}
}
void finish ( ) throws XmlException
{
if (_stripWhitespace)
stripLeadingWhitespace();
// TODO: deal with unterminated begins here
if (_frontier != _root._doc)
throw new XmlException( "Document not ended" );
assert _root._leftOnly;
_finished = true;
_lastSplay = _root;
_lastPos = 0;
if (_options.hasOption(XmlOptions.LOAD_TRIM_TEXT_BUFFER))
_root._text.trim();
// If we have additional namespaces, add them now, making sure we
// done over ride exisitng ones.
if (_additionalNamespaces != null)
{
Splay s = _root._doc;
while ( !s.isRoot() && !s.isBegin() )
s = s.nextSplay();
if (s.isBegin())
{
java.util.Iterator i =
_additionalNamespaces.keySet().iterator();
while ( i.hasNext() )
{
String prefix = (String) i.next();
// Usually, this is the predefined xml namespace
if (prefix.toLowerCase().startsWith( "xml" ))
continue;
String namespace =
(String) _additionalNamespaces.get( prefix );
if (s.namespaceForPrefix( prefix ) == null)
{
_root.insertSingleSplaySansSplayInLeftOnlyTree(
new Xmlns( new QName( namespace, prefix ) ),
s );
// The above insert should not splay the tree
assert _root.isLeftOnly();
}
}
}
}
// For most of loading, I don't invalidate the document
// version because nothing should be sensitive to it while
// loading. When finished loading, bump it.
_root.invalidateVersion();
assert _root.isLeftOnly();
}
private QName checkName ( String local, String uri )
{
if (_substituteNamespaces != null)
{
String substituteUri =
(String) _substituteNamespaces.get( uri );
if (substituteUri != null)
return _qnameCache.getName( substituteUri, local );
}
return _qnameCache.getName( uri, local );
}
private QName checkName ( QName name )
{
if (_substituteNamespaces != null)
{
String substituteUri =
(String)
_substituteNamespaces.get( name.getNamespaceURI() );
if (substituteUri != null)
{
name =
_qnameCache.getName(
substituteUri, name.getLocalPart() );
}
}
return name;
}
private QName checkNameAttr ( String local, String uri )
{
if (_substituteNamespaces != null && uri.length() > 0)
{
String substituteUri =
(String) _substituteNamespaces.get( uri );
if (substituteUri != null)
return _qnameCache.getName( substituteUri, local );
}
return _qnameCache.getName( uri, local );
}
private QName checkNameAttr ( QName name )
{
if (_substituteNamespaces != null && name.getNamespaceURI().length() > 0 )
{
String substituteUri =
(String)
_substituteNamespaces.get( name.getNamespaceURI() );
if (substituteUri != null)
{
name =
_qnameCache.getName(
substituteUri, name.getLocalPart() );
}
}
return name;
}
void doctype ( String name, String publicID, String systemID )
{
_root._props.setDoctypeName( name );
_root._props.setDoctypePublicId( publicID );
_root._props.setDoctypeSystemId( systemID );
}
private void insertBegin ( QName name )
{
if (_stripWhitespace)
stripLeadingWhitespace();
if (_frontier.isDoc() && !_docElemDiscarded &&
(_discardDocElem || isXmlFragment( name )))
{
_docElemDiscarded = true;
if (_replaceDocElem == null)
{
// Remove all content up to now because the
// document element is to be removed, and I dont
// want that content to mix with the real content.
_root.ensureEmpty();
_lastNonAttr = _root._doc;
_lastSplay = _root._doc;
_lastPos = 0;
_frontier = _root._doc;
return;
}
name = _replaceDocElem;
}
insert( _frontier = new Begin( name, _frontier ) );
}
void begin ( String local, String uri )
{
insertBegin( checkName( local, uri ) );
}
void begin ( QName name )
{
insertBegin( checkName( name ) );
}
void end ( )
{
if (_stripWhitespace)
stripLeadingWhitespace();
if (_frontier.isDoc())
{
if (!_docElemDiscarded)
throw new IllegalStateException( "Too many end elements" );
}
else
{
assert !_finished;
assert _frontier.isBegin();
assert !_frontier.isLeaf();
if (_lastNonAttr == _frontier)
{
_lastSplay = _frontier;
_lastPos = 1 + _frontier.getCch();
_frontier.toggleIsLeaf();
int cch = _frontier.getCchAfter();
_frontier.adjustCchAfter( - cch );
}
else
{
Begin b = (Begin) _frontier;
End e = new End( b );
b._end = e;
insert( e );
}
_frontier = _frontier.getContainer();
}
}
void attr ( QName name, char[] buf, int off, int cch )
{
insert( new Attr( checkNameAttr( name ) ), buf, off, cch );
}
void attr ( QName name, String value )
{
insert( new Attr( checkNameAttr( name ) ), value );
}
void attr ( String local, String uri, String value )
{
insert( new Attr( checkNameAttr( local, uri ) ), value );
}
private boolean discardXmlns ( QName name )
{
return
_docElemDiscarded && _frontier.isDoc() &&
name.getNamespaceURI().equals( _openFragUri );
}
void xmlns ( String prefix, String uri )
{
QName name = checkName( prefix, uri );
if (!discardXmlns( name ))
insert( new Xmlns( name ) );
}
void xmlns ( QName name )
{
name = checkName( name );
if (!discardXmlns( name ))
insert( new Xmlns( name ) );
}
void comment ( char[] buf, int off, int cch )
{
if (!_stripComments)
insert( new Comment(), buf, off, cch );
}
void comment ( String value )
{
if (!_stripComments)
insert( new Comment(), value );
}
void procinst ( String target, char[] buf, int off, int cch )
{
if (!_stripProcinsts)
insert( new Procinst( target ), buf, off, cch );
}
void procinst ( String target, String value )
{
if (!_stripProcinsts)
insert( new Procinst( target ), value );
}
//
// returns the cp where new text should go.
//
int preText ( )
{
assert !_finished;
return getCp( _lastNonAttr ) + _lastNonAttr.getCch();
}
//
// New text has been placed, adjust...
//
void postText ( int cp, int cch )
{
if (_stripWhitespace && _lastNonAttr.getCchAfter() == 0)
{
int off = _root._text.unObscure( cp, cch );
int i = 0;
while ( i < cch && isWhiteSpace( _root._text._buf[ off + i ] ) )
i++;
if (i > 0)
{
_root._text.remove( cp, i );
cch -= i;
}
}
if (cch > 0)
{
_lastSplay = _lastNonAttr;
_lastPos = _lastNonAttr.getEndPos();
_lastNonAttr.adjustCchAfter( cch );
adjustCch( _lastNonAttr, cch );
}
}
void text ( char[] buf, int off, int cch )
{
assert !_finished;
int start = off;
int end = off + cch;
if (_stripWhitespace && _lastNonAttr.getCchAfter() == 0)
{
while ( start < end && isWhiteSpace( buf[ start ] ) )
start++;
}
int cchText = end - start;
if (cchText > 0)
{
_lastSplay = _lastNonAttr;
_lastPos = _lastNonAttr.getEndPos();
_root._text.insert(
getCp( _lastNonAttr ) + _lastNonAttr.getCch(),
buf, start, cchText );
_lastNonAttr.adjustCchAfter( cchText );
adjustCch( _lastNonAttr, cchText );
}
}
void text ( String text )
{
assert !_finished;
int start = 0;
int end = text.length();
if (_stripWhitespace && _lastNonAttr.getCchAfter() == 0)
{
while ( start < end && isWhiteSpace( text.charAt( start ) ) )
start++;
}
int cchText = end - start;
if (cchText > 0)
{
_lastSplay = _lastNonAttr;
_lastPos = _lastNonAttr.getEndPos();
_root._text.insert(
getCp( _lastNonAttr ) + _lastNonAttr.getCch(),
text, start, cchText );
_lastNonAttr.adjustCchAfter( cchText );
adjustCch( _lastNonAttr, cchText );
}
}
// Annotates the last thing inserted
void annotate ( XmlBookmark xmlBookmark )
{
new Annotation( _root, xmlBookmark ).
set( _lastSplay, _lastPos );
}
void lineNumberAnnotation ( int line, int column, int offset )
{
annotate( new XmlLineNumber( line, column, offset ) );
}
void lineNumberAnnotation ( XMLEvent xe )
{
Location loc = xe.getLocation();
if (loc != null)
{
lineNumberAnnotation(
loc.getLineNumber(), loc.getColumnNumber(), -1 );
}
}
void javelinAnnotation ( XmlCursor.XmlBookmark ja )
{
if (ja != null)
annotate( ja );
}
private Root _root;
private Splay _lastNonAttr;
private Container _frontier;
private Splay _lastSplay;
private int _lastPos;
private boolean _finished;
private boolean _discardDocElem;
private QName _replaceDocElem;
private boolean _stripWhitespace;
private boolean _stripComments;
private boolean _stripProcinsts;
private boolean _docElemDiscarded;
private Map _substituteNamespaces;
private Map _additionalNamespaces;
private QNameCache _qnameCache;
private XmlOptions _options;
}
private void loadNodeChildren ( Node n, LoadContext context )
{
for ( Node c = n.getFirstChild() ; c != null ; c = c.getNextSibling() )
loadNode( c, context );
}
private void loadNode ( Node n, LoadContext context )
{
switch ( n.getNodeType() )
{
case Node.DOCUMENT_NODE :
case Node.DOCUMENT_FRAGMENT_NODE :
case Node.ENTITY_REFERENCE_NODE :
{
loadNodeChildren( n, context );
break;
}
case Node.ELEMENT_NODE :
{
String localName = n.getLocalName();
if (localName == null)
localName = n.getNodeName();
context.begin( localName, n.getNamespaceURI() );
NamedNodeMap attrs = n.getAttributes();
for ( int i = 0 ; i < attrs.getLength() ; i++ )
{
Node a = attrs.item( i );
String uri = a.getNamespaceURI();
String local = a.getLocalName();
String value = a.getNodeValue();
if (local == null)
local = a.getNodeName();
if (uri != null && uri.equals( _xmlnsUri ))
{
if (local.equals( "xmlns" ))
context.xmlns( "", value );
else
context.xmlns( local, value );
}
else
{
context.attr( local, uri, value );
}
}
loadNodeChildren( n, context );
context.end();
break;
}
case Node.TEXT_NODE :
case Node.CDATA_SECTION_NODE :
{
context.text( n.getNodeValue() );
break;
}
case Node.COMMENT_NODE :
{
context.comment( n.getNodeValue() );
break;
}
case Node.PROCESSING_INSTRUCTION_NODE :
{
context.procinst( n.getNodeName(), n.getNodeValue() );
break;
}
case Node.DOCUMENT_TYPE_NODE :
case Node.ENTITY_NODE :
case Node.NOTATION_NODE :
case Node.ATTRIBUTE_NODE :
{
throw new RuntimeException( "Unexpected node" );
}
}
}
public XmlObject loadXml ( Node node, SchemaType type, XmlOptions options )
throws XmlException
{
LoadContext context = new LoadContext( this, options );
loadNode( node, context );
associateSourceName( options );
return autoTypedDocument( type, options );
}
public XmlObject loadXml (
XMLInputStream xis, SchemaType type, XmlOptions options )
throws XMLStreamException, XmlException
{
loadXmlInputStream( xis, options );
return autoTypedDocument( type, options );
}
public void loadXmlInputStream ( XMLInputStream xis, XmlOptions options )
throws XMLStreamException, XmlException
{
options = XmlOptions.maskNull( options );
XMLEvent x = xis.peek();
if (x != null && x.getType() == XMLEvent.START_ELEMENT)
{
Map nsMap = ((StartElement) x).getNamespaceMap();
if (nsMap != null && nsMap.size() > 0)
{
Map namespaces = new HashMap();
namespaces.putAll( nsMap );
options = new XmlOptions( options );
options.put( XmlOptions.LOAD_ADDITIONAL_NAMESPACES, namespaces );
}
}
LoadContext context = new LoadContext( this, options );
boolean lineNums = options.hasOption( XmlOptions.LOAD_LINE_NUMBERS );
events:
for ( XMLEvent xe = xis.next() ; xe != null ; xe = xis.next() )
{
switch ( xe.getType() )
{
case XMLEvent.START_DOCUMENT :
// BUGBUG (ericvas) 12258 - FIXED below
StartDocument doc = (StartDocument) xe;
// context.doctype(
// doc.getname().getLocalName(),
// "", doc.getPublicId()
_props.setDoctypeSystemId( doc.getSystemId() );
// _publicID = doc.getPublicId();
_props.setEncoding( doc.getCharacterEncodingScheme() );
_props.setVersion( doc.getVersion() );
_standAlone = doc.isStandalone();
if (lineNums)
context.lineNumberAnnotation( xe );
break;
case XMLEvent.END_DOCUMENT :
if (lineNums)
context.lineNumberAnnotation( xe );
break events;
case XMLEvent.NULL_ELEMENT :
if (!xis.hasNext())
break events;
break;
case XMLEvent.START_ELEMENT :
context.begin( XMLNameHelper.getQName( xe.getName() ) );
if (lineNums)
context.lineNumberAnnotation( xe );
for ( AttributeIterator ai = ((StartElement) xe).getAttributes()
; ai.hasNext() ; )
{
Attribute attr = ai.next();
context.attr(
XMLNameHelper.getQName( attr.getName() ),
attr.getValue() );
}
for ( AttributeIterator ai = ((StartElement) xe).getNamespaces()
; ai.hasNext() ; )
{
Attribute attr = ai.next();
XMLName name = attr.getName();
String local = name.getLocalName();
if (name.getPrefix() == null && local.equals( "xmlns" ))
local = "";
context.xmlns( local, attr.getValue() );
}
break;
case XMLEvent.END_ELEMENT :
context.end();
if (lineNums)
context.lineNumberAnnotation( xe );
break;
case XMLEvent.SPACE :
if (((Space) xe).ignorable())
break;
// Fall through
case XMLEvent.CHARACTER_DATA :
CharacterData cd = (CharacterData) xe;
if (cd.hasContent())
{
context.text( cd.getContent() );
if (lineNums)
context.lineNumberAnnotation( xe );
}
break;
case XMLEvent.COMMENT :
weblogic.xml.stream.Comment comment =
(weblogic.xml.stream.Comment) xe;
if (comment.hasContent())
{
context.comment( comment.getContent() );
if (lineNums)
context.lineNumberAnnotation( xe );
}
break;
case XMLEvent.PROCESSING_INSTRUCTION :
ProcessingInstruction procInstr = (ProcessingInstruction) xe;
context.procinst( procInstr.getTarget(), procInstr.getData() );
if (lineNums)
context.lineNumberAnnotation( xe );
break;
// These are ignored
case XMLEvent.ENTITY_REFERENCE :
case XMLEvent.START_PREFIX_MAPPING :
case XMLEvent.END_PREFIX_MAPPING :
case XMLEvent.CHANGE_PREFIX_MAPPING :
case XMLEvent.XML_EVENT :
break;
default :
throw new RuntimeException(
"Unhandled xml event type: " + xe.getTypeAsString() );
}
}
context.finish();
associateSourceName( options );
assert validate();
assert isLeftOnly();
}
public static void dump ( XmlObject x )
{
dump( x, System.out );
}
public static void dump ( XmlObject x, PrintStream ps )
{
XmlCursor xc = x.newCursor();
Root r = ((Cursor) xc).getRoot();
r.dump( ps, null, ((Cursor) xc).getSplay(), false );
xc.dispose();
}
public static void dump ( XmlCursor xc )
{
dump( xc, System.out );
}
public static void dump ( XmlCursor xc, PrintStream ps )
{
Root r = ((Cursor) xc).getRoot();
r.dump( ps, null, ((Cursor) xc).getSplay(), false );
}
//
//
//
private void dumpText ( PrintStream ps, int cp, int cch, Splay s, int p )
{
if (cp >= 0 && cp + cch <= _text.length())
dumpString( ps, _text.fetch( cp, cch ), s, p );
else
ps.print( "[string: cp=" + cp + ", cch=" + cch + " ]" );
}
private void dumpText ( PrintStream ps, int cp, int cch )
{
if (cp >= 0 && cp + cch <= _text.length())
dumpString( ps, _text.fetch( cp, cch ), null, 0 );
else
ps.print( "[string: cp=" + cp + ", cch=" + cch + " ]" );
}
private void dumpString ( PrintStream ps, String s )
{
dumpString( ps, s, null, 0 );
}
private void dumpGoobersInline ( PrintStream ps, Splay s, int p )
{
for ( Goober g = s.firstGoober() ; g != null ;
g = s.nextGoober( g ) )
{
if (g.getKind() == CURSOR && g.getPos() == p)
{
CursorGoober cg = (CursorGoober) g;
ps.print( "[" + ((CursorGoober) g).getDebugId() + "]" );
}
}
}
private void dumpString ( PrintStream ps, String str, Splay s, int p )
{
for ( int i = 0 ; i < str.length() ; i++ )
{
if (s != null)
dumpGoobersInline( ps, s, i + p );
if (i == 36)
{
ps.print( "..." );
break;
}
char ch = str.charAt( i );
if (ch == '\n')
ps.print( "\\n" );
else if (ch == '\r')
ps.print( "\\r" );
else if (ch == '\t')
ps.print( "\\t" );
else if (ch == '\"')
ps.print( "\\\"" );
else
ps.print( ch );
}
}
private void dumpGoobers ( PrintStream ps, Goober g )
{
if (g == null)
return;
if (g.getKind() == AGGREGATE)
{
ps.print( " {" );
dumpGoobers( ps, g._goobers );
ps.print( "}" );
}
else
ps.print( " - " + g.getKindName() + " pos: " + g.getPos() );
if (g.getKind() == CURSOR)
ps.print( " id: " + ((CursorGoober) g).getDebugId() );
if (g._next != g._parent._goobers)
dumpGoobers( ps, g._next );
}
private void dumpSplayTree( Splay s, PrintStream ps )
{
if (s == null)
return;
if (s._rightSplay != null)
dumpSplayTree( s._rightSplay, ps );
for ( Splay t = s._parentSplay ; t != null ; t = t._parentSplay )
ps.print( " " );
ps.print( "[" + s.getDebugId() );
ps.print( " c:" + s.getCchLeft() + "(" + s.getCch() + ")");
ps.print( " b:" + s.getCdocBeginLeft() + "(" + s.getCdocBegin() + ")");
if (s._parentSplay != null)
{
ps.print( " p:" + s._parentSplay.getDebugId() );
ps.print( s._parentSplay._leftSplay == s ? "L" : "R" );
}
ps.println( "]" );
if (s._leftSplay != null)
dumpSplayTree( s._leftSplay, ps );
}
public static void dump ( XmlCursor c, boolean verbose )
{
((Cursor) c).dump( verbose );
}
public void dump ( )
{
dump( System.out, null, this, false );
}
public void dump ( boolean verbose )
{
dump( System.out, null, this, verbose );
}
public void dump ( PrintStream ps )
{
dump( ps, null, this, false );
}
public void dump ( PrintStream ps, String msg, Object src, boolean verbose )
{
// Under IntelliJ, if you call a function from the expression
// evaluator and it produces too much output, IntelliJ will not
// show you the output of the function. So, I dump to a file
// here as well and the given print stream!
File f = new File( "c:\\" );
if (f.exists())
{
f = new File( f, "xbean.dmp" );
OutputStream os = null;
PrintStream ps2 = null;
try
{
os = new FileOutputStream( f );
ps2 = new PrintStream( os );
doDump( ps2, msg, src, verbose );
}
catch ( Throwable t )
{
if (ps2 != null)
{
ps2.println( "Exception during dump." );
t.printStackTrace( ps2 );
}
}
if (os != null)
{
try { os.close(); } catch ( Exception e ) { }
}
}
try
{
doDump( ps, msg, src, verbose );
}
catch ( Throwable t )
{
System.out.println( "Exception during dump." );
t.printStackTrace( System.out );
}
}
static class DumpNsManager implements NamespaceManager
{
DumpNsManager ( PrintStream ps )
{
this.ps = ps;
}
public String find_prefix_for_nsuri ( String uri, String suggestion )
{
String prefix = "debug_prefix_" + i++;
ps.print( " [find_prefix_for_nsuri: " );
ps.print( "\"" + uri + "\" (" + suggestion + ") -> " + prefix );
ps.print( "]" );
return prefix;
}
public String getNamespaceForPrefix ( String prefix )
{
if (prefix != null && prefix.equals( "xml" ))
return _xml1998Uri;
String uri = "debug_ns_" + i++;
ps.print( " [lookup_nsuri_for_prefix: " );
ps.print( prefix + " -> \"" + uri + "\"" );
ps.print( "]" );
return uri;
}
PrintStream ps;
private int i = 1;
}
public void doDump (
PrintStream ps, String msg, Object src, boolean verbose )
{
if (!_assertEnabled)
{
ps.println( "No dump produced (assert needs to be enabled)" );
return;
}
NamespaceManager nsm = new DumpNsManager( ps );
if (msg != null)
ps.println( msg );
else
ps.println( "Dump:" );
if (src != null)
{
if (src instanceof Cursor)
{
ps.println(
" from cursor " + ((CursorGoober)((Cursor) src)._data._goober).getDebugId() );
}
else if (src instanceof Splay)
ps.println( " from splay " + ((Splay) src).getDebugId() );
else
ps.println( " from src " + src );
}
int depth = 0;
for ( Splay s = _doc ; s != null ; s = s.nextSplay() )
{
int kind = s.getKind();
String ids = "" + s.getDebugId();
ids = " ".substring( 0, 6 - ids.length() ) + ids;
ps.print( ids + ": " );
if (kind == END)
depth--;
if (!s.isRoot())
{
for ( int i = 0 ; i < depth ; i++ )
ps.print( " " );
}
dumpGoobersInline( ps, s, 0 );
switch ( kind )
{
case DOC :
ps.print( "DOC" );
break;
case BEGIN :
{
Begin b = (Begin) s;
if (!b.isLeaf())
depth++;
ps.print( "<" );
ps.print( s.getName().toString() );
ps.print( ">" );
if (b.isLeaf())
{
if (b.getCchValue() > 0)
{
ps.print( "\"" );
dumpText( ps, s.getCpSlow(), b.getCchValue(), s, 1 );
ps.print( "\"" );
}
dumpGoobersInline( ps, s, s.getPosLeafEnd() );
ps.print( "</" );
ps.print( s.getName().getLocalPart() );
ps.print( "/>" );
}
break;
}
case ATTR :
{
if (s.isXmlns())
{
ps.print( "#xmlns:" );
ps.print( s.getName().getLocalPart() );
ps.print( "=\"" );
ps.print( s.getName().getNamespaceURI() );
ps.print( "\"" );
}
else
{
ps.print( "@" );
ps.print( s.getName() );
ps.print( "=\"" );
dumpText( ps, s.getCpSlow(), s.getCchValue() );
ps.print( "\"" );
}
break;
}
case END :
{
End es = (End) s;
Begin b = es._begin;
ps.print( "</" );
ps.print( b.getName().getLocalPart() );
ps.print( "/>" );
break;
}
case COMMENT :
{
if (s.isFragment())
{
ps.print( "FRAG" );
}
else
{
ps.print( "<!--" );
dumpText( ps, s.getCpSlow(), s.getCchValue() );
ps.print( "-->" );
}
break;
}
case PROCINST :
{
ps.print( "<?" );
ps.print( s.getLocal() );
ps.print( " " );
dumpText( ps, s.getCpSlow(), s.getCchValue() );
ps.print( "?>" );
break;
}
case ROOT :
{
ps.print( "ROOT" );
break;
}
default:
throw new RuntimeException( "Unknown splay kind" );
}
if (s.getCchAfter() > 0)
{
ps.print( "\"" );
dumpText(
ps, s.getCpSlow() + s.getCchValue(), s.getCchAfter(),
s, s.getPosAfter() );
ps.print( "\"" );
}
dumpGoobersInline( ps, s, s.getEndPos() );
if (s.isInvalid())
{
String value = s.peekType().build_text( nsm );
ps.print( " [invalid:" );
ps.print( "\"" );
dumpString( ps, value );
ps.print( "\"" );
ps.print( "]" );
}
dumpGoobers( ps, s._goobers );
if (verbose)
{
switch ( kind )
{
case BEGIN :
{
Begin b = (Begin) s;
if (b.getFinish() != null)
{
ps.print( " [end: " );
ps.print( b.getFinish().getDebugId() );
ps.print( "]" );
}
if (b.getContainer() != null)
{
ps.print(
" [container: " +
b.getContainer().getDebugId() + "]" );
}
break;
}
case END :
{
End es = (End) s;
Begin b = es._begin;
ps.print( " [begin: " + b.getDebugId() + "]" );
break;
}
}
}
ps.println();
}
ps.println();
if (getCchLeft() > _text.length())
{
ps.println(
"Text buffer has too few characters (" +
(getCchLeft() - _text.length()) + ")" );
}
else if (getCchLeft() < _text.length())
{
ps.println(
"Text buffer has too many characters (" +
(_text.length() - getCchLeft()) + "): " );
dumpString(
ps,
_text.fetch( getCchLeft(), _text.length() - getCchLeft() ) );
}
if (verbose)
{
ps.println( "Splay tree:" );
ps.println( " isLeftOnly: " + _leftOnly );
ps.println( " version: " + getVersion() );
ps.println( " first: " + _doc.getDebugId() );
ps.println();
dumpSplayTree( this, ps );
ps.println();
ps.println();
}
ps.println();
}
/**
* Insert a splay (or splays) into the tree. This is a low level
* operation, and operates only on the splay aspect of the tree.
* Any invalidation maintenance must be handled by callers.
*/
void insertSplay ( Splay s, Splay a )
{
assert s != null;
assert !s.isRoot();
assert a != null;
assert Root.dv > 0 || validateSplayTree();
assert !a.isRoot();
assert Root.dv > 0 || a.getRootSlow() == this;
assert s._parentSplay == null;
assert s._rightSplay == null;
assert s._leftSplay != null || s.getCchLeft() == 0;
assert s._leftSplay != null || s.getCdocBeginLeft() == 0;
int cch = s.getCch();
int cbegin = s.getCdocBegin();
if (s._leftSplay != null)
{
cch += s.getCchLeft();
cbegin += s.getCdocBeginLeft();
_leftOnly = false;
}
if (_leftOnly && a == _leftSplay)
{
s._leftSplay = _leftSplay;
s._parentSplay = this;
assert s.getCchLeft() == 0;
s.adjustCchLeft(
_leftSplay.getCchLeft() + _leftSplay.getCch() );
assert s.getCdocBeginLeft() == 0;
s.adjustCdocBeginLeft(
_leftSplay.getCdocBeginLeft() + _leftSplay.getCdocBegin() );
_leftSplay._parentSplay = s;
_leftSplay = s;
adjustCchLeft( cch );
adjustCdocBeginLeft( cbegin );
}
else if (_leftOnly && cch == 0 && cbegin == 0)
{
//
// If the splay to insert has no cch or cbegin, then when
// the tree is left only children, I need not splay.
//
s._parentSplay = a._parentSplay;
s._leftSplay = a;
a._parentSplay = s;
s._parentSplay._leftSplay = s;
s.adjustCchLeft( a.getCchLeft() + a.getCch() );
s.adjustCdocBeginLeft(
a.getCdocBeginLeft() + a.getCdocBegin() );
}
else
{
Splay p;
if (a._rightSplay == null)
{
(p = a)._rightSplay = s;
_leftOnly = false;
}
else
{
for ( p = a._rightSplay ; p._leftSplay != null ; )
p = p._leftSplay;
p._leftSplay = s;
}
s._parentSplay = p;
for ( p = s ; ; )
{
Splay t = p._parentSplay;
if (t == null)
break;
if (t._leftSplay == p)
{
t.adjustCchLeft( cch );
t.adjustCdocBeginLeft( cbegin );
}
p = t;
}
s.splay( this, this );
}
assert validateSplayTree();
}
/**
* Special insert to insert a single splay into a leftonly tree without
* causing the tree to go non left only. Because this does not splay,
* doing this too many times can be very inefficient.
*/
void insertSingleSplaySansSplayInLeftOnlyTree ( Splay s, Splay a )
{
assert _leftOnly;
assert s._rightSplay == null;
assert s._leftSplay == null;
s._leftSplay = a;
s._parentSplay = a._parentSplay;
a._parentSplay._leftSplay = s;
a._parentSplay = s;
s.adjustCchLeft( a.getCchLeft() + a.getCch() );
s.adjustCdocBeginLeft( a.getCdocBeginLeft() + a.getCdocBegin() );
int cch = s.getCch();
int cbegin = s.getCdocBegin();
for ( Splay p = s._parentSplay ; p != null ; p = p._parentSplay )
{
p.adjustCchLeft( cch );
p.adjustCdocBeginLeft( cbegin );
}
}
/**
* Remove [ first, last ) splays from total sequence:
*
* A - first - B - x - last - C
*
* where first, last and x are individual splays and A, B and C are
* multiple, intervening splays. Return the result with x at the top
* and first his left child. This allows x to have the splay
* characteristics for the whole removed tree.
*/
Splay removeSplays ( Splay first, Splay last )
{
assert validateSplayTree();
assert first != last;;
assert !first.isRoot();
assert !first.isDoc();
assert Root.dv > 0 || first.getRootSlow() == this;
assert Root.dv > 0 || last.getRootSlow() == this;
assert Root.dv > 0 || first.compareSlow( last ) == -1;
assert !last.isRoot() || last == this;
Splay x = last.prevSplay();
if (x == first)
return x.removeSplay( this );
// Make the dog leg!
if (last != this)
last.splay( this, this );
x.splay( this, last );
first.splay( this, x );
assert this == last || this._leftSplay == last;
assert last._leftSplay == x;
assert x._leftSplay == first;
assert x._rightSplay == null;
assert first._leftSplay != null;
int firstCchLeft = first.getCchLeft();
int firstCbeginLeft = first.getCdocBeginLeft();
int deltaCchLeft = firstCchLeft - last.getCchLeft();
int deltaCbeginLeft = firstCbeginLeft - last.getCdocBeginLeft();
last.adjustCchLeft( deltaCchLeft );
last.adjustCdocBeginLeft( deltaCbeginLeft );
if (last != this)
{
adjustCchLeft( deltaCchLeft );
adjustCdocBeginLeft( deltaCbeginLeft );
}
x.adjustCchLeft( - firstCchLeft );
x.adjustCdocBeginLeft( - firstCbeginLeft );
first.adjustCchLeft( - firstCchLeft );
first.adjustCdocBeginLeft( - firstCbeginLeft );
assert first.getCchLeft() == 0;
assert first.getCdocBeginLeft() == 0;
assert x.getCchLeft() + deltaCchLeft + x.getCch() == 0;
assert x.getCdocBeginLeft() + deltaCbeginLeft + x.getCdocBegin() == 0;
first._leftSplay._parentSplay = last;
last._leftSplay = first._leftSplay;
x._parentSplay = null;
first._leftSplay = null;
first._parentSplay = null;
assert validateSplayTree();
return x;
}
public static synchronized boolean disableStoreValidation ( )
{ dv++; return true; }
public static synchronized boolean enableStoreValidation ( )
{ dv--; return true; }
public static int dv;
{
if (!"true".equals( System.getProperty( "treeasserts" )))
disableStoreValidation();
}
public boolean validate ( )
{
if (dv != 0)
return true;
try
{
return doValidate();
}
catch ( RuntimeException rte )
{
System.out.println( "Document invalid: " + rte.getMessage() );
rte.printStackTrace();
dump( true );
throw rte;
}
}
//
// Recursive descent validation of the content of the document
//
// Grammer for valid content of a document
//
// <doc> ::= DOC <attributes> <content> ROOT
// <attributes> ::= ( ATTR )*
// <content> ::= ( ( COMMENT | PROCINST | <element>) )*
// <element> ::= ( LEAF <attributes> ) |
// ( BEGIN <attributes> <content> END )
//
private Splay validateAttributes ( Splay s )
{
while ( s.getKind() == ATTR )
s = s.nextSplay();
return s;
}
private Splay validateContent ( Splay s )
{
for ( ; ; )
{
int k = s.getKind();
if (k == COMMENT || k == PROCINST)
s = s.nextSplay();
else
{
Splay q = s;
s = validateElement( s );
if (q == s)
break;
}
}
return s;
}
private Splay validateElement ( Splay s )
{
if (s.getKind() == BEGIN)
{
Splay b = s;
s = validateAttributes( s.nextSplay() );
if (!b.isLeaf())
{
s = validateContent( s );
assert s.isEnd(): "Missing END, splay: " + s.getDebugId();
s = s.nextSplay();
}
}
return s;
}
private boolean validateDoc ( )
{
Splay s = _doc.nextSplay();
s = validateAttributes( s );
s = validateContent( s );
assert s.isRoot(): "Expected root";
return true;
}
private static class ValidateContext
{
int _numSplayTypes;
int _cInvalidatableTypes;
int _cElemOrderSensitiveTypes;
}
private void validateGoober ( Goober g, Splay s, ValidateContext context )
{
if (g instanceof Type)
{
assert g.getKind() == TYPE;
assert s.isTypeable();
context._numSplayTypes++;
Type type = (Type) g;
if (type.uses_invalidate_value())
context._cInvalidatableTypes++;
if (type.is_child_element_order_sensitive())
context._cElemOrderSensitiveTypes++;
}
else
{
assert g.getKind() != TYPE;
}
assert g.getSplay() == s;
assert g.getRoot() == this;
assert g.getPos() >= 0;
assert g.getPos() <= s.getMaxPos();
}
private boolean doValidate ( )
{
assert validateDoc();
assert validateSplayTree();
assert getCchLeft() == _text.length();
validateChangeListenerState();
// TODO: Validate that is the root type is null, there are no types in
// tree at all
// TODO: Check the invarient that if there is a Type anywhere
// in the document, that there is an existing chain of types
// all the way to the root and is_ok_element_user or is_ok_attribute_user,
// depending on the case, returns ok.
ValidateContext context = new ValidateContext();
Container recentContainer = null;
for ( Splay s = _doc ; s != null ; s = s.nextSplay() )
{
if (s.isRoot())
{
assert s.getCchAfter() == 0;
}
else if (s.isBegin())
{
Begin b = (Begin) s;
assert b.getName() != null;
assert
b.getFinish() == null ||
b.getFinish().getContainer() == b;
if (b.isLeaf())
{
assert b.getFinish() == null;
}
else
{
assert b.getFinish() != null;
assert b.getFinish().getContainer() == b;
assert b.getCchValue() == 0;
}
}
else if (s.isAttr())
{
assert s.getName() != null;
assert s.getCchAfter() == 0;
}
if (s.isProcinst())
{
assert s.getName().getNamespaceURI() != null;
assert s.getName().getNamespaceURI().length() == 0;
}
if (s.isContainer())
{
assert s.getContainer() == recentContainer;
if (!s.isLeaf())
recentContainer = (Container) s;
}
else if (s.isFinish())
{
assert s.getContainer() == recentContainer;
recentContainer = recentContainer.getContainer();
}
context._numSplayTypes = 0;
for ( Goober g = s.firstGoober() ; g != null ;
g = s.nextGoober( g ) )
{
validateGoober( g, s, context );
}
if (isInvalid())
{
assert s.isTypeable();
assert s.peekType() != null;
assert context._numSplayTypes == 1;
if (s.isDoc())
{
assert s.getCchAfter() == 0;
Splay n = s.nextNonAttrSplay();
assert n.isRoot();
}
else if (s.isBegin())
{
assert s.isLeaf();
assert s.getCchValue() == 0;
}
else if (s.isAttr())
{
assert s.getCchValue() == 0;
}
}
else
{
assert context._numSplayTypes <= 1;
}
}
assert context._cInvalidatableTypes == _cInvalidatableTypes;
assert context._cElemOrderSensitiveTypes ==_cElemOrderSensitiveTypes;
// TODO: Validate indices
return true;
}
boolean validateSplayTree ( )
{
if (dv != 0)
return true;
try
{
return doValidateSplayTree();
}
catch ( RuntimeException rte )
{
System.out.println( "Splay tree invalid: " + rte );
dump( true );
throw rte;
}
}
private static class ValidateStats extends HashMap
{
int getCch ( Splay s )
{
return getStats( s )._cch;
}
void adjustCch ( Splay s, int cchDelta )
{
Stats stats = getStats( s );
stats._cch += cchDelta;
}
int getCbegin ( Splay s )
{
return getStats( s )._cbegin;
}
void adjustCbegin ( Splay s, int cbeginDelta )
{
Stats stats = getStats( s );
stats._cbegin += cbeginDelta;
}
private Stats getStats ( Splay s )
{
Stats stats = (Stats) get( s );
if (stats == null)
put( s, stats = new Stats() );
return stats;
}
private static class Stats
{
public int _cch;
public int _cbegin;
}
}
boolean doValidateSplayTree ( )
{
assertAssertEnabled();
ValidateStats stats = new ValidateStats();
assert _parentSplay == null;
assert _rightSplay == null;
assert _doc._leftSplay == null;
Splay s = this;
if (s._leftSplay != null)
{
s = s._leftSplay;
while ( s != null && s._leftSplay != null )
s = s._leftSplay;
}
assert s == _doc;
loop:
for ( ; ; )
{
if (s._leftSplay == null && s._rightSplay == null)
{
stats.adjustCch( s, s.getCch() );
stats.adjustCbegin( s, s.getCdocBegin() );
}
if (s._rightSplay != null)
{
for ( s = s._rightSplay ; s._leftSplay != null ; )
s = s._leftSplay;
}
else
{
for ( ; ; )
{
Splay p = s._parentSplay;
if (p == null)
break loop;
if (p._rightSplay == null || p._rightSplay == s)
{
s = p;
stats.adjustCch( s, s.getCch() );
stats.adjustCbegin( s, s.getCdocBegin() );
if (s._leftSplay != null)
{
stats.adjustCch( s, stats.getCch( s._leftSplay ) );
stats.adjustCbegin(
s, stats.getCbegin( s._leftSplay ) );
}
if (s._rightSplay != null)
{
stats.adjustCch( s, stats.getCch( s._rightSplay ) );
stats.adjustCbegin(
s, stats.getCbegin( s._rightSplay ) );
}
}
else
{
assert p._leftSplay == s;
assert p._rightSplay != null;
s = p._rightSplay;
while ( s._leftSplay != null )
s = s._leftSplay;
break;
}
}
}
}
for ( s = _doc ; s != null ; s = s.nextSplay() )
{
assert !_leftOnly || s._rightSplay == null: "" + s.getDebugId();
assert s._leftSplay == null || s._leftSplay ._parentSplay == s;
assert s._rightSplay == null || s._rightSplay._parentSplay == s;
if (s._leftSplay == null)
{
assert s.getCchLeft() == 0;
assert s.getCdocBeginLeft() == 0;
}
else
{
assert
s.getCchLeft() == stats.getCch( s._leftSplay ):
"" + s.getDebugId();
assert s.getCdocBeginLeft() == stats.getCbegin( s._leftSplay );
}
}
return true;
}
//
//
//
interface ChangeListener
{
void changeNotification ( );
}
private static class ChangeClient
{
ChangeListener _listener;
ChangeClient _next;
}
long getVersion ( )
{
return __version;
}
void invalidateVersion ( )
{
assert _changeClients == null;
__version++;
assert (_debugChangeVersion = __version) == 0 || true;
}
// Use this *only* if you know what you are doing!
void restoreVersion ( long oldVersion )
{
assert __version >= oldVersion;
__version = oldVersion;
assert (_debugChangeVersion = __version) == 0 || true;
}
boolean validateChangeStarted ( )
{
assert _changeClients == null;
return _changeClients == null;
}
boolean validateChangeListenerState ( )
{
assert _debugChangeVersion == __version;
return true;
}
void registerForChange ( ChangeListener listener )
{
assert validateChangeListenerState();
// See if this listener is the first one on the list. Easy but not
// totally complete optimization
if (_changeClients != null && _changeClients._listener == listener)
return;
ChangeClient client = new ChangeClient();
client._next = _changeClients;
client._listener = listener;
_changeClients = client;
}
void startChange ( )
{
assert validateChangeListenerState();
long currentVersion = 0;
assert (currentVersion = __version) == 0 || true;
while ( _changeClients != null )
{
_changeClients._listener.changeNotification();
_changeClients = _changeClients._next;
}
assert currentVersion == __version;
}
//
// Document properties
//
static class DocProps
extends XmlDocumentProperties
{
private HashMap _map = new HashMap();
public Object put ( Object key, Object value )
{
return _map.put( key, value );
}
public Object get ( Object key )
{
return _map.get( key );
}
public Object remove ( Object key )
{
return _map.remove( key );
}
}
class nthCache
{
private boolean namesSame ( QName pattern, QName name )
{
return pattern == null || pattern.equals( name );
}
private boolean setsSame ( QNameSet patternSet, QNameSet set)
{
// value equality is probably too expensive. Since the use case
// involves QNameSets that are generated by the compiler, we
// can use identity comparison.
return patternSet != null && patternSet == set;
}
private boolean nameHit(QName namePattern, QNameSet setPattern, QName name)
{
if (setPattern == null)
return namesSame(namePattern, name);
else
return setPattern.contains(name);
}
private boolean cacheSame (QName namePattern, QNameSet setPattern)
{
return setPattern == null ? namesSame(namePattern, _name) :
setsSame(setPattern, _set);
}
int distance ( Splay parent, QName name, QNameSet set, int n )
{
assert n >= 0;
if (_version != Root.this.getVersion())
return Integer.MAX_VALUE - 1;
if (parent != _parent || !cacheSame(name, set))
return Integer.MAX_VALUE;
return n > _n ? n - _n : _n - n;
}
Begin fetch ( Splay parent, QName name, QNameSet set, int n )
{
assert n >= 0;
if (_version != Root.this.getVersion() || _parent != parent ||
! cacheSame(name, set) || n == 0)
{
_version = Root.this.getVersion();
_parent = parent;
_name = name;
_child = null;
_n = -1;
if (!parent.isLeaf())
{
loop:
for ( Splay s = parent.nextSplay() ; ; s = s.nextSplay() )
{
switch ( s.getKind() )
{
case END :
case ROOT : break loop;
case BEGIN :
if (nameHit( name, set, s.getName() ))
{
_child = s;
_n = 0;
break loop;
}
s = s.getFinishSplay();
break;
}
}
}
}
if (_n < 0)
return null;
if (n > _n)
{
while ( n > _n )
{
for ( Splay s = _child.getFinishSplay().nextSplay() ; ;
s = s.nextSplay() )
{
if (s.isFinish())
return null;
if (s.isBegin())
{
if (nameHit( name, set, s.getName() ))
{
_child = s;
_n++;
break;
}
s = s.getFinishSplay();
}
}
}
}
else if (n < _n)
{
while ( n < _n )
{
Splay s = _child;
for ( ; ; )
{
s = s.prevSplay();
if (s.isLeaf() || s.isEnd())
{
if (s.isEnd())
s = s.getContainer();
if (nameHit( name, set, s.getName() ))
{
_child = s;
_n--;
break;
}
}
else if (s.isContainer())
return null;
}
}
}
return (Begin) _child;
}
private long _version;
private Splay _parent;
private QName _name;
private QNameSet _set;
private Splay _child;
private int _n;
}
//
// Da fields. Da Bears. Ditka is God.
//
boolean _leftOnly;
Doc _doc;
Text _text;
boolean _validateOnSet;
//
// Document version. These numbers get incremented when the document
// changes in a variety of ways.
//
private long __version = 1;
private long _debugChangeVersion = 1; // Debug only
private ChangeClient _changeClients;
DocProps _props;
//
// XmlInputStream
//
boolean _standAlone;
//
//
//
final SchemaTypeLoader _schemaTypeSystem;
int _cInvalidatableTypes;
int _cElemOrderSensitiveTypes;
//
//
//
nthCache _nthCache_A = new nthCache();
nthCache _nthCache_B = new nthCache();
TypeStoreFactory _factory;
}