IncrementalSAXSource_Xercespublic class IncrementalSAXSource_Xerces extends Object implements IncrementalSAXSourceIncrementalSAXSource_Xerces takes advantage of the fact that Xerces1
incremental mode is already a coroutine of sorts, and just wraps our
IncrementalSAXSource API around it.
Usage example: See main().
Status: Passes simple main() unit-test. NEEDS JAVADOC. |
Fields Summary |
---|
Method | fParseSomeSetup | Method | fParseSome | Object | fPullParserConfig | Method | fConfigSetInput | Method | fConfigParse | Method | fSetInputSource | Constructor | fConfigInputSourceCtor | Method | fConfigSetByteStream | Method | fConfigSetCharStream | Method | fConfigSetEncoding | Method | fReset | SAXParser | fIncrementalParser | private boolean | fParseInProgress | private static final Object[] | noparms | private static final Object[] | parmsfalse |
Constructors Summary |
---|
public IncrementalSAXSource_Xerces()Create a IncrementalSAXSource_Xerces, and create a SAXParser
to go with it. Xerces2 incremental parsing is only supported if
this constructor is used, due to limitations in the Xerces2 API (as of
Beta 3). If you don't like that restriction, tell the Xerces folks that
there should be a simpler way to request incremental SAX parsing.
//
// Constructors
//
try
{
// Xerces-2 incremental parsing support (as of Beta 3)
// ContentHandlers still get set on fIncrementalParser (to get
// conversion from XNI events to SAX events), but
// _control_ for incremental parsing must be exercised via the config.
//
// At this time there's no way to read the existing config, only
// to assert a new one... and only when creating a brand-new parser.
//
// Reflection is used to allow us to continue to compile against
// Xerces1. If/when we can abandon the older versions of the parser,
// this will simplify significantly.
// If we can't get the magic constructor, no need to look further.
Class xniConfigClass=ObjectFactory.findProviderClass(
"com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
ObjectFactory.findClassLoader(), true);
Class[] args1={xniConfigClass};
Constructor ctor=SAXParser.class.getConstructor(args1);
// Build the parser configuration object. StandardParserConfiguration
// happens to implement XMLPullParserConfiguration, which is the API
// we're going to want to use.
Class xniStdConfigClass=ObjectFactory.findProviderClass(
"com.sun.org.apache.xerces.internal.parsers.StandardParserConfiguration",
ObjectFactory.findClassLoader(), true);
fPullParserConfig=xniStdConfigClass.newInstance();
Object[] args2={fPullParserConfig};
fIncrementalParser = (SAXParser)ctor.newInstance(args2);
// Preload all the needed the configuration methods... I want to know they're
// all here before we commit to trying to use them, just in case the
// API changes again.
Class fXniInputSourceClass=ObjectFactory.findProviderClass(
"com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource",
ObjectFactory.findClassLoader(), true);
Class[] args3={fXniInputSourceClass};
fConfigSetInput=xniStdConfigClass.getMethod("setInputSource",args3);
Class[] args4={String.class,String.class,String.class};
fConfigInputSourceCtor=fXniInputSourceClass.getConstructor(args4);
Class[] args5={java.io.InputStream.class};
fConfigSetByteStream=fXniInputSourceClass.getMethod("setByteStream",args5);
Class[] args6={java.io.Reader.class};
fConfigSetCharStream=fXniInputSourceClass.getMethod("setCharacterStream",args6);
Class[] args7={String.class};
fConfigSetEncoding=fXniInputSourceClass.getMethod("setEncoding",args7);
Class[] argsb={Boolean.TYPE};
fConfigParse=xniStdConfigClass.getMethod("parse",argsb);
Class[] noargs=new Class[0];
fReset=fIncrementalParser.getClass().getMethod("reset",noargs);
}
catch(Exception e)
{
// Fallback if this fails (implemented in createIncrementalSAXSource) is
// to attempt Xerces-1 incremental setup. Can't do tail-call in
// constructor, so create new, copy Xerces-1 initialization,
// then throw it away... Ugh.
IncrementalSAXSource_Xerces dummy=new IncrementalSAXSource_Xerces(new SAXParser());
this.fParseSomeSetup=dummy.fParseSomeSetup;
this.fParseSome=dummy.fParseSome;
this.fIncrementalParser=dummy.fIncrementalParser;
}
| public IncrementalSAXSource_Xerces(SAXParser parser)Create a IncrementalSAXSource_Xerces wrapped around
an existing SAXParser. Currently this works only for recent
releases of Xerces-1. Xerces-2 incremental is currently possible
only if we are allowed to create the parser instance, due to
limitations in the API exposed by Xerces-2 Beta 3; see the
no-args constructor for that code.
// Reflection is used to allow us to compile against
// Xerces2. If/when we can abandon the older versions of the parser,
// this constructor will simply have to fail until/unless the
// Xerces2 incremental support is made available on previously
// constructed SAXParser instances.
fIncrementalParser=parser;
Class me=parser.getClass();
Class[] parms={InputSource.class};
fParseSomeSetup=me.getMethod("parseSomeSetup",parms);
parms=new Class[0];
fParseSome=me.getMethod("parseSome",parms);
// Fallback if this fails (implemented in createIncrementalSAXSource) is
// to use IncrementalSAXSource_Filter rather than Xerces-specific code.
|
Methods Summary |
---|
public static void | _main(java.lang.String[] args)Simple unit test. Attempt coroutine parsing of document indicated
by first argument (as a URI), report progress.
System.out.println("Starting...");
CoroutineManager co = new CoroutineManager();
int appCoroutineID = co.co_joinCoroutineSet(-1);
if (appCoroutineID == -1)
{
System.out.println("ERROR: Couldn't allocate coroutine number.\n");
return;
}
IncrementalSAXSource parser=
createIncrementalSAXSource();
// Use a serializer as our sample output
com.sun.org.apache.xml.internal.serialize.XMLSerializer trace;
trace=new com.sun.org.apache.xml.internal.serialize.XMLSerializer(System.out,null);
parser.setContentHandler(trace);
parser.setLexicalHandler(trace);
// Tell coroutine to begin parsing, run while parsing is in progress
for(int arg=0;arg<args.length;++arg)
{
try
{
InputSource source = new InputSource(args[arg]);
Object result=null;
boolean more=true;
parser.startParse(source);
for(result = parser.deliverMoreNodes(more);
result==Boolean.TRUE;
result = parser.deliverMoreNodes(more))
{
System.out.println("\nSome parsing successful, trying more.\n");
// Special test: Terminate parsing early.
if(arg+1<args.length && "!".equals(args[arg+1]))
{
++arg;
more=false;
}
}
if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
{
System.out.println("\nParser ended (EOF or on request).\n");
}
else if (result == null) {
System.out.println("\nUNEXPECTED: Parser says shut down prematurely.\n");
}
else if (result instanceof Exception) {
throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException((Exception)result);
// System.out.println("\nParser threw exception:");
// ((Exception)result).printStackTrace();
}
}
catch(SAXException e)
{
e.printStackTrace();
}
}
| public static com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource | createIncrementalSAXSource()
try
{
return new IncrementalSAXSource_Xerces();
}
catch(NoSuchMethodException e)
{
// Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
// Fall back on filtering solution.
IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
iss.setXMLReader(new SAXParser());
return iss;
}
| public static com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource | createIncrementalSAXSource(com.sun.org.apache.xerces.internal.parsers.SAXParser parser)
try
{
return new IncrementalSAXSource_Xerces(parser);
}
catch(NoSuchMethodException e)
{
// Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
// Fall back on filtering solution.
IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
iss.setXMLReader(parser);
return iss;
}
| public java.lang.Object | deliverMoreNodes(boolean parsemore)deliverMoreNodes() is a simple API which tells the coroutine
parser that we need more nodes. This is intended to be called
from one of our partner routines, and serves to encapsulate the
details of how incremental parsing has been achieved.
if(!parsemore)
{
fParseInProgress=false;
return Boolean.FALSE;
}
Object arg;
try {
boolean keepgoing = parseSome();
arg = keepgoing ? Boolean.TRUE : Boolean.FALSE;
} catch (SAXException ex) {
arg = ex;
} catch (IOException ex) {
arg = ex;
} catch (Exception ex) {
arg = new SAXException(ex);
}
return arg;
| private boolean | parseSome()
// Take next parsing step, return false iff parsing complete:
if(fConfigSetInput!=null)
{
Object ret=(Boolean)(fConfigParse.invoke(fPullParserConfig,parmsfalse));
return ((Boolean)ret).booleanValue();
}
else
{
Object ret=fParseSome.invoke(fIncrementalParser,noparms);
return ((Boolean)ret).booleanValue();
}
| private boolean | parseSomeSetup(org.xml.sax.InputSource source)
if(fConfigSetInput!=null)
{
// Obtain input from SAX inputSource object, construct XNI version of
// that object. Logic adapted from Xerces2.
Object[] parms1={source.getPublicId(),source.getSystemId(),null};
Object xmlsource=fConfigInputSourceCtor.newInstance(parms1);
Object[] parmsa={source.getByteStream()};
fConfigSetByteStream.invoke(xmlsource,parmsa);
parmsa[0]=source.getCharacterStream();
fConfigSetCharStream.invoke(xmlsource,parmsa);
parmsa[0]=source.getEncoding();
fConfigSetEncoding.invoke(xmlsource,parmsa);
// Bugzilla5272 patch suggested by Sandy Gao.
// Has to be reflection to run with Xerces2
// after compilation against Xerces1. or vice
// versa, due to return type mismatches.
Object[] noparms=new Object[0];
fReset.invoke(fIncrementalParser,noparms);
parmsa[0]=xmlsource;
fConfigSetInput.invoke(fPullParserConfig,parmsa);
// %REVIEW% Do first pull. Should we instead just return true?
return parseSome();
}
else
{
Object[] parm={source};
Object ret=fParseSomeSetup.invoke(fIncrementalParser,parm);
return ((Boolean)ret).booleanValue();
}
| public void | setContentHandler(org.xml.sax.ContentHandler handler)
// Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
// %OPT% Cast at asignment?
((XMLReader)fIncrementalParser).setContentHandler(handler);
| public void | setDTDHandler(org.xml.sax.DTDHandler handler)
// Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
// %OPT% Cast at asignment?
((XMLReader)fIncrementalParser).setDTDHandler(handler);
| public void | setLexicalHandler(org.xml.sax.ext.LexicalHandler handler)
// Not supported by all SAX2 parsers but should work in Xerces:
try
{
// Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
// %OPT% Cast at asignment?
((XMLReader)fIncrementalParser).setProperty("http://xml.org/sax/properties/lexical-handler",
handler);
}
catch(org.xml.sax.SAXNotRecognizedException e)
{
// Nothing we can do about it
}
catch(org.xml.sax.SAXNotSupportedException e)
{
// Nothing we can do about it
}
| public void | startParse(org.xml.sax.InputSource source)startParse() is a simple API which tells the IncrementalSAXSource
to begin reading a document.
if (fIncrementalParser==null)
throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_NEEDS_SAXPARSER, null)); //"startParse needs a non-null SAXParser.");
if (fParseInProgress)
throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_WHILE_PARSING, null)); //"startParse may not be called while parsing.");
boolean ok=false;
try
{
ok = parseSomeSetup(source);
}
catch(Exception ex)
{
throw new SAXException(ex);
}
if(!ok)
throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_INIT_PARSER, null)); //"could not initialize parser with");
|
|