public static void checkFields(SchemaTypeImpl sType) {
if (sType.isSimpleType())
return;
XmlObject location = sType.getParseObject();
SchemaAttributeModel sAttrModel = sType.getAttributeModel();
if (sAttrModel != null)
{
SchemaLocalAttribute[] sAttrs = sAttrModel.getAttributes();
QName idAttr = null;
for (int i = 0; i < sAttrs.length; i++)
{
XmlObject attrLocation = ((SchemaLocalAttributeImpl)sAttrs[i])._parseObject;
if (XmlID.type.isAssignableFrom(sAttrs[i].getType()))
{
if (idAttr == null)
{
idAttr = sAttrs[i].getName();
}
else
{
StscState.get().error(XmlErrorCodes.ATTR_GROUP_PROPERTIES$TWO_IDS,
new Object[]{ QNameHelper.pretty(idAttr), sAttrs[i].getName() },
attrLocation != null ? attrLocation : location);
}
if (sAttrs[i].getDefaultText() != null)
{
StscState.get().error(XmlErrorCodes.ATTR_PROPERTIES$ID_FIXED_OR_DEFAULT,
null, attrLocation != null ? attrLocation : location);
}
}
else
{
String valueConstraint = sAttrs[i].getDefaultText();
if (valueConstraint != null)
{
try
{
XmlAnySimpleType val = sAttrs[i].getDefaultValue();
if (!val.validate())
throw new Exception();
SchemaPropertyImpl sProp = (SchemaPropertyImpl)sType.getAttributeProperty(sAttrs[i].getName());
if (sProp != null && sProp.getDefaultText() != null)
{
sProp.setDefaultValue(new XmlValueRef(val));
}
}
catch (Exception e)
{
// move to 'fixed' or 'default' attribute on the attribute definition
String constraintName = (sAttrs[i].isFixed() ? "fixed" : "default");
XmlObject constraintLocation = location;
if (attrLocation != null)
{
constraintLocation = attrLocation.selectAttribute("", constraintName);
if (constraintLocation == null)
constraintLocation = attrLocation;
}
StscState.get().error(XmlErrorCodes.ATTR_PROPERTIES$CONSTRAINT_VALID,
new Object[] { QNameHelper.pretty(sAttrs[i].getName()),
constraintName,
valueConstraint,
QNameHelper.pretty(sAttrs[i].getType().getName()) },
constraintLocation);
}
}
}
}
}
checkElementDefaults(sType.getContentModel(), location, sType);
}
The following code checks rule #5 of http://www.w3.org/TR/xmlschema-1/#coss-ct
as well as attribute + element default/fixed validity. |
public static boolean checkRestriction(SchemaTypeImpl sType) {
if (sType.getDerivationType() == SchemaType.DT_RESTRICTION && !sType.isSimpleType())
{
StscState state = StscState.get();
// we don't remember very precise line number information, but it's better than nothin.
XmlObject location = sType.getParseObject();
SchemaType baseType = sType.getBaseType();
if (baseType.isSimpleType())
{
state.error(XmlErrorCodes.SCHEMA_COMPLEX_TYPE$COMPLEX_CONTENT,
new Object[] { QNameHelper.pretty(baseType.getName()) },
location);
return false;
}
// 5 The appropriate case among the following must be true:
switch (sType.getContentType())
{
case SchemaType.SIMPLE_CONTENT:
// 5.1 If the {content type} of the complex type definition is a simple type definition, then one of the following must be true:
switch (baseType.getContentType())
{
case SchemaType.SIMPLE_CONTENT:
// 5.1.1 The {content type} of the {base type definition} must be a simple type definition of which the {content type} is a �valid restriction� as defined in Derivation Valid (Restriction, Simple) (�3.14.6).
SchemaType cType = sType.getContentBasedOnType();
if (cType != baseType)
{
// We have to check that the contentType is legally derived
// from the base simple type in the hierarchy
SchemaType bType = baseType;
while (bType != null && !bType.isSimpleType())
bType = bType.getContentBasedOnType();
if (bType != null && !bType.isAssignableFrom(cType))
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$SC_NOT_DERIVED,
null, location);
return false;
}
}
break;
case SchemaType.MIXED_CONTENT:
// 5.1.2 The {base type definition} must be mixed and have a particle which is �emptiable� as defined in Particle Emptiable (�3.9.6).
if (baseType.getContentModel() != null && !baseType.getContentModel().isSkippable())
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$SC_AND_MIXED_EMPTIABLE,
null, location);
return false;
}
break;
default:
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$SC_AND_SIMPLE_TYPE_OR_MIXED,
null, location);
return false;
}
break;
case SchemaType.EMPTY_CONTENT:
// 5.2 If the {content type} of the complex type itself is empty , then one of the following must be true:
switch (baseType.getContentType())
{
case SchemaType.EMPTY_CONTENT:
// 5.2.1 The {content type} of the {base type definition} must also be empty.
break;
case SchemaType.MIXED_CONTENT:
case SchemaType.ELEMENT_CONTENT:
// 5.2.2 The {content type} of the {base type definition} must be elementOnly or mixed and have a particle which is �emptiable� as defined in Particle Emptiable (�3.9.6).
if (baseType.getContentModel() != null && !baseType.getContentModel().isSkippable())
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$EMPTY_AND_ELEMENT_OR_MIXED_EMPTIABLE,
null, location);
return false;
}
break;
default:
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$EMPTY_AND_NOT_SIMPLE,
null, location);
return false;
}
break;
case SchemaType.MIXED_CONTENT:
// 5.3 If the {content type} of the {base type definition} is mixed...
if (baseType.getContentType() != SchemaType.MIXED_CONTENT)
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$ELEMENT_OR_MIXED_AND_MIXED,
null, location);
return false;
}
// FALLTHROUGH
case SchemaType.ELEMENT_CONTENT:
// 5.3 ... or the {content type} of the complex type definition itself is element-only,...
if (baseType.getContentType() == SchemaType.EMPTY_CONTENT)
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$ELEMENT_OR_MIXED_AND_EMPTY,
null, location);
return false;
}
if (baseType.getContentType() == SchemaType.SIMPLE_CONTENT)
{
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$ELEMENT_OR_MIXED_AND_SIMPLE,
null, location);
return false;
}
// 5.3 ... then the particle of the complex type definition itself must be a �valid restriction� of the particle of the {content type} of the {base type definition}
SchemaParticle baseModel = baseType.getContentModel();
SchemaParticle derivedModel = sType.getContentModel();
assert(baseModel != null && derivedModel != null);
if (baseModel == null || derivedModel == null)
{
XBeanDebug.logStackTrace("Null models that weren't caught by EMPTY_CONTENT: " + baseType + " (" + baseModel + "), " + sType + " (" + derivedModel + ")");
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$ELEMENT_OR_MIXED_AND_VALID, null, location);
return false;
}
// 5.3 ... as defined in Particle Valid (Restriction) (�3.9.6).
List errors = new ArrayList();
boolean isValid = isParticleValidRestriction(baseModel, derivedModel, errors, location);
if (!isValid)
{
// we only add the last error, because isParticleValidRestriction may add errors
// to the collection that it later changes its mind about, or it may (inadvertently)
// forget to describe an error into the collection....
if (errors.size() == 0)
state.error(XmlErrorCodes.COMPLEX_TYPE_RESTRICTION$ELEMENT_OR_MIXED_AND_VALID, null, location);
else
state.getErrorListener().add(errors.get(errors.size() - 1));
//state.getErrorListener().addAll(errors);
return false; // KHK: should return false, right?
}
}
}
return true;
}
The following code only checks rule #5 of http://www.w3.org/TR/xmlschema-1/#derivation-ok-restriction
(Everything else can and should be done in StscResolver, because we can give more detailed line # info there |
public static boolean isParticleValidRestriction(SchemaParticle baseModel,
SchemaParticle derivedModel,
Collection errors,
XmlObject context) {
boolean restrictionValid = false;
// 1 They are the same particle.
if (baseModel.equals(derivedModel)) {
restrictionValid = true;
} else {
// Implement table defined in schema spec on restrictions at:
// http://www.w3.org/TR/xmlschema-1/#cos-particle-restrict
switch (baseModel.getParticleType()) {
case SchemaParticle.ELEMENT:
switch (derivedModel.getParticleType()) {
case SchemaParticle.ELEMENT:
restrictionValid = nameAndTypeOK((SchemaLocalElement) baseModel, (SchemaLocalElement) derivedModel, errors, context);
break;
case SchemaParticle.WILDCARD:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.ALL:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.CHOICE:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.SEQUENCE:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Derived Type");
}
break;
case SchemaParticle.WILDCARD:
switch (derivedModel.getParticleType()) {
case SchemaParticle.ELEMENT:
restrictionValid = nsCompat(baseModel, (SchemaLocalElement) derivedModel, errors, context);
break;
case SchemaParticle.WILDCARD:
restrictionValid = nsSubset(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.ALL:
restrictionValid = nsRecurseCheckCardinality(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.CHOICE:
restrictionValid = nsRecurseCheckCardinality(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.SEQUENCE:
restrictionValid = nsRecurseCheckCardinality(baseModel, derivedModel, errors, context);
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Derived Type");
}
break;
case SchemaParticle.ALL:
switch (derivedModel.getParticleType()) {
case SchemaParticle.ELEMENT:
restrictionValid = recurseAsIfGroup(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.WILDCARD:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.ALL:
restrictionValid = recurse(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.CHOICE:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.SEQUENCE:
restrictionValid = recurseUnordered(baseModel, derivedModel, errors, context);
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Derived Type");
}
break;
case SchemaParticle.CHOICE:
switch (derivedModel.getParticleType()) {
case SchemaParticle.ELEMENT:
restrictionValid = recurseAsIfGroup(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.WILDCARD:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.ALL:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.CHOICE:
restrictionValid = recurseLax(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.SEQUENCE:
restrictionValid = mapAndSum(baseModel, derivedModel, errors, context);
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Derived Type");
}
break;
case SchemaParticle.SEQUENCE:
switch (derivedModel.getParticleType()) {
case SchemaParticle.ELEMENT:
restrictionValid = recurseAsIfGroup(baseModel, derivedModel, errors, context);
break;
case SchemaParticle.WILDCARD:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.ALL:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.CHOICE:
errors.add(XmlError.forObject(XmlErrorCodes.PARTICLE_RESTRICTION$INVALID_RESTRICTION,
new Object[] { printParticle(baseModel), printParticle(derivedModel) }, context));
restrictionValid = false;
break;
case SchemaParticle.SEQUENCE:
restrictionValid = recurse(baseModel, derivedModel, errors, context);
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Derived Type");
}
break;
default:
assert false : XBeanDebug.logStackTrace("Unknown schema type for Base Type");
}
}
return restrictionValid;
}
This function takes in two schema particle types, a baseModel, and a derived model and returns true if the
derivedModel can be egitimately be used for restriction. Errors are put into the errors collections. |