blob: 355881edc84602697938cb780fb1ee22e577752d [file] [log] [blame]
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Copyright 2001-2005 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 com.sun.org.apache.xerces.internal.impl.xs.traversers;
import java.util.ArrayList;
import java.util.Vector;
import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeFacetException;
import com.sun.org.apache.xerces.internal.impl.dv.SchemaDVFactory;
import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
import com.sun.org.apache.xerces.internal.impl.dv.xs.SchemaDVFactoryImpl;
import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
import com.sun.org.apache.xerces.internal.util.DOMUtil;
import com.sun.org.apache.xerces.internal.xni.QName;
import com.sun.org.apache.xerces.internal.xs.XSConstants;
import com.sun.org.apache.xerces.internal.xs.XSObjectList;
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
import org.w3c.dom.Element;
/**
* The simple type definition schema component traverser.
*
* <simpleType
* final = (#all | (list | union | restriction))
* id = ID
* name = NCName
* {any attributes with non-schema namespace . . .}>
* Content: (annotation?, (restriction | list | union))
* </simpleType>
*
* <restriction
* base = QName
* id = ID
* {any attributes with non-schema namespace . . .}>
* Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*))
* </restriction>
*
* <list
* id = ID
* itemType = QName
* {any attributes with non-schema namespace . . .}>
* Content: (annotation?, (simpleType?))
* </list>
*
* <union
* id = ID
* memberTypes = List of QName
* {any attributes with non-schema namespace . . .}>
* Content: (annotation?, (simpleType*))
* </union>
*
* @xerces.internal
*
* @author Elena Litani, IBM
* @author Neeraj Bajaj, Sun Microsystems, Inc.
* @author Sandy Gao, IBM
*
* @version $Id: XSDSimpleTypeTraverser.java,v 1.7 2010-11-01 04:40:02 joehw Exp $
*/
class XSDSimpleTypeTraverser extends XSDAbstractTraverser {
// whether the type being parsed is a S4S built-in type.
private boolean fIsBuiltIn = false;
XSDSimpleTypeTraverser (XSDHandler handler,
XSAttributeChecker gAttrCheck) {
super(handler, gAttrCheck);
}
//return qualified name of simpleType or empty string if error occured
XSSimpleType traverseGlobal(Element elmNode,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar) {
// General Attribute Checking
Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc);
String nameAtt = (String)attrValues[XSAttributeChecker.ATTIDX_NAME];
if (nameAtt == null) {
attrValues[XSAttributeChecker.ATTIDX_NAME] = NO_NAME;
}
XSSimpleType type = traverseSimpleTypeDecl(elmNode, attrValues, schemaDoc, grammar);
fAttrChecker.returnAttrArray(attrValues, schemaDoc);
// if it's a global type without a name, return null
if (nameAtt == null) {
reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, SchemaSymbols.ATT_NAME}, elmNode);
type = null;
}
// don't add global components without name to the grammar
if (type != null) {
if (grammar.getGlobalTypeDecl(type.getName()) == null) {
grammar.addGlobalSimpleTypeDecl(type);
}
// also add it to extended map
final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc);
final XSTypeDefinition type2 = grammar.getGlobalTypeDecl(type.getName(), loc);
if (type2 == null) {
grammar.addGlobalSimpleTypeDecl(type, loc);
}
// handle duplicates
if (fSchemaHandler.fTolerateDuplicates) {
if (type2 != null) {
if (type2 instanceof XSSimpleType) {
type = (XSSimpleType) type2;
}
}
fSchemaHandler.addGlobalTypeDecl(type);
}
}
return type;
}
XSSimpleType traverseLocal(Element elmNode,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar) {
// General Attribute Checking
Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc);
String name = genAnonTypeName(elmNode);
XSSimpleType type = getSimpleType (name, elmNode, attrValues, schemaDoc, grammar);
if (type instanceof XSSimpleTypeDecl) {
((XSSimpleTypeDecl)type).setAnonymous(true);
}
fAttrChecker.returnAttrArray(attrValues, schemaDoc);
return type;
}
private XSSimpleType traverseSimpleTypeDecl(Element simpleTypeDecl,
Object[] attrValues,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar) {
// get name and final values
String name = (String)attrValues[XSAttributeChecker.ATTIDX_NAME];
return getSimpleType(name, simpleTypeDecl, attrValues, schemaDoc, grammar);
}
/*
* Generate a name for an anonymous type
*/
private String genAnonTypeName(Element simpleTypeDecl) {
// Generate a unique name for the anonymous type by concatenating together the
// names of parent nodes
// The name is quite good for debugging/error purposes, but we may want to
// revisit how this is done for performance reasons (LM).
StringBuffer typeName = new StringBuffer("#AnonType_");
Element node = DOMUtil.getParent(simpleTypeDecl);
while (node != null && (node != DOMUtil.getRoot(DOMUtil.getDocument(node)))) {
typeName.append(node.getAttribute(SchemaSymbols.ATT_NAME));
node = DOMUtil.getParent(node);
}
return typeName.toString();
}
/**
* @param name
* @param simpleTypeDecl
* @param attrValues
* @param schemaDoc
* @param grammar
* @return
*/
private XSSimpleType getSimpleType(String name, Element simpleTypeDecl, Object[] attrValues, XSDocumentInfo schemaDoc, SchemaGrammar grammar) {
XInt finalAttr = (XInt)attrValues[XSAttributeChecker.ATTIDX_FINAL];
int finalProperty = finalAttr == null ? schemaDoc.fFinalDefault : finalAttr.intValue();
// annotation?,(list|restriction|union)
Element child = DOMUtil.getFirstChildElement(simpleTypeDecl);
XSAnnotationImpl [] annotations = null;
if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
XSAnnotationImpl annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc);
if (annotation != null)
annotations = new XSAnnotationImpl [] {annotation};
child = DOMUtil.getNextSiblingElement(child);
}
else {
String text = DOMUtil.getSyntheticAnnotation(simpleTypeDecl);
if (text != null) {
XSAnnotationImpl annotation = traverseSyntheticAnnotation(simpleTypeDecl, text, attrValues, false, schemaDoc);
annotations = new XSAnnotationImpl[] {annotation};
}
}
// (list|restriction|union)
if (child == null) {
reportSchemaError("s4s-elt-must-match.2", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))"}, simpleTypeDecl);
return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION);
}
// derivation type: restriction/list/union
String varietyProperty = DOMUtil.getLocalName(child);
short refType = XSConstants.DERIVATION_RESTRICTION;
boolean restriction = false, list = false, union = false;
if (varietyProperty.equals(SchemaSymbols.ELT_RESTRICTION)) {
refType = XSConstants.DERIVATION_RESTRICTION;
restriction = true;
}
else if (varietyProperty.equals(SchemaSymbols.ELT_LIST)) {
refType = XSConstants.DERIVATION_LIST;
list = true;
}
else if (varietyProperty.equals(SchemaSymbols.ELT_UNION)) {
refType = XSConstants.DERIVATION_UNION;
union = true;
}
else {
reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", varietyProperty}, simpleTypeDecl);
return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION);
}
// nothing should follow this element
Element nextChild = DOMUtil.getNextSiblingElement(child);
if (nextChild != null) {
reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", DOMUtil.getLocalName(nextChild)}, nextChild);
}
// General Attribute Checking: get base/item/member types
Object[] contentAttrs = fAttrChecker.checkAttributes(child, false, schemaDoc);
QName baseTypeName = (QName)contentAttrs[restriction ?
XSAttributeChecker.ATTIDX_BASE :
XSAttributeChecker.ATTIDX_ITEMTYPE];
Vector memberTypes = (Vector)contentAttrs[XSAttributeChecker.ATTIDX_MEMBERTYPES];
//content = {annotation?,simpleType?...}
Element content = DOMUtil.getFirstChildElement(child);
//check content (annotation?, ...)
if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_ANNOTATION)) {
XSAnnotationImpl annotation = traverseAnnotationDecl(content, contentAttrs, false, schemaDoc);
if (annotation != null ) {
if(annotations == null) {
annotations = new XSAnnotationImpl [] {annotation};
}
else {
XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2];
tempArray[0] = annotations[0];
annotations = tempArray;
annotations[1] = annotation;
}
}
content = DOMUtil.getNextSiblingElement(content);
}
else {
String text = DOMUtil.getSyntheticAnnotation(child);
if (text != null) {
XSAnnotationImpl annotation = traverseSyntheticAnnotation(child, text, contentAttrs, false, schemaDoc);
if (annotations == null) {
annotations = new XSAnnotationImpl [] {annotation};
}
else {
XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2];
tempArray[0] = annotations[0];
annotations = tempArray;
annotations[1] = annotation;
}
}
}
// get base type from "base" attribute
XSSimpleType baseValidator = null;
if ((restriction || list) && baseTypeName != null) {
baseValidator = findDTValidator(child, name, baseTypeName, refType, schemaDoc);
// if its the built-in type, return null from here
if (baseValidator == null && fIsBuiltIn) {
fIsBuiltIn = false;
return null;
}
}
// get types from "memberTypes" attribute
ArrayList dTValidators = null;
XSSimpleType dv = null;
XSObjectList dvs;
if (union && memberTypes != null && memberTypes.size() > 0) {
int size = memberTypes.size();
dTValidators = new ArrayList(size);
// for each qname in the list
for (int i = 0; i < size; i++) {
// get the type decl
dv = findDTValidator(child, name, (QName)memberTypes.elementAt(i),
XSConstants.DERIVATION_UNION, schemaDoc);
if (dv != null) {
// if it's a union, expand it
if (dv.getVariety() == XSSimpleType.VARIETY_UNION) {
dvs = dv.getMemberTypes();
for (int j = 0; j < dvs.getLength(); j++)
dTValidators.add(dvs.item(j));
} else {
dTValidators.add(dv);
}
}
}
}
// check if there is a child "simpleType"
if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE)) {
if (restriction || list) {
// it's an error for both "base" and "simpleType" to appear
if (baseTypeName != null) {
reportSchemaError(list ? "src-simple-type.3.a" : "src-simple-type.2.a", null, content);
}
if (baseValidator == null) {
// traverse this child to get the base type
baseValidator = traverseLocal(content, schemaDoc, grammar);
}
// get the next element
content = DOMUtil.getNextSiblingElement(content);
}
else if (union) {
if (dTValidators == null) {
dTValidators = new ArrayList(2);
}
do {
// traverse this child to get the member type
dv = traverseLocal(content, schemaDoc, grammar);
if (dv != null) {
// if it's a union, expand it
if (dv.getVariety() == XSSimpleType.VARIETY_UNION) {
dvs = dv.getMemberTypes();
for (int j = 0; j < dvs.getLength(); j++) {
dTValidators.add(dvs.item(j));
}
}
else {
dTValidators.add(dv);
}
}
// get the next element
content = DOMUtil.getNextSiblingElement(content);
} while (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE));
}
}
else if ((restriction || list) && baseTypeName == null) {
// it's an error if neither "base/itemType" nor "simpleType" appears
reportSchemaError(list ? "src-simple-type.3.b" : "src-simple-type.2.b", null, child);
}
else if (union && (memberTypes == null || memberTypes.size() == 0)) {
// it's an error if "memberTypes" is empty and no "simpleType" appears
reportSchemaError("src-union-memberTypes-or-simpleTypes", null, child);
}
// error finding "base" or error traversing "simpleType".
// don't need to report an error, since some error has been reported.
if ((restriction || list) && baseValidator == null) {
fAttrChecker.returnAttrArray(contentAttrs, schemaDoc);
return errorType(name, schemaDoc.fTargetNamespace,
restriction ? XSConstants.DERIVATION_RESTRICTION : XSConstants.DERIVATION_LIST);
}
// error finding "memberTypes" or error traversing "simpleType".
// don't need to report an error, since some error has been reported.
if (union && (dTValidators == null || dTValidators.size() == 0)) {
fAttrChecker.returnAttrArray(contentAttrs, schemaDoc);
return errorType(name, schemaDoc.fTargetNamespace,
XSConstants.DERIVATION_UNION);
}
// item type of list types can't have list content
if (list && isListDatatype(baseValidator)) {
reportSchemaError("cos-st-restricts.2.1", new Object[]{name, baseValidator.getName()}, child);
fAttrChecker.returnAttrArray(contentAttrs, schemaDoc);
return errorType(name, schemaDoc.fTargetNamespace,
XSConstants.DERIVATION_LIST);
}
// create the simple type based on the "base" type
XSSimpleType newDecl = null;
if (restriction) {
newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator,
annotations == null? null : new XSObjectListImpl(annotations, annotations.length));
}
else if (list) {
newDecl = fSchemaHandler.fDVFactory.createTypeList(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator,
annotations == null? null : new XSObjectListImpl(annotations, annotations.length));
}
else if (union) {
XSSimpleType[] memberDecls = (XSSimpleType[]) dTValidators.toArray(new XSSimpleType[dTValidators.size()]);
newDecl = fSchemaHandler.fDVFactory.createTypeUnion(name, schemaDoc.fTargetNamespace, (short)finalProperty, memberDecls,
annotations == null? null : new XSObjectListImpl(annotations, annotations.length));
}
// now traverse facets, if it's derived by restriction
if (restriction && content != null) {
FacetInfo fi = traverseFacets(content, baseValidator, schemaDoc);
content = fi.nodeAfterFacets;
try {
fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport);
newDecl.applyFacets(fi.facetdata, fi.fPresentFacets, fi.fFixedFacets, fValidationState);
} catch (InvalidDatatypeFacetException ex) {
reportSchemaError(ex.getKey(), ex.getArgs(), child);
// Recreate the type, ignoring the facets
newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator,
annotations == null? null : new XSObjectListImpl(annotations, annotations.length));
}
}
// no element should appear after this point
if (content != null) {
if (restriction) {
reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_RESTRICTION, "(annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*))", DOMUtil.getLocalName(content)}, content);
}
else if (list) {
reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_LIST, "(annotation?, (simpleType?))", DOMUtil.getLocalName(content)}, content);
}
else if (union) {
reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_UNION, "(annotation?, (simpleType*))", DOMUtil.getLocalName(content)}, content);
}
}
fAttrChecker.returnAttrArray(contentAttrs, schemaDoc);
// return the new type
return newDecl;
}
//@param: elm - top element
//@param: baseTypeStr - type (base/itemType/memberTypes)
//@param: baseRefContext: whether the caller is using this type as a base for restriction, union or list
//return XSSimpleType available for the baseTypeStr, null if not found or disallowed.
// also throws an error if the base type won't allow itself to be used in this context.
// REVISIT: can this code be re-used?
private XSSimpleType findDTValidator(Element elm, String refName,
QName baseTypeStr, short baseRefContext,
XSDocumentInfo schemaDoc) {
if (baseTypeStr == null)
return null;
XSTypeDefinition baseType = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, baseTypeStr, elm);
if (baseType == null) {
return null;
}
if (baseType.getTypeCategory() != XSTypeDefinition.SIMPLE_TYPE) {
reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm);
return null;
}
// if it's a complex type, or if its restriction of anySimpleType
if (baseType == SchemaGrammar.fAnySimpleType &&
baseRefContext == XSConstants.DERIVATION_RESTRICTION) {
// if the base type is anySimpleType and the current type is
// a S4S built-in type, return null. (not an error).
if (checkBuiltIn(refName, schemaDoc.fTargetNamespace)) {
return null;
}
reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm);
return null;
}
if ((baseType.getFinal() & baseRefContext) != 0) {
if (baseRefContext == XSConstants.DERIVATION_RESTRICTION) {
reportSchemaError("st-props-correct.3", new Object[]{refName, baseTypeStr.rawname}, elm);
}
else if (baseRefContext == XSConstants.DERIVATION_LIST) {
reportSchemaError("cos-st-restricts.2.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm);
}
else if (baseRefContext == XSConstants.DERIVATION_UNION) {
reportSchemaError("cos-st-restricts.3.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm);
}
return null;
}
return (XSSimpleType)baseType;
}
// check whethe the type denoted by the name and namespace is a S4S
// built-in type. update fIsBuiltIn at the same time.
private final boolean checkBuiltIn(String name, String namespace) {
if (namespace != SchemaSymbols.URI_SCHEMAFORSCHEMA)
return false;
if (SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(name) != null)
fIsBuiltIn = true;
return fIsBuiltIn;
}
// find if a datatype validator is a list or has list datatype member.
private boolean isListDatatype(XSSimpleType validator) {
if (validator.getVariety() == XSSimpleType.VARIETY_LIST)
return true;
if (validator.getVariety() == XSSimpleType.VARIETY_UNION) {
XSObjectList temp = validator.getMemberTypes();
for (int i = 0; i < temp.getLength(); i++) {
if (((XSSimpleType)temp.item(i)).getVariety() == XSSimpleType.VARIETY_LIST) {
return true;
}
}
}
return false;
}//isListDatatype(XSSimpleTypeDecl):boolean
private XSSimpleType errorType(String name, String namespace, short refType) {
XSSimpleType stringType = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getTypeDefinition("string");
switch (refType) {
case XSConstants.DERIVATION_RESTRICTION:
return fSchemaHandler.fDVFactory.createTypeRestriction(name, namespace, (short)0,
stringType, null);
case XSConstants.DERIVATION_LIST:
return fSchemaHandler.fDVFactory.createTypeList(name, namespace, (short)0,
stringType, null);
case XSConstants.DERIVATION_UNION:
return fSchemaHandler.fDVFactory.createTypeUnion(name, namespace, (short)0,
new XSSimpleType[]{stringType}, null);
}
return null;
}
}//class XSDSimpleTypeTraverser