All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.impl.validator.ValidatingXMLStreamReader Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

The newest version!
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.xmlbeans.impl.validator;

import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeLoader;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.common.ValidatorListener;
import org.apache.xmlbeans.impl.common.XmlWhitespace;
import org.apache.xmlbeans.impl.common.QNameHelper;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.Location;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.StreamReaderDelegate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * This class is a wrapper over a generic XMLStreamReader that provides validation.
 * There are 3 cases:
 * 
1) the XMLStreamReader represents a document, it contains only one element document * - in this case the user schema type should be null or it should be a document SchemaType *
2) the XMLStreamReader represents an xml-fragment (content only) - must have at least one user type or xsi:type *
a) it has an xsi:type - if user schema type is available it has to be a base type of xsi:type *
b) it doesn't have xsi:type - user must provide a schema type * otherwise will error and will not do validation *
3) the XMLStreamReader represents a global attribute - i.e. user schema type is null and only one attribute *
* * @author Cezar Andrei (cezar.andrei at bea.com) * Date: Feb 13, 2004 */ public class ValidatingXMLStreamReader extends StreamReaderDelegate implements XMLStreamReader { public static final String OPTION_ATTTRIBUTE_VALIDATION_COMPAT_MODE = "OPTION_ATTTRIBUTE_VALIDATION_COMPAT_MODE"; private static final String URI_XSI = "http://www.w3.org/2001/XMLSchema-instance"; private static final QName XSI_TYPE = new QName(URI_XSI, "type"); private static final QName XSI_NIL = new QName(URI_XSI, "nil"); private static final QName XSI_SL = new QName(URI_XSI, "schemaLocation"); private static final QName XSI_NSL = new QName(URI_XSI, "noNamespaceSchemaLocation"); private SchemaType _contentType; private SchemaTypeLoader _stl; private XmlOptions _options; private Collection _errorListener; protected Validator _validator; private final ElementEventImpl _elemEvent; private final AttributeEventImpl _attEvent; private final SimpleEventImpl _simpleEvent; private PackTextXmlStreamReader _packTextXmlStreamReader; private int _state; private final int STATE_FIRSTEVENT = 0; private final int STATE_VALIDATING = 1; private final int STATE_ATTBUFFERING = 2; private final int STATE_ERROR = 3; private List _attNamesList; private List _attValuesList; private SchemaType _xsiType; private int _depth; /** * Default constructor. Use init(...) to set the params. * See {@link #init} */ public ValidatingXMLStreamReader() { super(); _elemEvent = new ElementEventImpl(); _attEvent = new AttributeEventImpl(); _simpleEvent = new SimpleEventImpl(); _packTextXmlStreamReader = new PackTextXmlStreamReader(); } /** * Used in case of reusing the same ValidatinXMLStreamReader object * @param xsr The stream to be validated * @param startWithCurrentEvent Validation will start if true with the current event or if false with the next event in the stream * @param contentType The schemaType of the content. This can be null for document and global Att validation * @param stl SchemaTypeLoader context of validation * @param options Validator options * @param errorListener Errors and warnings listener */ public void init(XMLStreamReader xsr, boolean startWithCurrentEvent, SchemaType contentType, SchemaTypeLoader stl, XmlOptions options, Collection errorListener) { _packTextXmlStreamReader.init(xsr); // setParent(xsr); setParent(_packTextXmlStreamReader); _contentType = contentType; _stl = stl; _options = options; _errorListener = errorListener; // _elemEvent.setXMLStreamReader(xsr); // _attEvent.setXMLStreamReader(xsr); // _simpleEvent.setXMLStreamReader(xsr); _elemEvent.setXMLStreamReader(_packTextXmlStreamReader); _attEvent.setXMLStreamReader(_packTextXmlStreamReader); _simpleEvent.setXMLStreamReader(_packTextXmlStreamReader); _validator = null; _state = STATE_FIRSTEVENT; if (_attNamesList!=null) { _attNamesList.clear(); _attValuesList.clear(); } _xsiType = null; _depth = 0; if (startWithCurrentEvent) { int evType = getEventType(); validate_event(evType); } } private static class PackTextXmlStreamReader extends StreamReaderDelegate implements XMLStreamReader { private boolean _hasBufferedText; private StringBuffer _buffer = new StringBuffer(); private int _textEventType; void init(XMLStreamReader xmlstream) { setParent(xmlstream); _hasBufferedText = false; _buffer.delete(0, _buffer.length()); } public int next() throws XMLStreamException { if (_hasBufferedText) { clearBuffer(); return super.getEventType(); } int evType = super.next(); if (evType == XMLEvent.CHARACTERS || evType == XMLEvent.CDATA || evType == XMLEvent.SPACE) { _textEventType = evType; bufferText(); } return evType; } private void clearBuffer() { _buffer.delete(0, _buffer.length()); _hasBufferedText = false; } private void bufferText() throws XMLStreamException { if (super.hasText()) _buffer.append( super.getText()); _hasBufferedText = true; while (hasNext()) { int evType = super.next(); switch (evType) { case XMLEvent.CHARACTERS: case XMLEvent.CDATA: case XMLEvent.SPACE: if (super.hasText()) _buffer.append(super.getText()); case XMLEvent.COMMENT: //ignore continue; default: return; } } } public String getText() { assert _hasBufferedText; return _buffer.toString(); } public int getTextLength() { assert _hasBufferedText; return _buffer.length(); } public int getTextStart() { assert _hasBufferedText; return 0; } public char[] getTextCharacters() { assert _hasBufferedText; return _buffer.toString().toCharArray(); } public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) { assert _hasBufferedText; _buffer.getChars(sourceStart, sourceStart + length, target, targetStart); return length; } public boolean isWhiteSpace() { assert _hasBufferedText; return XmlWhitespace.isAllSpace(_buffer); } public boolean hasText() { if (_hasBufferedText) return true; else return super.hasText(); } public int getEventType() { if (_hasBufferedText) return _textEventType; else return super.getEventType(); } } private static class ElementEventImpl implements ValidatorListener.Event { private static final int BUF_LENGTH = 1024; private char[] _buf = new char[BUF_LENGTH]; private int _length; private boolean _supportForGetTextCharacters = true; private XMLStreamReader _xmlStream; private void setXMLStreamReader(XMLStreamReader xsr) { _xmlStream = xsr; } // can return null, used only to locate errors public XmlCursor getLocationAsCursor() { return null; } public javax.xml.stream.Location getLocation() { return _xmlStream.getLocation(); } // fill up chars with the xsi:type attribute value if there is one othervise return false public String getXsiType() // BEGIN xsi:type { return _xmlStream.getAttributeValue(URI_XSI, "type"); } // fill up chars with xsi:nill attribute value if any public String getXsiNil() // BEGIN xsi:nil { return _xmlStream.getAttributeValue(URI_XSI, "nil"); } // not used curently public String getXsiLoc() // BEGIN xsi:schemaLocation { return _xmlStream.getAttributeValue(URI_XSI, "schemaLocation"); } // not used curently public String getXsiNoLoc() // BEGIN xsi:noNamespaceSchemaLocation { return _xmlStream.getAttributeValue(URI_XSI, "noNamespaceSchemaLocation"); } // On START and ATTR public QName getName() { // avoid construction of a new QName object after the bug in getName() is fixed. if (_xmlStream.hasName()) return new QName(_xmlStream.getNamespaceURI(), _xmlStream.getLocalName()); else return null; } // On TEXT and ATTR public String getText() { _length = 0; addTextToBuffer(); return new String( _buf, 0, _length ); // return _xmlStream.getText(); } public String getText(int wsr) { return XmlWhitespace.collapse( _xmlStream.getText(), wsr ); } public boolean textIsWhitespace() { return _xmlStream.isWhiteSpace(); } public String getNamespaceForPrefix(String prefix) { return _xmlStream.getNamespaceURI(prefix); } private void addTextToBuffer() { int textLength = _xmlStream.getTextLength(); ensureBufferLength(textLength); if (_supportForGetTextCharacters) try { _length = _xmlStream.getTextCharacters(0, _buf, _length, textLength); } catch(Exception e) { _supportForGetTextCharacters = false; } if(!_supportForGetTextCharacters) { System.arraycopy(_xmlStream.getTextCharacters(), _xmlStream.getTextStart(), _buf, _length, textLength); _length = _length + textLength; } } private void ensureBufferLength(int lengthToAdd) { if (_length + lengthToAdd>_buf.length) { char[] newBuf = new char[_length + lengthToAdd]; if (_length>0) System.arraycopy(_buf, 0, newBuf, 0, _length); _buf = newBuf; } } } private static final class AttributeEventImpl implements ValidatorListener.Event { private int _attIndex; private XMLStreamReader _xmlStream; private void setXMLStreamReader(XMLStreamReader xsr) { _xmlStream = xsr; } // can return null, used only to locate errors public XmlCursor getLocationAsCursor() { return null; } public javax.xml.stream.Location getLocation() { return _xmlStream.getLocation(); } // fill up chars with the xsi:type attribute value if there is one othervise return false public String getXsiType() // BEGIN xsi:type { throw new IllegalStateException(); } // fill up chars with xsi:nill attribute value if any public String getXsiNil() // BEGIN xsi:nil { throw new IllegalStateException(); } // not used curently public String getXsiLoc() // BEGIN xsi:schemaLocation { throw new IllegalStateException(); } // not used curently public String getXsiNoLoc() // BEGIN xsi:noNamespaceSchemaLocation { throw new IllegalStateException(); } // On START and ATTR public QName getName() { assert _xmlStream.isStartElement() : "Not on Start Element."; String uri = _xmlStream.getAttributeNamespace(_attIndex); QName qn = new QName(uri==null ? "" : uri, _xmlStream.getAttributeLocalName(_attIndex)); //System.out.println(" Att QName: " + qn); return qn; } // On TEXT and ATTR public String getText() { assert _xmlStream.isStartElement() : "Not on Start Element."; return _xmlStream.getAttributeValue(_attIndex); } public String getText(int wsr) { assert _xmlStream.isStartElement() : "Not on Start Element."; return XmlWhitespace.collapse( _xmlStream.getAttributeValue(_attIndex), wsr ); } public boolean textIsWhitespace() { throw new IllegalStateException(); } public String getNamespaceForPrefix(String prefix) { assert _xmlStream.isStartElement() : "Not on Start Element."; return _xmlStream.getNamespaceURI(prefix); } private void setAttributeIndex(int attIndex) { _attIndex = attIndex; } } /** * This is used as implementation of Event for validating global attributes * and for pushing the buffered attributes */ private static final class SimpleEventImpl implements ValidatorListener.Event { private String _text; private QName _qname; private XMLStreamReader _xmlStream; private void setXMLStreamReader(XMLStreamReader xsr) { _xmlStream = xsr; } // should return null, getLocation will be used, used only to locate errors public XmlCursor getLocationAsCursor() { return null; } public javax.xml.stream.Location getLocation() { return _xmlStream.getLocation(); } // fill up chars with the xsi:type attribute value if there is one othervise return false public String getXsiType() // BEGIN xsi:type { return null; } // fill up chars with xsi:nill attribute value if any public String getXsiNil() // BEGIN xsi:nil { return null; } // not used curently public String getXsiLoc() // BEGIN xsi:schemaLocation { return null; } // not used curently public String getXsiNoLoc() // BEGIN xsi:noNamespaceSchemaLocation { return null; } // On START and ATTR public QName getName() { return _qname; } // On TEXT and ATTR public String getText() { return _text; } public String getText(int wsr) { return XmlWhitespace.collapse( _text, wsr ); } public boolean textIsWhitespace() { return false; } public String getNamespaceForPrefix(String prefix) { return _xmlStream.getNamespaceURI(prefix); } } /* public methods in XMLStreamReader */ public Object getProperty(String s) throws IllegalArgumentException { return super.getProperty(s); } public int next() throws XMLStreamException { int evType = super.next(); //debugEvent(evType); validate_event(evType); return evType; } private void validate_event(int evType) { if (_state==STATE_ERROR) return; if (_depth<0) throw new IllegalArgumentException("ValidatingXMLStreamReader cannot go further than the subtree is was initialized on."); switch(evType) { case XMLEvent.START_ELEMENT: _depth++; if (_state == STATE_ATTBUFFERING) pushBufferedAttributes(); if (_validator==null) { // avoid construction of a new QName object after the bug in getName() is fixed. QName qname = new QName(getNamespaceURI(), getLocalName()); if (_contentType==null) _contentType = typeForGlobalElement(qname); if (_state==STATE_ERROR) break; initValidator(_contentType); _validator.nextEvent(Validator.BEGIN, _elemEvent); } _validator.nextEvent(Validator.BEGIN, _elemEvent); int attCount = getAttributeCount(); validate_attributes(attCount); break; case XMLEvent.ATTRIBUTE: if (getAttributeCount()==0) break; if (_state == STATE_FIRSTEVENT || _state == STATE_ATTBUFFERING) { // buffer all Attributes for (int i=0; i 1 than the validator will add an error } else { addError("No content type provided for validation of a content model."); _state = STATE_ERROR; return; } } // here validationType is the right type, start pushing all acumulated attributes initValidator(validationType); _validator.nextEvent(Validator.BEGIN, _simpleEvent); // validate attributes from _attNamesList validate_attributes(_attNamesList.size()); _attNamesList = null; _attValuesList = null; _state = STATE_VALIDATING; } private boolean isSpecialAttribute(QName qn) { if (qn.getNamespaceURI().equals(URI_XSI)) return qn.getLocalPart().equals(XSI_TYPE.getLocalPart()) || qn.getLocalPart().equals(XSI_NIL.getLocalPart()) || qn.getLocalPart().equals(XSI_SL.getLocalPart()) || qn.getLocalPart().equals(XSI_NSL.getLocalPart()); return false; } /** * Initializes the validator for the given schemaType * @param schemaType */ private void initValidator(SchemaType schemaType) { assert schemaType!=null; _validator = new Validator(schemaType, null, _stl, _options, _errorListener); } private SchemaType typeForGlobalElement(QName qname) { assert qname!=null; SchemaType docType = _stl.findDocumentType(qname); if (docType==null) { addError("Schema document type not found for element '" + qname + "'."); _state = STATE_ERROR; } return docType; } private void addError(String msg) { String source = null; Location location = getLocation(); if (location != null) { source = location.getPublicId(); if (source==null) source = location.getSystemId(); _errorListener.add(XmlError.forLocation(msg, source, location)); } else _errorListener.add(XmlError.forMessage(msg)); } protected void validate_attributes(int attCount) { for(int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy