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

src.java.com.ctc.wstx.msv.RelaxNGValidator Maven / Gradle / Ivy

The newest version!
/* Woodstox XML processor
 *
 * Copyright (c) 2004- Tatu Saloranta, [email protected]
 *
 * Licensed under the License specified in the file LICENSE which is
 * included with the source code.
 * You may not use this file except in compliance with the License.
 *
 * 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 com.ctc.wstx.msv;

import java.io.*;
import java.net.URL;
import java.util.*;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.*;

import org.codehaus.stax2.*;
import org.codehaus.stax2.validation.*;

import com.sun.msv.grammar.IDContextProvider2;
import com.sun.msv.util.DatatypeRef;
import com.sun.msv.util.StartTagInfo;
import com.sun.msv.util.StringRef;
import com.sun.msv.verifier.Acceptor;
import com.sun.msv.verifier.regexp.REDocumentDeclaration;

import com.ctc.wstx.exc.WstxIOException;
import com.ctc.wstx.util.TextAccumulator;

/**
 * Actual non-shareable validator instance, that is bound to an XML
 * document, or document subset.
 *

* Some notes about implementation: * * (a) Some properties of RelaxNG model are used for optimization: for * example, since text content in mixed-content models is not really * validated for content, we only combine text segments between start * and end tags (in any combination) -- full textual content between * matching start and end tags is not necessarily collected (or rather, * if there are child elements, is NEVER collected). */ public class RelaxNGValidator extends XMLValidator { /* //////////////////////////////////// // Configuration //////////////////////////////////// */ final XMLValidationSchema mParentSchema; final ValidationContext mContext; final REDocumentDeclaration mVGM; /* //////////////////////////////////// // State //////////////////////////////////// */ final ArrayList mAcceptors = new ArrayList(); Acceptor mCurrAcceptor = null; final TextAccumulator mTextAccumulator = new TextAccumulator(); /* //////////////////////////////////// // Helper objects //////////////////////////////////// */ final StringRef mErrorRef = new StringRef(); /** * StartTagInfo instance need not be thread-safe, and it is not immutable * so let's reuse one instance during a single validation. */ final StartTagInfo mStartTag = new StartTagInfo("", "", "", null, (IDContextProvider2) null); /** * Since RelaxNG never has to look into attributes during element * processing (start/end) -- unlike W3C schema, which may need to * access xsi:type and xsi:nillable -- we can just use an empty * shared instance. */ final AttributeProxy mAttributeProxy; final IDContextProvider2 mMsvContext; /* //////////////////////////////////// // Construction, configuration //////////////////////////////////// */ public RelaxNGValidator(XMLValidationSchema parent, ValidationContext ctxt, REDocumentDeclaration vgm) { mParentSchema = parent; mContext = ctxt; mVGM = vgm; mCurrAcceptor = mVGM.createAcceptor(); mMsvContext = new MSVContextProvider(ctxt); mAttributeProxy = new AttributeProxy(ctxt); } /* /////////////////////////////////////// // XMLValidator implementation /////////////////////////////////////// */ public XMLValidationSchema getSchema() { return mParentSchema; } /** * Method called to update information about the newly encountered (start) * element. At this point namespace information has been resolved, but * no DTD validation has been done. Validator is to do these validations, * including checking for attribute value (and existence) compatibility. */ public void validateElementStart(String localName, String uri, String prefix) throws XMLValidationException { // Very first thing: do we have text collected? if (mTextAccumulator.hasText()) { doValidateText(mTextAccumulator); } /* 31-Mar-2006, TSa: MSV seems to require empty String for empty/no * namespace, not null. */ if (uri == null) { uri = ""; } /* Do we need to properly fill it? Or could we just put local name? * Looking at code, I do believe it's only used for error reporting * purposes... */ //String qname = (prefix == null || prefix.length() == 0) ? localName : (prefix + ":" +localName); String qname = localName; mStartTag.reinit(uri, localName, qname, mAttributeProxy, mMsvContext); mCurrAcceptor = mCurrAcceptor.createChildAcceptor(mStartTag, mErrorRef); /* As per documentation, the side-effect of getting the error message * is that we also get a recoverable non-null acceptor... thus, should * never (?) see null acceptor being returned */ if (mErrorRef.str != null) { reportError(mErrorRef); } mAcceptors.add(mCurrAcceptor); } public String validateAttribute(String localName, String uri, String prefix, String value) throws XMLValidationException { if (mCurrAcceptor != null) { String qname = localName; // for now, let's assume we don't need prefixed version DatatypeRef typeRef = null; // for now, let's not care /* 31-Mar-2006, TSa: MSV seems to require empty String for empty/no * namespace, not null. */ if (uri == null) { uri = ""; } if (!mCurrAcceptor.onAttribute2(uri, localName, qname, value, mMsvContext, mErrorRef, typeRef) || mErrorRef.str != null) { reportError(mErrorRef); } } /* No normalization done by RelaxNG, is there? (at least nothing * visible to callers that is) */ return null; } public String validateAttribute(String localName, String uri, String prefix, char[] valueChars, int valueStart, int valueEnd) throws XMLValidationException { int len = valueEnd - valueStart; /* This is very sub-optimal... but MSV doesn't deal with char * arrays. */ return validateAttribute(localName, uri, prefix, new String(valueChars, valueStart, len)); } public int validateElementAndAttributes() throws XMLValidationException { if (mCurrAcceptor != null) { /* start tag info is still intact here (only attributes sent * since child acceptor was created) */ if (!mCurrAcceptor.onEndAttributes(mStartTag, mErrorRef) || mErrorRef.str != null) { reportError(mErrorRef); } int stringChecks = mCurrAcceptor.getStringCareLevel(); switch (stringChecks) { case Acceptor.STRING_PROHIBITED: // only WS return XMLValidator.CONTENT_ALLOW_WS; case Acceptor.STRING_IGNORE: // anything (mixed content models) return XMLValidator.CONTENT_ALLOW_ANY_TEXT; case Acceptor.STRING_STRICT: // validatable (data-oriented) return XMLValidator.CONTENT_ALLOW_VALIDATABLE_TEXT; default: throw new IllegalArgumentException("Internal error: unexpected string care level value return by MSV: "+stringChecks); } } // If no acceptor, we are recovering, no need or use to validate text return CONTENT_ALLOW_ANY_TEXT; } /** * @return Validation state that should be effective for the parent * element state */ public int validateElementEnd(String localName, String uri, String prefix) throws XMLValidationException { // Very first thing: do we have text collected? if (mTextAccumulator.hasText()) { doValidateText(mTextAccumulator); } Acceptor acc = (Acceptor)mAcceptors.remove(mAcceptors.size()-1); if (acc != null) { // may be null during error recovery? or not? if (!acc.isAcceptState(mErrorRef) || mErrorRef.str != null) { reportError(mErrorRef); } } int len = mAcceptors.size(); if (len == 0) { // root closed mCurrAcceptor = null; } else { mCurrAcceptor = (Acceptor) mAcceptors.get(len-1); } if (mCurrAcceptor != null && acc != null) { if (!mCurrAcceptor.stepForward(acc, mErrorRef) || mErrorRef.str != null) { reportError(mErrorRef); } int stringChecks = mCurrAcceptor.getStringCareLevel(); switch (stringChecks) { case Acceptor.STRING_PROHIBITED: // only WS return XMLValidator.CONTENT_ALLOW_WS; case Acceptor.STRING_IGNORE: // anything (mixed content models) return XMLValidator.CONTENT_ALLOW_ANY_TEXT; case Acceptor.STRING_STRICT: // validatable (data-oriented) return XMLValidator.CONTENT_ALLOW_VALIDATABLE_TEXT; default: throw new IllegalArgumentException("Internal error: unexpected string care level value return by MSV: "+stringChecks); } } return XMLValidator.CONTENT_ALLOW_ANY_TEXT; } public void validateText(String text, boolean lastTextSegment) throws XMLValidationException { /* If we got here, then it's likely we do need to call onText2(). * (not guaranteed, though; in case of multiple parallel validators, * only one of them may actually be interested) */ mTextAccumulator.addText(text); if (lastTextSegment) { doValidateText(mTextAccumulator); } } public void validateText(char[] cbuf, int textStart, int textEnd, boolean lastTextSegment) throws XMLValidationException { /* If we got here, then it's likely we do need to call onText(). * (not guaranteed, though; in case of multiple parallel validators, * only one of them may actually be interested) */ mTextAccumulator.addText(cbuf, textStart, textEnd); if (lastTextSegment) { doValidateText(mTextAccumulator); } } public void validationCompleted(boolean eod) throws XMLValidationException { // Is there something we should do here...? } /* /////////////////////////////////////// // Attribute info access /////////////////////////////////////// */ // // // Access to type info public String getAttributeType(int index) { // !!! TBI return null; } public int getIdAttrIndex() { // !!! TBI return -1; } public int getNotationAttrIndex() { // !!! TBI return -1; } /* /////////////////////////////////////// // Internal methods /////////////////////////////////////// */ private void doValidateText(TextAccumulator textAcc) throws XMLValidationException { if (mCurrAcceptor != null) { String str = textAcc.getAndClear(); DatatypeRef typeRef = null; if (!mCurrAcceptor.onText2(str, mMsvContext, mErrorRef, typeRef) || mErrorRef.str != null) { reportError(mErrorRef); } } } private void reportError(StringRef errorRef) throws XMLValidationException { String msg = errorRef.str; errorRef.str = null; if (msg == null) { msg = "Unknown reason"; } mContext.reportProblem(new XMLValidationProblem (mContext.getValidationLocation(), msg, XMLValidationProblem.SEVERITY_ERROR)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy