You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by er...@locus.apache.org on 2000/10/18 03:07:21 UTC
cvs commit: xml-xerces/java/src/org/apache/xerces/impl/validation/validators XMLDTDValidator.java
ericye 00/10/17 18:07:21
Modified: java/src/org/apache/xerces/impl/validation/validators Tag:
xerces_j_2 XMLDTDValidator.java
Log:
begin to add element content validation.
Revision Changes Path
No revision
No revision
1.1.2.2 +366 -5 xml-xerces/java/src/org/apache/xerces/impl/validation/validators/Attic/XMLDTDValidator.java
Index: XMLDTDValidator.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/impl/validation/validators/Attic/XMLDTDValidator.java,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -r1.1.2.1 -r1.1.2.2
--- XMLDTDValidator.java 2000/10/16 23:04:11 1.1.2.1
+++ XMLDTDValidator.java 2000/10/18 01:07:21 1.1.2.2
@@ -59,8 +59,13 @@
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.XMLValidator;
+import org.apache.xerces.impl.msg.XMLMessageFormatter;
+import org.apache.xerces.impl.validation.ContentModelValidator;
+import org.apache.xerces.impl.validation.DatatypeValidator;
+import org.apache.xerces.impl.validation.InvalidDatatypeValueException;
import org.apache.xerces.impl.validation.Grammar;
import org.apache.xerces.impl.validation.GrammarPool;
+import org.apache.xerces.impl.validation.XMLElementDecl;
import org.apache.xerces.impl.validation.grammars.DTDGrammar;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.xni.QName;
@@ -82,7 +87,7 @@
/**
* @author Eric Ye, IBM
*
- * @version $Id: XMLDTDValidator.java,v 1.1.2.1 2000/10/16 23:04:11 ericye Exp $
+ * @version $Id: XMLDTDValidator.java,v 1.1.2.2 2000/10/18 01:07:21 ericye Exp $
*/
public class XMLDTDValidator
extends XMLValidator {
@@ -91,6 +96,37 @@
// Data
//
+ /** Cache all infor regarding the current element */
+ private QName fCurrentElement = new QName();
+ private int fCurrentElementIndex = -1;
+ private int fCurrentContentSpecType = -1;
+ private boolean fNamespacesEnabled = false;
+ private int fNamespacesPrefix = -1;
+ private QName fRootElement = new QName();
+ private boolean fSeenDoctypeDecl = false;
+
+ private final int TOP_LEVEL_SCOPE = -1;
+ private int fEmptyURI = - 1;
+
+ /** element stack */
+ private int[] fElementIndexStack = new int[8];
+ private int[] fContentSpecTypeStack = new int[8];
+ private QName[] fElementQNamePartsStack = new QName[8];
+
+ /** childrent list and offset stack */
+ private QName[] fElementChildren = new QName[32];
+ private int fElementChildrenLength = 0;
+ private int[] fElementChildrenOffsetStack = new int[32];
+ private int fElementDepth = -1;
+
+ /** validation states */
+ private boolean fStandaloneIsNo = false;
+ private boolean fSeenRootElement = false;
+
+ /** temporary variables so that we create less objects */
+ private XMLElementDecl fTempElementDecl = new XMLElementDecl();
+
+
//
// Constructors
//
@@ -99,6 +135,29 @@
//
// XMLComponent methods
//
+
+ /*
+ * Resets the component. The component can query the component manager
+ * about any features and properties that affect the operation of the
+ * component.
+ *
+ * @param componentManager The component manager.
+ *
+ * @throws SAXException Thrown by component on initialization error.
+ * For example, if a feature or property is
+ * required for the operation of the component, the
+ * component manager may throw a
+ * SAXNotRecognizedException or a
+ * SAXNotSupportedException.
+ */
+ public void reset(XMLComponentManager configurationManager)
+ throws SAXException {
+
+ super.reset(configurationManager);
+
+ fElementDepth = -1;
+
+ } // reset(XMLComponentManager)
//
@@ -116,6 +175,7 @@
if (fDocumentHandler != null) {
fDocumentHandler.startDocument();
}
+
} // startDocument()
@@ -134,6 +194,11 @@
public void xmlDecl(String version, String encoding, String standalone)
throws SAXException {
+ if (standalone != null )
+ if ( standalone.equals("no") ) {
+ fStandaloneIsNo = true;
+ }
+
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.xmlDecl(version, encoding, standalone);
@@ -155,6 +220,8 @@
public void doctypeDecl(String rootElement, String publicId, String systemId)
throws SAXException {
+ fRootElement.setValues(null, rootElement, rootElement, null);
+
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.doctypeDecl(rootElement, publicId, systemId);
@@ -193,12 +260,68 @@
*/
public void startElement(QName element, XMLAttributes attributes)
throws SAXException {
+
+ // VC: Root Element Type
+ // see if the root element's name matches the one in DoctypeDecl
+ if (!fSeenRootElement) {
+ fSeenRootElement = true;
+ rootElementSpecified(element);
+ }
+
+ // TO DO
+ // 0. resolve the element
+ // 1. insert default attributes
+ // 2. validate the attrivute list.
+
+ // increment the element depth, add this element's
+ // QName to its enclosing element 's children list
+ fElementDepth++;
+ //if (fElementDepth >= 0) {
+ if (fValidation) {
+ // push current length onto stack
+ if (fElementChildrenOffsetStack.length < fElementDepth) {
+ int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
+ System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length);
+ fElementChildrenOffsetStack = newarray;
+ }
+ fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
- // call handlers
- if (fDocumentHandler != null) {
- fDocumentHandler.startElement(element, attributes);
+ // add this element to children
+ if (fElementChildren.length <= fElementChildrenLength) {
+ QName[] newarray = new QName[fElementChildrenLength * 2];
+ System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
+ fElementChildren = newarray;
+ }
+ QName qname = fElementChildren[fElementChildrenLength];
+ if (qname == null) {
+ for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
+ fElementChildren[i] = new QName();
+ }
+ qname = fElementChildren[fElementChildrenLength];
+ }
+ qname.setValues(element);
+ fElementChildrenLength++;
+
+ /***
+ if (DEBUG_ELEMENT_CHILDREN) {
+ printChildren();
+ printStack();
+ }
+ /***/
}
-
+
+
+ ensureStackCapacity(fElementDepth);
+
+ fCurrentElement.setValues(element);
+
+ fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement);
+
+ fElementIndexStack[fElementDepth] = fCurrentElementIndex;
+ fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
+
+ super.startElement(element, attributes);
+
} // startElement(QName,XMLAttributes)
/**
@@ -247,11 +370,102 @@
*/
public void endElement(QName element) throws SAXException {
+ String prefixIndex = fCurrentElement.prefix;
+ String elementType = fCurrentElement.rawname;
+
+ fElementDepth--;
+ if (fValidation) {
+ int elementIndex = fCurrentElementIndex;
+ if (elementIndex != -1 && fCurrentContentSpecType != -1) {
+ QName children[] = fElementChildren;
+ int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
+ int childrenLength = fElementChildrenLength - childrenOffset;
+ int result = checkContent(elementIndex,
+ children, childrenOffset, childrenLength);
+
+
+ if (result != -1) {
+ // TO DO : fix this
+ /****
+ int majorCode = result != childrenLength ? XMLMessages.MSG_CONTENT_INVALID : XMLMessages.MSG_CONTENT_INCOMPLETE;
+ fGrammar.getElementDecl(elementIndex, fTempElementDecl);
+ if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
+ reportRecoverableXMLError(majorCode,
+ 0,
+ fStringPool.toString(elementType),
+ "EMPTY");
+ } else
+ reportRecoverableXMLError(majorCode,
+ 0,
+ fStringPool.toString(elementType),
+ XMLContentSpec.toString(fGrammar, fStringPool, fTempElementDecl.contentSpecIndex));
+
+ /****/
+ }
+ }
+ fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
+ }
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.endElement(element);
}
+
+ // now pop this element off the top of the element stack
+ if (fElementDepth < -1) {
+ throw new RuntimeException("FWK008 Element stack underflow");
+ }
+ if (fElementDepth < 0) {
+ fCurrentElement.clear();
+ fCurrentElementIndex = -1;
+ fCurrentContentSpecType = -1;
+
+ // TO DO : fix this
+ //
+ // Check after document is fully parsed
+ // (1) check that there was an element with a matching id for every
+ // IDREF and IDREFS attr (V_IDREF0)
+ //
+ /**
+ if (fValidating ) {
+ try {
+ this.fValIDRef.validate( null, this.fValidateIDRef );
+ this.fValIDRefs.validate( null, this.fValidateIDRef );
+ } catch ( InvalidDatatypeValueException ex ) {
+ reportRecoverableXMLError( ex.getMajorCode(), ex.getMinorCode(),
+ ex.getMessage() );
+
+
+ }
+ }
+
+ try {//Reset datatypes state
+ this.fValID.validate( null, this.fResetID );
+ this.fValIDRef.validate(null, this.fResetIDRef );
+ this.fValIDRefs.validate(null, this.fResetIDRef );
+ } catch ( InvalidDatatypeValueException ex ) {
+ System.err.println("Error re-Initializing: ID,IDRef,IDRefs pools" );
+ }
+ ***/
+ return;
+ }
+
+
+
+
+ if (fNamespaces) { //If Namespace enable then localName != rawName
+ fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].localpart;
+ } else {//REVISIT - jeffreyr - This is so we still do old behavior when namespace is off
+ fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].rawname;
+ }
+ fCurrentElement.rawname = fElementQNamePartsStack[fElementDepth].rawname;
+ fCurrentElement.uri = fElementQNamePartsStack[fElementDepth].uri;
+ fCurrentElement.prefix = fElementQNamePartsStack[fElementDepth].prefix;
+
+
+ fCurrentElementIndex = fElementIndexStack[fElementDepth];
+ fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
+
} // endElement(QName)
/**
@@ -949,5 +1163,152 @@
}
} // endContentModel()
+
+
+ //private methods
+
+ /** Root element specified. */
+ private void rootElementSpecified(QName rootElement) throws SAXException {
+ if (fValidation) {
+ String root1 = fRootElement.rawname;
+ String root2 = rootElement.rawname;
+ if ( root1 == null || !root1.equals(root2)) {
+ fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
+ "RootElementTypeMustMatchDoctypedecl",
+ new Object[]{root1, root2},
+ XMLErrorReporter.SEVERITY_ERROR);
+ }
+ }
+ } // rootElementSpecified(QName)
+
+
+ /**
+ * Check that the content of an element is valid.
+ * <p>
+ * This is the method of primary concern to the validator. This method is called
+ * upon the scanner reaching the end tag of an element. At that time, the
+ * element's children must be structurally validated, so it calls this method.
+ * The index of the element being checked (in the decl pool), is provided as
+ * well as an array of element name indexes of the children. The validator must
+ * confirm that this element can have these children in this order.
+ * <p>
+ * This can also be called to do 'what if' testing of content models just to see
+ * if they would be valid.
+ * <p>
+ * Note that the element index is an index into the element decl pool, whereas
+ * the children indexes are name indexes, i.e. into the string pool.
+ * <p>
+ * A value of -1 in the children array indicates a PCDATA node. All other
+ * indexes will be positive and represent child elements. The count can be
+ * zero, since some elements have the EMPTY content model and that must be
+ * confirmed.
+ *
+ * @param elementIndex The index within the <code>ElementDeclPool</code> of this
+ * element.
+ * @param childCount The number of entries in the <code>children</code> array.
+ * @param children The children of this element.
+ *
+ * @return The value -1 if fully valid, else the 0 based index of the child
+ * that first failed. If the value returned is equal to the number
+ * of children, then additional content is required to reach a valid
+ * ending state.
+ *
+ * @exception Exception Thrown on error.
+ */
+ private int checkContent(int elementIndex,
+ QName[] children,
+ int childOffset,
+ int childCount) throws SAXException {
+
+ fCurrentGrammar.getElementDecl(elementIndex, fTempElementDecl);
+
+ // Get the element name index from the element
+ final String elementType = fCurrentElement.rawname;
+
+ // Get out the content spec for this element
+ final int contentType = fCurrentContentSpecType;
+
+
+ //
+ // Deal with the possible types of content. We try to optimized here
+ // by dealing specially with content models that don't require the
+ // full DFA treatment.
+ //
+ if (contentType == XMLElementDecl.TYPE_EMPTY) {
+ //
+ // If the child count is greater than zero, then this is
+ // an error right off the bat at index 0.
+ //
+ if (childCount != 0) {
+ return 0;
+ }
+ } else if (contentType == XMLElementDecl.TYPE_ANY) {
+ //
+ // This one is open game so we don't pass any judgement on it
+ // at all. Its assumed to fine since it can hold anything.
+ //
+ } else if (contentType == XMLElementDecl.TYPE_MIXED ||
+ contentType == XMLElementDecl.TYPE_CHILDREN) {
+ // Get the content model for this element, faulting it in if needed
+ ContentModelValidator cmElem = null;
+ cmElem = fTempElementDecl.contentModelValidator;
+ int result = cmElem.validate(children, childOffset, childCount);
+ return result;
+ } else if (contentType == -1) {
+ /****
+ reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
+ XMLMessages.VC_ELEMENT_VALID,
+ elementType);
+ /****/
+ } else if (contentType == XMLElementDecl.TYPE_SIMPLE ) {
+
+ //REVISIT
+ // this should never be reached in the case of DTD validation.
+
+ } else {
+ /****
+ fErrorReporter.reportError(fErrorReporter.getLocator(),
+ ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
+ ImplementationMessages.VAL_CST,
+ 0,
+ null,
+ XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
+ /****/
+ }
+
+ // We succeeded
+ return -1;
+
+ } // checkContent(int,int,QName[]):int
+
+
+ /** ensure element stack capacity */
+ private void ensureStackCapacity ( int newElementDepth) {
+
+ if (newElementDepth == fElementQNamePartsStack.length ) {
+ int[] newStack = new int[newElementDepth * 2];
+
+ QName[] newStackOfQueue = new QName[newElementDepth * 2];
+ System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth );
+ fElementQNamePartsStack = newStackOfQueue;
+
+ QName qname = fElementQNamePartsStack[newElementDepth];
+ if (qname == null) {
+ for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
+ fElementQNamePartsStack[i] = new QName();
+ }
+ }
+
+ newStack = new int[newElementDepth * 2];
+ System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth);
+ fElementIndexStack = newStack;
+
+ newStack = new int[newElementDepth * 2];
+ System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth);
+ fContentSpecTypeStack = newStack;
+
+ }
+ } // ensureStackCapacity
+
} // class XMLDTDValidator