protected boolean scanStartElement() throws IOException, XNIException {
if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +" > > > scanStartElement()");
//when skipping is true and no more elements should be added
if(fSkip && !fAdd){
//get the stored element -- if everything goes right this should match the
//token in the buffer
QName name = fElementStack.getNext();
if(DEBUG_SKIP_ALGORITHM){
System.out.println("Trying to skip String = " + name.rawname);
}
//Be conservative -- if skipping fails -- stop.
fSkip = fEntityScanner.skipString(name.rawname); // skipQElement(name);
if(fSkip){
if(DEBUG_SKIP_ALGORITHM){
System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
}
fElementStack.push();
fElementQName = name;
}else{
//if skipping fails reposition the stack or fallback to normal way of processing
fElementStack.reposition();
if(DEBUG_SKIP_ALGORITHM){
System.out.println("Element was NOT skipped, REPOSITIONING stack" );
}
}
}
//we are still at the stage of adding elements
//the elements were not matched or
//fSkip is not set to true
if(!fSkip || fAdd){
//get the next element from the stack
fElementQName = fElementStack.nextElement();
// There are two variables,fNamespaces and fBindNamespaces
//StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
if (fNamespaces) {
fEntityScanner.scanQName(fElementQName);
} else {
String name = fEntityScanner.scanName();
fElementQName.setValues(null, name, name, null);
}
if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
if(DEBUG_SKIP_ALGORITHM){
if(fAdd){
System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
}
}
}
//when the elements are being added , we need to check if we are set for skipping the elements
if(fAdd){
//this sets the value of fAdd variable
fElementStack.matchElement(fElementQName);
}
//xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
fCurrentElement = fElementQName;
String rawname = fElementQName.rawname;
if (fBindNamespaces) {
fNamespaceContext.pushContext();
if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
if (fPerformValidation) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"MSG_GRAMMAR_NOT_FOUND",
new Object[]{ rawname},
XMLErrorReporter.SEVERITY_ERROR);
if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
"RootElementTypeMustMatchDoctypedecl",
new Object[]{fDoctypeName, rawname},
XMLErrorReporter.SEVERITY_ERROR);
}
}
}
}
fEmptyElement = false;
fAttributes.removeAllAttributes();
if(!seekCloseOfStartTag()){
fReadingAttributes = true;
fAttributeCacheUsedCount =0;
fStringBufferIndex =0;
fAddDefaultAttr = true;
fXmlnsDeclared = false;
do {
scanAttribute(fAttributes);
if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"ElementAttributeLimit",
new Object[]{rawname, new Integer(fAttributes.getLength()) },
XMLErrorReporter.SEVERITY_FATAL_ERROR );
}
} while (!seekCloseOfStartTag());
fReadingAttributes=false;
}
if (fBindNamespaces) {
// REVISIT: is it required? forbit xmlns prefix for element
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
"ElementXMLNSPrefix",
new Object[]{fElementQName.rawname},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
// bind the element
String prefix = fElementQName.prefix != null
? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
// assign uri to the element
fElementQName.uri = fNamespaceContext.getURI(prefix);
// make sure that object in the element stack is updated as well
fCurrentElement.uri = fElementQName.uri;
if (fElementQName.prefix == null && fElementQName.uri != null) {
fElementQName.prefix = XMLSymbols.EMPTY_STRING;
}
if (fElementQName.prefix != null && fElementQName.uri == null) {
fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
"ElementPrefixUnbound",
new Object[]{fElementQName.prefix, fElementQName.rawname},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
// bind attributes (xmlns are already bound bellow)
int length = fAttributes.getLength();
// fLength = 0; //initialize structure
for (int i = 0; i < length; i++) {
fAttributes.getName(i, fAttributeQName);
String aprefix = fAttributeQName.prefix != null
? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
String uri = fNamespaceContext.getURI(aprefix);
// REVISIT: try removing the first "if" and see if it is faster.
//
if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
// checkDuplicates(fAttributeQName, fAttributes);
continue;
}
if (aprefix != XMLSymbols.EMPTY_STRING) {
fAttributeQName.uri = uri;
if (uri == null) {
fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
"AttributePrefixUnbound",
new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
fAttributes.setURI(i, uri);
// checkDuplicates(fAttributeQName, fAttributes);
}
}
if (length > 1) {
QName name = fAttributes.checkDuplicatesNS();
if (name != null) {
if (name.uri != null) {
fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
"AttributeNSNotUnique",
new Object[]{fElementQName.rawname, name.localpart, name.uri},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
} else {
fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
"AttributeNotUnique",
new Object[]{fElementQName.rawname, name.rawname},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
}
}
}
if (fEmptyElement) {
//decrease the markup depth..
fMarkupDepth--;
// check that this element was opened in the same entity
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
reportFatalError("ElementEntityMismatch",
new Object[]{fCurrentElement.rawname});
}
// call handler
if (fDocumentHandler != null) {
if(DEBUG)
System.out.println("emptyElement = " + fElementQName);
fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
}
//We should not be popping out the context here in endELement becaause the namespace context is still
//valid when parser is at the endElement state.
fScanEndElement = true;
//if (fBindNamespaces) {
// fNamespaceContext.popContext();
//}
//pop the element off the stack..
fElementStack.popElement();
} else {
if(dtdGrammarUtil != null)
dtdGrammarUtil.startElement(fElementQName,fAttributes);
if(fDocumentHandler != null){
//complete element and attributes are traversed in this function so we can send a callback
//here.
//< strong >we shouldn't be sending callback in scanDocument()< /strong >
if(DEBUG)
System.out.println("startElement = " + fElementQName);
fDocumentHandler.startElement(fElementQName, fAttributes, null);
}
}
if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"< < < scanStartElement(): "+fEmptyElement);
return fEmptyElement;
}
Scans a start element. This method will handle the binding of
namespace information and notifying the handler of the start
of the element.
[44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
[40] STag ::= '<' Name (S Attribute)* S? '>'
Note: This method assumes that the leading
'<' character has been consumed.
Note: This method uses the fElementQName and
fAttributes variables. The contents of these variables will be
destroyed. The caller should copy important information out of
these variables before calling this method. |