blob: 530a50e8875a42850e9e349301ff6cf077147ed8 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xerces.impl.xs.traversers;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.validation.ValidationContext;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.impl.xs.SchemaGrammar;
import org.apache.xerces.impl.xs.SchemaSymbols;
import org.apache.xerces.impl.xs.XSAttributeDecl;
import org.apache.xerces.impl.xs.XSAttributeUse;
import org.apache.xerces.impl.xs.XSElementDecl;
import org.apache.xerces.impl.xs.XSTypeDecl;
import org.apache.xerces.xni.QName;
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.util.DOMUtil;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.impl.xs.util.XInt;
import org.apache.xerces.impl.validation.ValidationState;
import org.w3c.dom.Element;
/**
* The attribute declaration schema component traverser.
*
* <attribute
* default = string
* fixed = string
* form = (qualified | unqualified)
* id = ID
* name = NCName
* ref = QName
* type = QName
* use = (optional | prohibited | required) : optional
* {any attributes with non-schema namespace . . .}>
* Content: (annotation?, (simpleType?))
* </attribute>
*
* @author Sandy Gao, IBM
* @author Neeraj Bajaj, Sun Microsystems, inc.
* @version $Id$
*/
class XSDAttributeTraverser extends XSDAbstractTraverser {
public XSDAttributeTraverser (XSDHandler handler,
XSAttributeChecker gAttrCheck) {
super(handler, gAttrCheck);
}
protected XSAttributeUse traverseLocal(Element attrDecl,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar) {
// General Attribute Checking
Object[] attrValues = fAttrChecker.checkAttributes(attrDecl, false, schemaDoc);
String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT];
String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED];
String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME];
QName refAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_REF];
XInt useAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_USE];
// get 'attribute declaration'
XSAttributeDecl attribute = null;
if (attrDecl.getAttributeNode(SchemaSymbols.ATT_REF) != null) {
if (refAtt != null) {
attribute = (XSAttributeDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ATTRIBUTE_TYPE, refAtt);
Element child = DOMUtil.getFirstChildElement(attrDecl);
if(child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
traverseAnnotationDecl(child, attrValues, false, schemaDoc);
child = DOMUtil.getNextSiblingElement(child);
}
if (child != null) {
reportSchemaError("src-attribute.3.2", new Object[]{refAtt});
}
// for error reporting
nameAtt = refAtt.localpart;
} else {
attribute = null;
}
} else {
attribute = traverseNamedAttr(attrDecl, attrValues, schemaDoc, grammar, false);
}
// get 'value constraint'
short consType = XSAttributeDecl.NO_CONSTRAINT;
if (defaultAtt != null) {
consType = XSAttributeDecl.DEFAULT_VALUE;
} else if (fixedAtt != null) {
consType = XSAttributeDecl.FIXED_VALUE;
defaultAtt = fixedAtt;
fixedAtt = null;
}
XSAttributeUse attrUse = null;
if (attribute != null) {
attrUse = new XSAttributeUse();
attrUse.fAttrDecl = attribute;
attrUse.fUse = useAtt.shortValue();
attrUse.fConstraintType = consType;
if (defaultAtt != null) {
attrUse.fDefault = new ValidatedInfo();
attrUse.fDefault.normalizedValue = defaultAtt;
}
}
fAttrChecker.returnAttrArray(attrValues, schemaDoc);
//src-attribute
// 1 default and fixed must not both be present.
if (defaultAtt != null && fixedAtt != null) {
reportSchemaError("src-attribute.1", new Object[]{nameAtt});
}
// 2 If default and use are both present, use must have the actual value optional.
if (consType == XSAttributeDecl.DEFAULT_VALUE &&
useAtt != null && useAtt.intValue() != SchemaSymbols.USE_OPTIONAL) {
reportSchemaError("src-attribute.2", new Object[]{nameAtt});
}
// a-props-correct
if (defaultAtt != null && attrUse != null) {
// 2 if there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in String Valid (3.14.4).
fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport);
if (!checkDefaultValid(attrUse)) {
reportSchemaError ("a-props-correct.2", new Object[]{nameAtt, defaultAtt});
}
// 3 If the {type definition} is or is derived from ID then there must not be a {value constraint}.
if (attribute.fType.isIDType() ) {
reportSchemaError ("a-props-correct.3", new Object[]{nameAtt});
}
// check 3.5.6 constraint
// Attribute Use Correct
// 2 If the {attribute declaration} has a fixed {value constraint}, then if the attribute use itself has a {value constraint}, it must also be fixed and its value must match that of the {attribute declaration}'s {value constraint}.
if (attrUse.fAttrDecl.getConstraintType() == XSAttributeDecl.FIXED_VALUE &&
attrUse.fConstraintType != XSAttributeDecl.NO_CONSTRAINT) {
if (attrUse.fConstraintType != XSAttributeDecl.FIXED_VALUE ||
attrUse.fAttrDecl.fType.isEqual(attrUse.fAttrDecl.fDefault.actualValue,
attrUse.fDefault.actualValue)) {
reportSchemaError ("au-props-correct.2", new Object[]{nameAtt});
}
}
}
return attrUse;
}
protected XSAttributeDecl traverseGlobal(Element attrDecl,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar) {
// General Attribute Checking
Object[] attrValues = fAttrChecker.checkAttributes(attrDecl, true, schemaDoc);
XSAttributeDecl attribute = traverseNamedAttr(attrDecl, attrValues, schemaDoc, grammar, true);
fAttrChecker.returnAttrArray(attrValues, schemaDoc);
if (attribute != null)
attribute.setIsGlobal();
return attribute;
}
/**
* Traverse a globally declared attribute.
*
* @param attrDecl
* @param attrValues
* @param schemaDoc
* @param grammar
* @param isGlobal
* @return the attribute declaration index
*/
XSAttributeDecl traverseNamedAttr(Element attrDecl,
Object[] attrValues,
XSDocumentInfo schemaDoc,
SchemaGrammar grammar,
boolean isGlobal) {
String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT];
String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED];
XInt formAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FORM];
String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME];
QName typeAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_TYPE];
// Step 1: get declaration information
XSAttributeDecl attribute = new XSAttributeDecl();
// get 'name'
if (nameAtt != null)
attribute.fName = fSymbolTable.addSymbol(nameAtt);
// get 'target namespace'
if (isGlobal) {
attribute.fTargetNamespace = schemaDoc.fTargetNamespace;
}
else if (formAtt != null) {
if (formAtt.intValue() == SchemaSymbols.FORM_QUALIFIED)
attribute.fTargetNamespace = schemaDoc.fTargetNamespace;
else
attribute.fTargetNamespace = null;
} else if (schemaDoc.fAreLocalAttributesQualified) {
attribute.fTargetNamespace = schemaDoc.fTargetNamespace;
} else {
attribute.fTargetNamespace = null;
}
// get 'value constraint'
// for local named attribute, value constraint is absent
if (isGlobal) {
if (fixedAtt != null) {
attribute.fDefault = new ValidatedInfo();
attribute.fDefault.normalizedValue = fixedAtt;
attribute.setConstraintType(XSElementDecl.FIXED_VALUE);
} else if (defaultAtt != null) {
attribute.fDefault = new ValidatedInfo();
attribute.fDefault.normalizedValue = defaultAtt;
attribute.setConstraintType(XSElementDecl.DEFAULT_VALUE);
} else {
attribute.setConstraintType(XSElementDecl.NO_CONSTRAINT);
}
}
// get 'annotation'
Element child = DOMUtil.getFirstChildElement(attrDecl);
if(child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
traverseAnnotationDecl(child, attrValues, false, schemaDoc);
child = DOMUtil.getNextSiblingElement(child);
}
// get 'type definition'
XSSimpleType attrType = null;
boolean haveAnonType = false;
// Handle Anonymous type if there is one
if (child != null) {
String childName = DOMUtil.getLocalName(child);
if (childName.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
attrType = fSchemaHandler.fSimpleTypeTraverser.traverseLocal(child, schemaDoc, grammar);
haveAnonType = true;
child = DOMUtil.getNextSiblingElement(child);
}
}
// Handler type attribute
if (attrType == null && typeAtt != null) {
XSTypeDecl type = (XSTypeDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, typeAtt);
if (type != null && type.getXSType() == XSTypeDecl.SIMPLE_TYPE)
attrType = (XSSimpleType)type;
else
// REVISIT: what should be the error code here
reportGenericSchemaError("the type for attribute '"+nameAtt+"' must be a simpleType");
}
if (attrType == null) {
attrType = SchemaGrammar.fAnySimpleType;
}
attribute.fType = attrType;
// Step 2: register attribute decl to the grammar
if (isGlobal && nameAtt != null)
grammar.addGlobalAttributeDecl(attribute);
// Step 3: check against schema for schemas
// required attributes
if (nameAtt == null) {
if (isGlobal)
reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_ATTRIBUTE, SchemaSymbols.ATT_NAME});
else
reportSchemaError("src-attribute.3.1", null);
nameAtt = NO_NAME;
}
// element
if (child != null) {
reportSchemaError("s4s-elt-must-match", new Object[]{nameAtt, "(annotation?, (simpleType?))"});
}
// Step 4: check 3.2.3 constraints
// src-attribute
// 1 default and fixed must not both be present.
if (defaultAtt != null && fixedAtt != null) {
reportSchemaError("src-attribute.1", new Object[]{nameAtt});
}
// 2 If default and use are both present, use must have the actual value optional.
// This is checked in "traverse" method
// 3 If the item's parent is not <schema>, then all of the following must be true:
// 3.1 One of ref or name must be present, but not both.
// This is checked in XSAttributeChecker
// 3.2 If ref is present, then all of <simpleType>, form and type must be absent.
// Attributes are checked in XSAttributeChecker, elements are checked in "traverse" method
// 4 type and <simpleType> must not both be present.
if (haveAnonType && (typeAtt != null)) {
reportSchemaError( "src-attribute.4", new Object[]{nameAtt});
}
// Step 5: check 3.2.6 constraints
// check for NOTATION type
checkNotationType(nameAtt, attrType);
// a-props-correct
// 2 if there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in String Valid (3.14.4).
if (attribute.fDefault != null) {
fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport);
if (!checkDefaultValid(attribute)) {
reportSchemaError ("a-props-correct.2", new Object[]{nameAtt, defaultAtt});
}
}
// 3 If the {type definition} is or is derived from ID then there must not be a {value constraint}.
if (attribute.fDefault != null) {
if (attrType.isIDType() ) {
reportSchemaError ("a-props-correct.3", new Object[]{nameAtt});
}
}
// no-xmlns
// The {name} of an attribute declaration must not match xmlns.
if (nameAtt != null && nameAtt.equals(SchemaSymbols.XMLNS)) {
reportSchemaError("no-xmlns", null);
}
// no-xsi
// The {target namespace} of an attribute declaration, whether local or top-level, must not match http://www.w3.org/2001/XMLSchema-instance (unless it is one of the four built-in declarations given in the next section).
if (attribute.fTargetNamespace != null && attribute.fTargetNamespace.equals(SchemaSymbols.URI_XSI)) {
reportSchemaError("no-xsi", new Object[]{SchemaSymbols.URI_XSI});
}
return attribute;
}
// return whether the constraint value is valid for the given type
boolean checkDefaultValid(XSAttributeDecl attribute) {
boolean ret = true;
try {
//set the actual value
attribute.fType.validate(attribute.fDefault.normalizedValue, fValidationState, attribute.fDefault);
} catch (InvalidDatatypeValueException ide) {
ret = false;
}
return ret;
}
// return whether the constraint value is valid for the given type
boolean checkDefaultValid(XSAttributeUse attrUse) {
boolean ret = true;
try {
//set the actual value
attrUse.fAttrDecl.fType.validate(attrUse.fDefault.normalizedValue, fValidationState, attrUse.fDefault);
} catch (InvalidDatatypeValueException ide) {
ret = false;
}
return ret;
}
}