/* Woodstox XML processor
*
* Copyright (c) 2004- Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in file LICENSE, 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.dtd;
import java.util.*;
import javax.xml.stream.XMLStreamException;
import org.codehaus.stax2.validation.*;
import com.ctc.wstx.ent.EntityDecl;
import com.ctc.wstx.util.DataUtil;
import com.ctc.wstx.util.ElementIdMap;
import com.ctc.wstx.util.ExceptionUtil;
import com.ctc.wstx.util.PrefixedName;
This class is a "non-validating validator"; a validator-like object
that handles DTD-based non-validation functionality: determining type
information and default values. This instance does NOT implement any
actual DTD-validation, and is to be used in DTD-aware non-validating
mode.
/**
* This class is a "non-validating validator"; a validator-like object
* that handles DTD-based non-validation functionality: determining type
* information and default values. This instance does NOT implement any
* actual DTD-validation, and is to be used in DTD-aware non-validating
* mode.
*/
public class DTDTypingNonValidator
extends DTDValidatorBase
{
/*
///////////////////////////////////////////
// Element def/spec/validator stack, state
///////////////////////////////////////////
*/
Flag that indicates if current element has any attributes that
have default values.
/**
* Flag that indicates if current element has any attributes that
* have default values.
*/
protected boolean mHasAttrDefaults = false;
Bitset used for keeping track of defaulted attributes for which values
have been found. Only non-null when current element does have such
attributes
/**
* Bitset used for keeping track of defaulted attributes for which values
* have been found. Only non-null when current element does have such
* attributes
*/
protected BitSet mCurrDefaultAttrs = null;
Flag that indicates whether any of the attributes is potentially
normalizable, and we are in attribute-normalizing mode.
/**
* Flag that indicates whether any of the attributes is potentially
* normalizable, and we are in attribute-normalizing mode.
*/
protected boolean mHasNormalizableAttrs = false;
/*
///////////////////////////////////////
// Temporary helper objects
///////////////////////////////////////
*/
Reusable lazily instantiated BitSet; needed to keep track of
'missing' attributes with default values (normal default, #FIXED).
/**
* Reusable lazily instantiated BitSet; needed to keep track of
* 'missing' attributes with default values (normal default, #FIXED).
*/
BitSet mTmpDefaultAttrs;
/*
///////////////////////////////////////////
// Life-cycle
///////////////////////////////////////////
*/
public DTDTypingNonValidator(DTDSubset schema, ValidationContext ctxt, boolean hasNsDefaults,
Map<PrefixedName,DTDElement> elemSpecs, Map<String,EntityDecl> genEntities)
{
super(schema, ctxt, hasNsDefaults, elemSpecs, genEntities);
}
Returns: False, since this is not a real validator
/**
* @return False, since this is not a real validator
*/
@Override
public final boolean reallyValidating() { return false; }
/*
///////////////////////////////////////
// Configuration
///////////////////////////////////////
*/
This 'validator' will not normalize any attributes,
so let's implement this as no-op.
/**
* This 'validator' will not normalize any attributes,
* so let's implement this as no-op.
*/
@Override
public void setAttrValueNormalization(boolean state) {
// nop
}
/*
///////////////////////////////////////
// XMLValidator implementation
///////////////////////////////////////
*/
//public XMLValidationSchema getSchema()
@Override
public void validateElementStart(String localName, String uri, String prefix)
throws XMLStreamException
{
// Ok, can we find the element definition?
mTmpKey.reset(prefix, localName);
DTDElement elem = mElemSpecs.get(mTmpKey);
// whether it's found or not, let's add a stack frame:
int elemCount = mElemCount++;
if (elemCount >= mElems.length) {
mElems = (DTDElement[]) DataUtil.growArrayBy50Pct(mElems);
}
mElems[elemCount] = mCurrElem = elem;
mAttrCount = 0;
mIdAttrIndex = -2; // -2 as a "don't know yet" marker
/* but if not found, can not obtain any type information. Not
* a validation problem though, since we are doing none...
* Oh, also, unlike with real validation, not having actual element
* information is ok; can still have attributes!
*/
if (elem == null) { // || !elem.isDefined())
mCurrAttrDefs = NO_ATTRS;
mHasAttrDefaults = false;
mCurrDefaultAttrs = null;
mHasNormalizableAttrs = false;
return;
}
// If element found, does it have any attributes?
mCurrAttrDefs = elem.getAttributes();
if (mCurrAttrDefs == null) {
mCurrAttrDefs = NO_ATTRS;
mHasAttrDefaults = false;
mCurrDefaultAttrs = null;
mHasNormalizableAttrs = false;
return;
}
// Any normalization needed?
mHasNormalizableAttrs = mNormAttrs || elem.attrsNeedValidation();
// Any default values?
mHasAttrDefaults = elem.hasAttrDefaultValues();
if (mHasAttrDefaults) {
/* Special count also contains ones with #REQUIRED value, but
* that's a minor sub-optimality...
*/
int specCount = elem.getSpecialCount();
BitSet bs = mTmpDefaultAttrs;
if (bs == null) {
mTmpDefaultAttrs = bs = new BitSet(specCount);
} else {
bs.clear();
}
mCurrDefaultAttrs = bs;
} else {
mCurrDefaultAttrs = null;
}
}
@Override
public String validateAttribute(String localName, String uri,
String prefix, String value)
throws XMLStreamException
{
/* no need to do any validation; however, need to do following:
*
* (a) Figure out type info, if any (to get data type, id index etc);
* if yes, do:
* (1) If attribute has default value, note down it's not needed due
* to explicit definition
* (2) If attribute is normalizable, normalize it without validation
*/
DTDAttribute attr = mCurrAttrDefs.get(mTmpKey.reset(prefix, localName));
int index = mAttrCount++;
if (index >= mAttrSpecs.length) {
mAttrSpecs = (DTDAttribute[]) DataUtil.growArrayBy50Pct(mAttrSpecs);
}
mAttrSpecs[index] = attr;
/* Although undeclared attribute would be a validation error,
* we don't care here... just need to skip it
*/
if (attr != null) {
if (mHasAttrDefaults) {
/* Once again, let's use more generic 'special' index,
* even though it also includes #REQUIRED values
*/
int specIndex = attr.getSpecialIndex();
if (specIndex >= 0) {
mCurrDefaultAttrs.set(specIndex);
}
}
if (mHasNormalizableAttrs) {
// !!! TBI
}
}
return null; // fine as is
}
@Override
public String validateAttribute(String localName, String uri,
String prefix,
char[] valueChars, int valueStart,
int valueEnd)
throws XMLStreamException
{
// note: cut'n pasted from above...
DTDAttribute attr = mCurrAttrDefs.get(mTmpKey.reset(prefix, localName));
int index = mAttrCount++;
if (index >= mAttrSpecs.length) {
mAttrSpecs = (DTDAttribute[]) DataUtil.growArrayBy50Pct(mAttrSpecs);
}
mAttrSpecs[index] = attr;
if (attr != null) {
if (mHasAttrDefaults) {
int specIndex = attr.getSpecialIndex();
if (specIndex >= 0) {
mCurrDefaultAttrs.set(specIndex);
}
}
if (mHasNormalizableAttrs) { // may get normalized, after all
return attr.normalize(this, valueChars, valueStart, valueEnd);
}
}
return null; // fine as is
}
@Override
public int validateElementAndAttributes()
throws XMLStreamException
{
/* Ok; since we are not really validating, we just need to add possible
* attribute default values, and return "anything goes"
* as the allowable content:
*/
DTDElement elem = mCurrElem;
if (mHasAttrDefaults) {
BitSet specBits = mCurrDefaultAttrs;
int specCount = elem.getSpecialCount();
int ix = specBits.nextClearBit(0);
while (ix < specCount) { // something amiss!
List<DTDAttribute> specAttrs = elem.getSpecialAttrs();
DTDAttribute attr = specAttrs.get(ix);
if (attr.hasDefaultValue()) { // no default for #REQUIRED...
doAddDefaultValue(attr);
}
ix = specBits.nextClearBit(ix+1);
}
}
/* However: we should indicate cases where PCDATA is not supposed
* to occur -- although it won't be considered an error, when not
* validating, info is needed to determine type of SPACE instead
* of CHARACTERS. Other validation types are not to be returned,
* however, since caller doesn't know how to deal with such
* cases.
*/
return (elem == null) ? XMLValidator.CONTENT_ALLOW_ANY_TEXT :
elem.getAllowedContentIfSpace();
}
@Override
public int validateElementEnd(String localName, String uri, String prefix)
throws XMLStreamException
{
/* Since we are not really validating, only need to maintain
* the element stack, and return "anything goes" as allowable content:
*/
int ix = --mElemCount;
mElems[ix] = null;
if (ix < 1) {
return XMLValidator.CONTENT_ALLOW_ANY_TEXT;
}
DTDElement elem = mElems[ix-1];
return (elem == null) ? XMLValidator.CONTENT_ALLOW_ANY_TEXT :
mElems[ix-1].getAllowedContentIfSpace();
}
// base class implements these ok:
//public void validateText(String text, boolean lastTextSegment)
//public void validateText(char[] cbuf, int textStart, int textEnd, boolean lastTextSegment)
@Override
public void validationCompleted(boolean eod)
//throws XMLStreamException
{
// fine, great, nothing to do...
}
/*
///////////////////////////////////////
// Package methods, accessors
///////////////////////////////////////
*/
@Override
protected ElementIdMap getIdMap()
{
/* should never be called; for now let's throw an exception, if it
* turns out it does get called can/should return an empty immutable
* map or something
*/
ExceptionUtil.throwGenericInternal();
return null; // never gets here
}
}