blob: 6e27651bb7d9f3648a1957e0b4618498916aad80 [file] [log] [blame]
/* Copyright 2004 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 org.apache.xmlbeans.impl.schema;
import java.util.*;
import java.util.List;
import java.math.BigInteger;
import org.w3.x2001.xmlSchema.*;
import org.w3.x2001.xmlSchema.SchemaDocument.Schema;
import org.w3.x2001.xmlSchema.RedefineDocument.Redefine;
import org.apache.xmlbeans.impl.common.XmlErrorContext;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.common.XMLChar;
import org.apache.xmlbeans.impl.common.XPath;
import org.apache.xmlbeans.impl.values.XmlIntegerImpl;
import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException;
import org.apache.xmlbeans.impl.values.NamespaceContext;
import org.apache.xmlbeans.impl.regex.RegularExpression;
import org.apache.xmlbeans.soap.SOAPArrayType;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.SchemaGlobalElement;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaParticle;
import org.apache.xmlbeans.QNameSet;
import org.apache.xmlbeans.QNameSetBuilder;
import org.apache.xmlbeans.SchemaIdentityConstraint;
import org.apache.xmlbeans.SchemaAttributeModel;
import org.apache.xmlbeans.SchemaLocalAttribute;
import org.apache.xmlbeans.SchemaGlobalAttribute;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlInteger;
import org.apache.xmlbeans.XmlBeans;
import javax.xml.namespace.QName;
public class StscTranslator
{
private static final QName WSDL_ARRAYTYPE_NAME =
QNameHelper.forLNS("arrayType", "http://schemas.xmlsoap.org/wsdl/");
public static void addAllDefinitions(StscImporter.SchemaToProcess[] schemasAndChameleons)
{
for (int i = 0; i < schemasAndChameleons.length; i++)
{
addAllDefinitions(
schemasAndChameleons[i].getSchema(),
schemasAndChameleons[i].getChameleonNamespace(),
schemasAndChameleons[i].getRedefine());
}
}
public static void addAllDefinitions(Schema schema, String givenTargetNamespace, Redefine redefine)
{
StscState state = StscState.get();
// quick check for a few unsupported features
if (schema.sizeOfNotationArray() > 0)
{
state.warning("Schema <notation> is not yet supported for this release.", XmlErrorContext.UNSUPPORTED_FEATURE, schema.getNotationArray(0));
}
// figure namespace (taking into account chameleons)
String targetNamespace = schema.getTargetNamespace();
boolean chameleon = false;
if (givenTargetNamespace != null && targetNamespace == null)
{
targetNamespace = givenTargetNamespace;
chameleon = true;
}
if (targetNamespace == null)
targetNamespace = "";
state.addNamespace(targetNamespace);
// make a note of all redefinitions
RedefinitionHolder redefinitions = new RedefinitionHolder(redefine);
TopLevelComplexType[] complexTypes = schema.getComplexTypeArray();
for (int i = 0; i < complexTypes.length; i++)
{
TopLevelComplexType redef = redefinitions.redefineComplexType(complexTypes[i].getName());
state.addGlobalType(translateGlobalComplexType(complexTypes[i], targetNamespace, chameleon, false), redef != null);
if (redef != null)
state.addGlobalType(translateGlobalComplexType(redef, targetNamespace, chameleon, true), false);
}
TopLevelSimpleType[] simpleTypes = schema.getSimpleTypeArray();
for (int i = 0; i < simpleTypes.length; i++)
{
TopLevelSimpleType redef = redefinitions.redefineSimpleType(simpleTypes[i].getName());
state.addGlobalType(translateGlobalSimpleType(simpleTypes[i], targetNamespace, chameleon, false), redef != null);
if (redef != null)
state.addGlobalType(translateGlobalSimpleType(redef, targetNamespace, chameleon, true), false);
}
TopLevelElement[] elements = schema.getElementArray();
for (int i = 0; i < elements.length; i++)
{
TopLevelElement element = elements[i];
state.addDocumentType(translateDocumentType(element, targetNamespace, chameleon), QNameHelper.forLNS(element.getName(), targetNamespace));
}
TopLevelAttribute[] attributes = schema.getAttributeArray();
for (int i = 0; i < attributes.length ; i++)
{
TopLevelAttribute attribute = attributes[i];
state.addAttributeType(translateAttributeType(attribute, targetNamespace, chameleon), QNameHelper.forLNS(attribute.getName(), targetNamespace));
}
NamedGroup[] modelgroups = schema.getGroupArray();
for (int i = 0; i < modelgroups.length; i++)
{
NamedGroup redef = redefinitions.redefineModelGroup(modelgroups[i].getName());
state.addModelGroup(translateModelGroup(modelgroups[i], targetNamespace, chameleon, false), redef != null);
if (redef != null)
state.addModelGroup(translateModelGroup(redef, targetNamespace, chameleon, true), false);
}
NamedAttributeGroup[] attrgroups = schema.getAttributeGroupArray();
for (int i = 0; i < attrgroups.length; i++)
{
NamedAttributeGroup redef = redefinitions.redefineAttributeGroup(attrgroups[i].getName());
state.addAttributeGroup(translateAttributeGroup(attrgroups[i], targetNamespace, chameleon, false), redef != null);
if (redef != null)
state.addAttributeGroup(translateAttributeGroup(redef, targetNamespace, chameleon, true), false);
}
redefinitions.complainAboutMissingDefinitions();
}
private static class RedefinitionHolder
{
// record redefinitions
private Map stRedefinitions = Collections.EMPTY_MAP;
private Map ctRedefinitions = Collections.EMPTY_MAP;
private Map agRedefinitions = Collections.EMPTY_MAP;
private Map mgRedefinitions = Collections.EMPTY_MAP;
private String schemaLocation = "";
// first build set of redefined components
RedefinitionHolder(Redefine redefine)
{
if (redefine != null)
{
StscState state = StscState.get();
stRedefinitions = new HashMap();
ctRedefinitions = new HashMap();
agRedefinitions = new HashMap();
mgRedefinitions = new HashMap();
if (redefine.getSchemaLocation() != null)
schemaLocation = redefine.getSchemaLocation();
TopLevelComplexType[] complexTypes = redefine.getComplexTypeArray();
for (int i = 0; i < complexTypes.length; i++)
{
if (complexTypes[i].getName() != null)
{
if (ctRedefinitions.containsKey(complexTypes[i].getName()))
state.error("Duplicate type redefinition: " + complexTypes[i].getName(), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null);
else
ctRedefinitions.put(complexTypes[i].getName(), complexTypes[i]);
}
}
TopLevelSimpleType[] simpleTypes = redefine.getSimpleTypeArray();
for (int i = 0; i < simpleTypes.length; i++)
{
if (simpleTypes[i].getName() != null)
{
if (stRedefinitions.containsKey(simpleTypes[i].getName()))
state.error("Duplicate type redefinition: " + simpleTypes[i].getName(), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null);
else
stRedefinitions.put(simpleTypes[i].getName(), simpleTypes[i]);
}
}
NamedGroup[] modelgroups = redefine.getGroupArray();
for (int i = 0; i < modelgroups.length; i++)
{
if (modelgroups[i].getName() != null)
{
if (mgRedefinitions.containsKey(modelgroups[i].getName()))
state.error("Duplicate type redefinition: " + modelgroups[i].getName(), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null);
else
mgRedefinitions.put(modelgroups[i].getName(), modelgroups[i]);
}
}
NamedAttributeGroup[] attrgroups = redefine.getAttributeGroupArray();
for (int i = 0; i < attrgroups.length; i++)
{
if (attrgroups[i].getName() != null)
{
if (agRedefinitions.containsKey(attrgroups[i].getName()))
state.error("Duplicate type redefinition: " + attrgroups[i].getName(), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null);
else
agRedefinitions.put(attrgroups[i].getName(), attrgroups[i]);
}
}
}
}
public TopLevelSimpleType redefineSimpleType(String name)
{
if (name == null || !stRedefinitions.containsKey(name))
return null;
return (TopLevelSimpleType)stRedefinitions.remove(name);
}
public TopLevelComplexType redefineComplexType(String name)
{
if (name == null || !ctRedefinitions.containsKey(name))
return null;
return (TopLevelComplexType)ctRedefinitions.remove(name);
}
public NamedGroup redefineModelGroup(String name)
{
if (name == null || !mgRedefinitions.containsKey(name))
return null;
return (NamedGroup)mgRedefinitions.remove(name);
}
public NamedAttributeGroup redefineAttributeGroup(String name)
{
if (name == null || !agRedefinitions.containsKey(name))
return null;
return (NamedAttributeGroup)agRedefinitions.remove(name);
}
public void complainAboutMissingDefinitions()
{
if (stRedefinitions.isEmpty() && ctRedefinitions.isEmpty() &&
agRedefinitions.isEmpty() && mgRedefinitions.isEmpty())
return;
StscState state = StscState.get();
for (Iterator i = stRedefinitions.keySet().iterator(); i.hasNext(); )
{
QName name = (QName)i.next();
state.error("Redefined simple type " + QNameHelper.pretty(name) + " not found in " + schemaLocation, XmlErrorContext.GENERIC_ERROR, (XmlObject)stRedefinitions.get(name));
}
for (Iterator i = ctRedefinitions.keySet().iterator(); i.hasNext(); )
{
QName name = (QName)i.next();
state.error("Redefined complex type " + QNameHelper.pretty(name) + " not found in " + schemaLocation, XmlErrorContext.GENERIC_ERROR, (XmlObject)ctRedefinitions.get(name));
}
for (Iterator i = agRedefinitions.keySet().iterator(); i.hasNext(); )
{
QName name = (QName)i.next();
state.error("Redefined attribute group " + QNameHelper.pretty(name) + " not found in " + schemaLocation, XmlErrorContext.GENERIC_ERROR, (XmlObject)agRedefinitions.get(name));
}
for (Iterator i = mgRedefinitions.keySet().iterator(); i.hasNext(); )
{
QName name = (QName)i.next();
state.error("Redefined model group " + QNameHelper.pretty(name) + " not found in " + schemaLocation, XmlErrorContext.GENERIC_ERROR, (XmlObject)mgRedefinitions.get(name));
}
}
}
private static String findFilename(XmlObject xobj)
{
return StscState.get().sourceNameForUri(xobj.documentProperties().getSourceName());
}
private static SchemaTypeImpl translateDocumentType ( TopLevelElement xsdType, String targetNamespace, boolean chameleon )
{
SchemaTypeImpl sType = new SchemaTypeImpl( StscState.get().sts() );
sType.setDocumentType(true);
sType.setParseContext( xsdType, targetNamespace, chameleon, false);
sType.setFilename( findFilename( xsdType ) );
return sType;
}
private static SchemaTypeImpl translateAttributeType ( TopLevelAttribute xsdType, String targetNamespace, boolean chameleon )
{
SchemaTypeImpl sType = new SchemaTypeImpl( StscState.get().sts() );
sType.setAttributeType(true);
sType.setParseContext( xsdType, targetNamespace, chameleon, false);
sType.setFilename( findFilename( xsdType ) );
return sType;
}
private static SchemaTypeImpl translateGlobalComplexType(TopLevelComplexType xsdType, String targetNamespace, boolean chameleon, boolean redefinition)
{
StscState state = StscState.get();
String localname = xsdType.getName();
if (localname == null)
{
state.error("Global type missing a name", XmlErrorContext.GLOBAL_TYPE_MISSING_NAME, xsdType);
// recovery: ignore unnamed types.
return null;
}
if (!XMLChar.isValidNCName(localname))
{
state.error("Invalid type name \"" + localname + "\"", XmlErrorContext.INVALID_NAME, xsdType.xgetName());
// recovery: let the name go through anyway.
}
QName name = QNameHelper.forLNS(localname, targetNamespace);
if (isReservedTypeName(name))
{
state.warning("Skipping definition of built-in type " + QNameHelper.pretty(name), XmlErrorContext.RESERVED_TYPE_NAME, xsdType);
return null;
}
// System.err.println("Recording type " + QNameHelper.pretty(name));
SchemaTypeImpl sType = new SchemaTypeImpl(state.sts());
sType.setParseContext(xsdType, targetNamespace, chameleon, redefinition);
sType.setFilename(findFilename(xsdType));
sType.setName(QNameHelper.forLNS(localname, targetNamespace));
return sType;
}
private static SchemaTypeImpl translateGlobalSimpleType(TopLevelSimpleType xsdType, String targetNamespace, boolean chameleon, boolean redefinition)
{
StscState state = StscState.get();
String localname = xsdType.getName();
if (localname == null)
{
state.error("Global type missing a name", XmlErrorContext.GLOBAL_TYPE_MISSING_NAME, xsdType);
// recovery: ignore unnamed types.
return null;
}
if (!XMLChar.isValidNCName(localname))
{
state.error("Invalid type name \"" + localname + "\"", XmlErrorContext.INVALID_NAME, xsdType.xgetName());
// recovery: let the name go through anyway.
}
QName name = QNameHelper.forLNS(localname, targetNamespace);
if (isReservedTypeName(name))
{
state.warning("Skipping definition of built-in type " + QNameHelper.pretty(name), XmlErrorContext.RESERVED_TYPE_NAME, xsdType);
return null;
}
// System.err.println("Recording type " + QNameHelper.pretty(name));
SchemaTypeImpl sType = new SchemaTypeImpl(state.sts());
sType.setSimpleType(true);
sType.setParseContext(xsdType, targetNamespace, chameleon, redefinition);
sType.setFilename(findFilename(xsdType));
sType.setName(name);
return sType;
}
static FormChoice findElementFormDefault(XmlObject obj)
{
XmlCursor cur = obj.newCursor();
while (cur.getObject().schemaType() != Schema.type)
if (!cur.toParent())
return null;
return ((Schema)cur.getObject()).xgetElementFormDefault();
}
public static boolean uriMatch(String s1, String s2)
{
if (s1 == null)
return s2 == null || s2.equals("");
if (s2 == null)
return s1.equals("");
return s1.equals(s2);
}
public static void copyGlobalElementToLocalElement(SchemaGlobalElement referenced, SchemaLocalElementImpl target )
{
target.setNameAndTypeRef(referenced.getName(), referenced.getType().getRef());
target.setNillable(referenced.isNillable());
target.setDefault(referenced.getDefaultText(), referenced.isFixed(), ((SchemaGlobalElementImpl)referenced).getParseObject());
target.setIdentityConstraints(((SchemaLocalElementImpl)referenced).getIdentityConstraintRefs());
target.setBlock(referenced.blockExtension(), referenced.blockRestriction(), referenced.blockSubstitution());
target.setAbstract(referenced.isAbstract());
target.setTransitionRules(((SchemaParticle)referenced).acceptedStartNames(),
((SchemaParticle)referenced).isSkippable());
}
public static void copyGlobalAttributeToLocalAttribute(SchemaGlobalAttributeImpl referenced, SchemaLocalAttributeImpl target )
{
target.init(
referenced.getName(), referenced.getTypeRef(), referenced.getUse(),
referenced.getDefaultText(),
referenced.getParseObject(), referenced._defaultValue,
referenced.isFixed(),
referenced.getWSDLArrayType() );
}
/**
* Translates a local or global schema element.
*/
// check rule 3.3.3
// http://www.w3c.org/TR/#section-Constraints-on-XML-Representations-of-Element-Declarations
public static SchemaLocalElementImpl translateElement(
Element xsdElt, String targetNamespace, boolean chameleon,
List anonymousTypes, SchemaType outerType)
{
StscState state = StscState.get();
SchemaTypeImpl sgHead = null;
// translate sg head
if (xsdElt.isSetSubstitutionGroup())
{
sgHead = state.findDocumentType(xsdElt.getSubstitutionGroup(),
((SchemaTypeImpl)outerType).getChameleonNamespace());
if (sgHead != null)
StscResolver.resolveType(sgHead);
}
String name = xsdElt.getName();
QName ref = xsdElt.getRef();
if (ref != null && name != null)
{
// if (name.equals(ref.getLocalPart()) && uriMatch(targetNamespace, ref.getNamespaceURI()))
// state.warning("Element " + name + " specifies both a ref and a name", XmlErrorContext.ELEMENT_EXTRA_REF, xsdElt.xgetRef());
// else
state.error("Element " + name + " specifies both a ref and a name", XmlErrorContext.ELEMENT_EXTRA_REF, xsdElt.xgetRef());
// ignore name
name = null;
}
if (ref == null && name == null)
{
state.error("Element has no name", XmlErrorContext.ELEMENT_MISSING_NAME, xsdElt);
// recovery: ignore this element
return null;
}
if (name != null && !XMLChar.isValidNCName(name))
{
state.error("Invalid element name \"" + name + "\"", XmlErrorContext.INVALID_NAME, xsdElt.xgetName());
// recovery: let the name go through anyway.
}
if (ref != null)
{
if (xsdElt.getType() != null || xsdElt.getSimpleType() != null || xsdElt.getComplexType() != null)
{
state.error("Element reference cannot also specify a type", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: let the name go through anyway.
}
if (xsdElt.getForm() != null)
{
state.error("Element reference cannot also specify form", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: let the name go through anyway.
}
if (xsdElt.sizeOfKeyArray() > 0 || xsdElt.sizeOfKeyrefArray() > 0 || xsdElt.sizeOfUniqueArray() > 0)
{
state.warning("Element reference cannot also contain key, keyref, or unique", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: ignore
}
if (xsdElt.isSetDefault())
{
state.warning("Element with reference to '" + ref.getLocalPart() + "' cannot also specify default", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: ignore
}
if (xsdElt.isSetFixed())
{
state.warning("Element with reference to '" + ref.getLocalPart() + "' cannot also specify fixed", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: ignore
}
if (xsdElt.isSetBlock())
{
state.warning("Element with reference to '" + ref.getLocalPart() + "' cannot also specify block", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: ignore
}
if (xsdElt.isSetNillable())
{
state.warning("Element with reference to '" + ref.getLocalPart() + "' cannot also specify nillable", XmlErrorContext.INVALID_NAME, xsdElt);
// recovery: ignore
}
if (XmlBeans.ASSERTS)
XmlBeans.assertTrue(xsdElt instanceof LocalElement);
SchemaGlobalElement referenced = state.findGlobalElement(ref, chameleon ? targetNamespace : null);
if (referenced == null)
{
state.notFoundError(ref, XmlErrorContext.ELEMENT_REF_NOT_FOUND, xsdElt.xgetRef());
// recovery: ignore this element
return null;
}
SchemaLocalElementImpl target = new SchemaLocalElementImpl();
target.setParticleType(SchemaParticle.ELEMENT);
copyGlobalElementToLocalElement( referenced, target );
return target;
}
QName qname;
SchemaLocalElementImpl impl;
SchemaType sType = null;
if (xsdElt instanceof LocalElement)
{
impl = new SchemaLocalElementImpl();
FormChoice form = xsdElt.xgetForm();
if (form == null)
form = findElementFormDefault(xsdElt);
if (form == null || form.getStringValue().equals("unqualified"))
qname = QNameHelper.forLN(name);
else
qname = QNameHelper.forLNS(name, targetNamespace);
}
else
{
SchemaGlobalElementImpl gelt = new SchemaGlobalElementImpl(state.sts());
impl = gelt;
// Set subst group head
if (sgHead != null)
{
SchemaGlobalElementImpl head = state.findGlobalElement(xsdElt.getSubstitutionGroup(), chameleon ? targetNamespace : null);
if (head != null)
gelt.setSubstitutionGroup(head.getRef());
}
// Set subst group members
qname = QNameHelper.forLNS(name, targetNamespace);
SchemaTypeImpl docType = (SchemaTypeImpl)outerType;
QName[] sgMembers = docType.getSubstitutionGroupMembers();
QNameSetBuilder transitionRules = new QNameSetBuilder();
transitionRules.add(qname);
for (int i = 0 ; i < sgMembers.length ; i++)
{
gelt.addSubstitutionGroupMember(sgMembers[i]);
transitionRules.add(sgMembers[i]);
}
impl.setTransitionRules(QNameSet.forSpecification(transitionRules), false);
impl.setTransitionNotes(QNameSet.EMPTY, true);
boolean finalExt = false;
boolean finalRest = false;
Object ds = xsdElt.getFinal();
if (ds != null)
{
if (ds instanceof String && ds.equals("#all"))
{
// #ALL value
finalExt = finalRest = true;
}
else if (ds instanceof List)
{
if (((List)ds).contains("extension"))
finalExt = true;
if (((List)ds).contains("restriction"))
finalRest = true;
}
}
gelt.setFinal(finalExt, finalRest);
gelt.setAbstract(xsdElt.getAbstract());
gelt.setFilename(findFilename(xsdElt));
gelt.setParseContext(xsdElt, targetNamespace, chameleon);
}
if (xsdElt.getType() != null)
{
sType = state.findGlobalType(xsdElt.getType(), chameleon ? targetNamespace : null );
if (sType == null)
state.notFoundError(xsdElt.getType(), XmlErrorContext.TYPE_NOT_FOUND, xsdElt.xgetType());
}
boolean simpleTypedef = false;
XmlObject typedef = xsdElt.getComplexType();
if (typedef == null)
{
typedef = xsdElt.getSimpleType();
simpleTypedef = true;
}
if ((sType != null) && typedef != null)
{
state.error("Illegal to define a nested type when a type attribute is specified", XmlErrorContext.REDUNDANT_NESTED_TYPE, typedef);
typedef = null;
}
if (typedef != null)
{
SchemaTypeImpl sTypeImpl = new SchemaTypeImpl(state.sts());
sType = sTypeImpl;
sTypeImpl.setContainerField(impl);
sTypeImpl.setOuterSchemaTypeRef(outerType == null ? null : outerType.getRef());
// leave the anonymous type unresolved: it will be resolved later.
anonymousTypes.add(sType);
sTypeImpl.setSimpleType(simpleTypedef);
sTypeImpl.setParseContext(typedef, targetNamespace, chameleon, false);
}
if (sType == null)
{
// type may inherit from substitution group head
if (sgHead != null)
{
SchemaGlobalElement head = state.findGlobalElement(xsdElt.getSubstitutionGroup(), chameleon ? targetNamespace : null);
// Bug - Do I need to copy the type if it's anonymous?
// If element does not exist, error has already been reported
if (head != null)
sType = head.getType();
}
}
if (sType == null)
sType = BuiltinSchemaTypeSystem.ST_ANY_TYPE;
SOAPArrayType wat = null;
XmlCursor c = xsdElt.newCursor();
String arrayType = c.getAttributeText(WSDL_ARRAYTYPE_NAME);
c.dispose();
if (arrayType != null)
{
wat = new SOAPArrayType(arrayType, new NamespaceContext(xsdElt));
}
impl.setWsdlArrayType(wat);
boolean isFixed = xsdElt.isSetFixed();
if (xsdElt.isSetDefault() && isFixed)
{
state.error("Should not set both default and fixed on the same element", XmlErrorContext.REDUNDANT_DEFAULT_FIXED, xsdElt.xgetFixed());
// recovery: ignore fixed
isFixed = false;
}
impl.setParticleType(SchemaParticle.ELEMENT);
impl.setNameAndTypeRef(qname, sType.getRef());
impl.setNillable(xsdElt.getNillable());
impl.setDefault(isFixed ? xsdElt.getFixed() : xsdElt.getDefault(), isFixed, xsdElt);
Object block = xsdElt.getBlock();
boolean blockExt = false;
boolean blockRest = false;
boolean blockSubst = false;
if (block != null)
{
if (block instanceof String && block.equals("#all"))
{
// #ALL value
blockExt = blockRest = blockSubst = true;
}
else if (block instanceof List)
{
if (((List)block).contains("extension"))
blockExt = true;
if (((List)block).contains("restriction"))
blockRest = true;
if (((List)block).contains("substitution"))
blockSubst = true;
}
}
impl.setBlock(blockExt, blockRest, blockSubst);
boolean constraintFailed = false;
// Translate Identity constraints
int length = xsdElt.sizeOfKeyArray() + xsdElt.sizeOfKeyrefArray() + xsdElt.sizeOfUniqueArray();
SchemaIdentityConstraintImpl[] constraints = new SchemaIdentityConstraintImpl[length];
int cur = 0;
// Handle key constraints
Keybase[] keys = xsdElt.getKeyArray();
for (int i = 0 ; i < keys.length ; i++, cur++) {
constraints[cur] = translateIdentityConstraint(keys[i], targetNamespace, chameleon);
if (constraints[cur] != null)
constraints[cur].setConstraintCategory(SchemaIdentityConstraint.CC_KEY);
else
constraintFailed = true;
}
// Handle unique constraints
Keybase[] uc = xsdElt.getUniqueArray();
for (int i = 0 ; i < uc.length ; i++, cur++) {
constraints[cur] = translateIdentityConstraint(uc[i], targetNamespace, chameleon);
if (constraints[cur] != null)
constraints[cur].setConstraintCategory(SchemaIdentityConstraint.CC_UNIQUE);
else
constraintFailed = true;
}
// Handle keyref constraints
KeyrefDocument.Keyref[] krs = xsdElt.getKeyrefArray();
for (int i = 0 ; i < krs.length ; i++, cur++) {
constraints[cur] = translateIdentityConstraint(krs[i], targetNamespace, chameleon);
if (constraints[cur] != null)
constraints[cur].setConstraintCategory(SchemaIdentityConstraint.CC_KEYREF);
else
constraintFailed = true;
}
if (!constraintFailed)
{
SchemaIdentityConstraint.Ref[] refs = new SchemaIdentityConstraint.Ref[length];
for (int i = 0 ; i < refs.length ; i++)
refs[i] = constraints[i].getRef();
impl.setIdentityConstraints(refs);
}
return impl;
}
private static String removeWhitespace(String xpath)
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < xpath.length(); i++)
{
char ch = xpath.charAt(i);
if (XMLChar.isSpace(ch))
continue;
sb.append(ch);
}
return sb.toString();
}
public static final org.apache.xmlbeans.impl.regex.RegularExpression XPATH_REGEXP = new org.apache.xmlbeans.impl.regex.RegularExpression("(\\.//)?((((child::)?((\\i\\c*:)?(\\i\\c*|\\*)))|\\.)/)*((((child::)?((\\i\\c*:)?(\\i\\c*|\\*)))|\\.)|((attribute::|@)((\\i\\c*:)?(\\i\\c*|\\*))))(\\|(\\.//)?((((child::)?((\\i\\c*:)?(\\i\\c*|\\*)))|\\.)/)*((((child::)?((\\i\\c*:)?(\\i\\c*|\\*)))|\\.)|((attribute::|@)((\\i\\c*:)?(\\i\\c*|\\*)))))*", "X");
private static boolean checkXPathSyntax(String xpath)
{
if (xpath == null)
return false;
// strip whitespace from xpath
xpath = removeWhitespace(xpath);
// apply regexp
synchronized (XPATH_REGEXP)
{
return (XPATH_REGEXP.matches(xpath));
}
}
private static SchemaIdentityConstraintImpl translateIdentityConstraint(Keybase parseIC,
String targetNamespace, boolean chameleon)
{
StscState state = StscState.get();
// first do some checking
String selector = parseIC.getSelector() == null ? null : parseIC.getSelector().getXpath();
if (!checkXPathSyntax(selector))
{
StscState.get().error("Invalid xpath in selector.",
XmlErrorContext.XPATH_COMPILATION_FAILURE, parseIC.getSelector().xgetXpath());
return null;
}
FieldDocument.Field[] fieldElts = parseIC.getFieldArray();
for (int j = 0; j < fieldElts.length; j++)
{
if (!checkXPathSyntax(fieldElts[j].getXpath()))
{
StscState.get().error("Invalid xpath in field.",
XmlErrorContext.XPATH_COMPILATION_FAILURE, fieldElts[j].xgetXpath());
return null;
}
}
// then translate.
SchemaIdentityConstraintImpl ic = new SchemaIdentityConstraintImpl(state.sts());
ic.setName(QNameHelper.forLNS(parseIC.getName(), targetNamespace));
ic.setSelector(parseIC.getSelector().getXpath());
ic.setParseContext(parseIC, targetNamespace, chameleon);
// Set the ns map
XmlCursor c = parseIC.newCursor();
Map nsMap = new HashMap();
c.getAllNamespaces(nsMap);
nsMap.remove(""); // Remove the default mapping. This cannot be used by the xpath expressions.
ic.setNSMap(nsMap);
c.dispose();
String[] fields = new String[fieldElts.length];
for (int j = 0 ; j < fields.length ; j++)
fields[j] = fieldElts[j].getXpath();
ic.setFields(fields);
try {
ic.buildPaths();
}
catch (XPath.XPathCompileException e) {
StscState.get().error("Invalid xpath in identity constraint: " + e.getMessage(),
XmlErrorContext.XPATH_COMPILATION_FAILURE, parseIC);
return null;
}
state.addIdConstraint(ic);
return ic;
}
public static SchemaModelGroupImpl translateModelGroup(NamedGroup namedGroup, String targetNamespace, boolean chameleon, boolean redefinition)
{
String name = namedGroup.getName();
if (name == null)
{
StscState.get().error("Model groups must be named", XmlErrorContext.MODEL_GROUP_MISSING_NAME, namedGroup);
return null;
}
SchemaModelGroupImpl result = new SchemaModelGroupImpl(StscState.get().sts());
result.init(QNameHelper.forLNS(name, targetNamespace), targetNamespace, chameleon, redefinition, namedGroup);
return result;
}
public static SchemaAttributeGroupImpl translateAttributeGroup(AttributeGroup attrGroup, String targetNamespace, boolean chameleon, boolean redefinition)
{
String name = attrGroup.getName();
if (name == null)
{
StscState.get().error("Attribute groups must be named", XmlErrorContext.ATTRIBUTE_GROUP_MISSING_NAME, attrGroup);
return null;
}
SchemaAttributeGroupImpl result = new SchemaAttributeGroupImpl(StscState.get().sts());
result.init(QNameHelper.forLNS(name, targetNamespace), targetNamespace, chameleon, redefinition, attrGroup);
return result;
}
static FormChoice findAttributeFormDefault(XmlObject obj)
{
XmlCursor cur = obj.newCursor();
while (cur.getObject().schemaType() != Schema.type)
if (!cur.toParent())
return null;
return ((Schema)cur.getObject()).xgetAttributeFormDefault();
}
static SchemaLocalAttributeImpl translateAttribute(
Attribute xsdAttr, String targetNamespace, boolean chameleon, List anonymousTypes,
SchemaType outerType, SchemaAttributeModel baseModel, boolean local)
{
StscState state = StscState.get();
String name = xsdAttr.getName();
QName ref = xsdAttr.getRef();
if (ref != null && name != null)
{
if (name.equals(ref.getLocalPart()) && uriMatch(targetNamespace, ref.getNamespaceURI()))
state.warning("Attribute " + name + " specifies both a ref and a name", XmlErrorContext.ELEMENT_EXTRA_REF, xsdAttr.xgetRef());
else
state.error("Attribute " + name + " specifies both a ref and a name", XmlErrorContext.ELEMENT_EXTRA_REF, xsdAttr.xgetRef());
// ignore name
name = null;
}
if (ref == null && name == null)
{
state.error("Attribute has no name", XmlErrorContext.ELEMENT_MISSING_NAME, xsdAttr);
// recovery: ignore this element
return null;
}
if (name != null && !XMLChar.isValidNCName(name))
{
state.error("Invalid attribute name \"" + name + "\"", XmlErrorContext.INVALID_NAME, xsdAttr.xgetName());
// recovery: let the name go through anyway.
}
boolean isFixed = false;
String deftext = null;
QName qname;
SchemaLocalAttributeImpl sAttr;
SchemaType sType = null;
int use = SchemaLocalAttribute.OPTIONAL;
if (local)
sAttr = new SchemaLocalAttributeImpl();
else
{
sAttr = new SchemaGlobalAttributeImpl(state.sts());
((SchemaGlobalAttributeImpl)sAttr).setParseContext(xsdAttr, targetNamespace, chameleon);
}
if (ref != null)
{
if (xsdAttr.getType() != null || xsdAttr.getSimpleType() != null)
{
state.error("Attribute reference cannot also specify type", XmlErrorContext.INVALID_NAME, xsdAttr);
// recovery: ignore type, simpleType
}
if (xsdAttr.getForm() != null)
{
state.error("Attribute reference cannot also specify form", XmlErrorContext.INVALID_NAME, xsdAttr);
// recovery: ignore form
}
SchemaGlobalAttribute referenced = state.findGlobalAttribute(ref, chameleon ? targetNamespace : null);
if (referenced == null)
{
state.notFoundError(ref, XmlErrorContext.ATTRIBUTE_REF_NOT_FOUND, xsdAttr.xgetRef());
// recovery: ignore this element
return null;
}
qname = ref;
use = referenced.getUse();
sType = referenced.getType();
deftext = referenced.getDefaultText();
if (deftext != null)
{
isFixed = referenced.isFixed();
}
}
else
{
if (local)
{
FormChoice form = xsdAttr.xgetForm();
if (form == null)
form = findAttributeFormDefault(xsdAttr);
if (form == null || form.getStringValue().equals("unqualified"))
qname = QNameHelper.forLN(name);
else
qname = QNameHelper.forLNS(name, targetNamespace);
}
else
{
qname = QNameHelper.forLNS(name, targetNamespace);
}
if (xsdAttr.getType() != null)
{
sType = state.findGlobalType(xsdAttr.getType(), chameleon ? targetNamespace : null );
if (sType == null)
state.notFoundError(xsdAttr.getType(), XmlErrorContext.TYPE_NOT_FOUND, xsdAttr.xgetType());
}
if (qname.getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema-instance"))
{
state.error("Illegal namespace for attribute declaration.", XmlErrorContext.INVALID_NAME, xsdAttr.xgetName());
}
if (qname.getNamespaceURI().length() == 0 && qname.getLocalPart().equals("xmlns"))
{
state.error("Illegal name for attribute declaration.", XmlErrorContext.INVALID_NAME, xsdAttr.xgetName());
}
XmlObject typedef = xsdAttr.getSimpleType();
if ((sType != null) && typedef != null)
{
state.error("Illegal to define a nested type when a type attribute is specified", XmlErrorContext.REDUNDANT_NESTED_TYPE, typedef);
typedef = null;
}
if (typedef != null)
{
SchemaTypeImpl sTypeImpl = new SchemaTypeImpl(state.sts());
sType = sTypeImpl;
sTypeImpl.setContainerField(sAttr);
sTypeImpl.setOuterSchemaTypeRef(outerType == null ? null : outerType.getRef());
// leave the anonymous type unresolved: it will be resolved later.
anonymousTypes.add(sType);
sTypeImpl.setSimpleType(true);
sTypeImpl.setParseContext(typedef, targetNamespace, chameleon, false);
}
if (sType == null && baseModel != null && baseModel.getAttribute(qname) != null)
sType = baseModel.getAttribute(qname).getType();
}
if (sType == null)
sType = BuiltinSchemaTypeSystem.ST_ANY_SIMPLE;
if (!sType.isSimpleType())
{
state.error("Attributes must have a simple type (not complex).", XmlErrorContext.INVALID_SCHEMA, xsdAttr);
// recovery: switch to the any-type
sType = BuiltinSchemaTypeSystem.ST_ANY_SIMPLE;
}
if (xsdAttr.isSetUse())
{
use = translateUseCode(xsdAttr.xgetUse());
// ignore referenced default if no longer optional
if (use != SchemaLocalAttribute.OPTIONAL && !isFixed)
deftext = null;
}
if (xsdAttr.isSetDefault() || xsdAttr.isSetFixed())
{
if (isFixed && !xsdAttr.isSetFixed())
state.error("A use of a fixed attribute definition must also be fixed", XmlErrorContext.REDUNDANT_DEFAULT_FIXED, xsdAttr.xgetFixed());
isFixed = xsdAttr.isSetFixed();
if (xsdAttr.isSetDefault() && isFixed)
{
state.error("Should not set both default and fixed on the same attribute", XmlErrorContext.REDUNDANT_DEFAULT_FIXED, xsdAttr.xgetFixed());
// recovery: ignore fixed
isFixed = false;
}
deftext = isFixed ? xsdAttr.getFixed() : xsdAttr.getDefault();
}
if (!local)
{
((SchemaGlobalAttributeImpl)sAttr).setFilename(findFilename(xsdAttr));
}
SOAPArrayType wat = null;
XmlCursor c = xsdAttr.newCursor();
String arrayType = c.getAttributeText(WSDL_ARRAYTYPE_NAME);
c.dispose();
if (arrayType != null)
{
wat = new SOAPArrayType(arrayType, new NamespaceContext(xsdAttr));
}
sAttr.init(
qname,
sType.getRef(),
use,
deftext, xsdAttr, null, isFixed,
wat);
return sAttr;
}
static int translateUseCode(Attribute.Use attruse)
{
if (attruse == null)
return SchemaLocalAttribute.OPTIONAL;
String val = attruse.getStringValue();
if (val.equals("optional"))
return SchemaLocalAttribute.OPTIONAL;
if (val.equals("required"))
return SchemaLocalAttribute.REQUIRED;
if (val.equals("prohibited"))
return SchemaLocalAttribute.PROHIBITED;
return SchemaLocalAttribute.OPTIONAL;
}
static XmlInteger buildNnInteger(XmlAnySimpleType value)
{
if (value == null)
return null;
String text = value.getStringValue();
BigInteger bigInt;
try
{
bigInt = new BigInteger(text);
}
catch (NumberFormatException e)
{
StscState.get().error("Must be nonnegative integer", XmlErrorContext.MALFORMED_NUMBER, value);
return null;
}
if (bigInt.signum() < 0)
{
StscState.get().error("Must be nonnegative integer", XmlErrorContext.MALFORMED_NUMBER, value);
return null;
}
try
{
XmlIntegerImpl i = new XmlIntegerImpl();
i.set(bigInt);
i.setImmutable();
return i;
}
catch (XmlValueOutOfRangeException e)
{
StscState.get().error("Internal error processing number", XmlErrorContext.MALFORMED_NUMBER, value);
return null;
}
}
private static boolean isReservedTypeName(QName name)
{
return (BuiltinSchemaTypeSystem.get().findType(name) != null);
}
}