1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Nov 2017 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xerces.internal.impl.xs.traversers; 23 24 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeFacetException; 25 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; 26 import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl; 27 import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar; 28 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols; 29 import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl; 30 import com.sun.org.apache.xerces.internal.impl.xs.util.XInt; 31 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; 32 import com.sun.org.apache.xerces.internal.util.DOMUtil; 33 import com.sun.org.apache.xerces.internal.xni.QName; 34 import com.sun.org.apache.xerces.internal.xs.XSConstants; 35 import com.sun.org.apache.xerces.internal.xs.XSObject; 36 import com.sun.org.apache.xerces.internal.xs.XSObjectList; 37 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; 38 import java.util.ArrayList; 39 import java.util.List; 40 import org.w3c.dom.Element; 41 42 /** 43 * The simple type definition schema component traverser. 44 * 45 * <simpleType 46 * final = (#all | (list | union | restriction)) 47 * id = ID 48 * name = NCName 49 * {any attributes with non-schema namespace . . .}> 50 * Content: (annotation?, (restriction | list | union)) 51 * </simpleType> 52 * 53 * <restriction 54 * base = QName 55 * id = ID 56 * {any attributes with non-schema namespace . . .}> 57 * Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)) 58 * </restriction> 59 * 60 * <list 61 * id = ID 62 * itemType = QName 63 * {any attributes with non-schema namespace . . .}> 64 * Content: (annotation?, (simpleType?)) 65 * </list> 66 * 67 * <union 68 * id = ID 69 * memberTypes = List of QName 70 * {any attributes with non-schema namespace . . .}> 71 * Content: (annotation?, (simpleType*)) 72 * </union> 73 * 74 * @xerces.internal 75 * 76 * @author Elena Litani, IBM 77 * @author Neeraj Bajaj, Sun Microsystems, Inc. 78 * @author Sandy Gao, IBM 79 * 80 */ 81 class XSDSimpleTypeTraverser extends XSDAbstractTraverser { 82 83 // whether the type being parsed is a S4S built-in type. 84 private boolean fIsBuiltIn = false; 85 86 XSDSimpleTypeTraverser (XSDHandler handler, 87 XSAttributeChecker gAttrCheck) { 88 super(handler, gAttrCheck); 89 } 90 91 //return qualified name of simpleType or empty string if error occured 92 XSSimpleType traverseGlobal(Element elmNode, 93 XSDocumentInfo schemaDoc, 94 SchemaGrammar grammar) { 95 96 // General Attribute Checking 97 Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc); 98 String nameAtt = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; 99 if (nameAtt == null) { 100 attrValues[XSAttributeChecker.ATTIDX_NAME] = NO_NAME; 101 } 102 XSSimpleType type = traverseSimpleTypeDecl(elmNode, attrValues, schemaDoc, grammar); 103 fAttrChecker.returnAttrArray(attrValues, schemaDoc); 104 105 // if it's a global type without a name, return null 106 if (nameAtt == null) { 107 reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, SchemaSymbols.ATT_NAME}, elmNode); 108 type = null; 109 } 110 111 // don't add global components without name to the grammar 112 if (type != null) { 113 if (grammar.getGlobalTypeDecl(type.getName()) == null) { 114 grammar.addGlobalSimpleTypeDecl(type); 115 } 116 117 // also add it to extended map 118 final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); 119 final XSTypeDefinition type2 = grammar.getGlobalTypeDecl(type.getName(), loc); 120 if (type2 == null) { 121 grammar.addGlobalSimpleTypeDecl(type, loc); 122 } 123 124 // handle duplicates 125 if (fSchemaHandler.fTolerateDuplicates) { 126 if (type2 != null) { 127 if (type2 instanceof XSSimpleType) { 128 type = (XSSimpleType) type2; 129 } 130 } 131 fSchemaHandler.addGlobalTypeDecl(type); 132 } 133 } 134 135 return type; 136 } 137 138 XSSimpleType traverseLocal(Element elmNode, 139 XSDocumentInfo schemaDoc, 140 SchemaGrammar grammar) { 141 142 // General Attribute Checking 143 Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc); 144 String name = genAnonTypeName(elmNode); 145 XSSimpleType type = getSimpleType (name, elmNode, attrValues, schemaDoc, grammar); 146 if (type instanceof XSSimpleTypeDecl) { 147 ((XSSimpleTypeDecl)type).setAnonymous(true); 148 } 149 fAttrChecker.returnAttrArray(attrValues, schemaDoc); 150 151 return type; 152 } 153 154 private XSSimpleType traverseSimpleTypeDecl(Element simpleTypeDecl, 155 Object[] attrValues, 156 XSDocumentInfo schemaDoc, 157 SchemaGrammar grammar) { 158 159 // get name and final values 160 String name = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; 161 return getSimpleType(name, simpleTypeDecl, attrValues, schemaDoc, grammar); 162 } 163 164 /* 165 * Generate a name for an anonymous type 166 */ 167 private String genAnonTypeName(Element simpleTypeDecl) { 168 169 // Generate a unique name for the anonymous type by concatenating together the 170 // names of parent nodes 171 // The name is quite good for debugging/error purposes, but we may want to 172 // revisit how this is done for performance reasons (LM). 173 StringBuffer typeName = new StringBuffer("#AnonType_"); 174 Element node = DOMUtil.getParent(simpleTypeDecl); 175 while (node != null && (node != DOMUtil.getRoot(DOMUtil.getDocument(node)))) { 176 typeName.append(node.getAttribute(SchemaSymbols.ATT_NAME)); 177 node = DOMUtil.getParent(node); 178 } 179 return typeName.toString(); 180 } 181 182 /** 183 * @param name 184 * @param simpleTypeDecl 185 * @param attrValues 186 * @param schemaDoc 187 * @param grammar 188 * @return 189 */ 190 private XSSimpleType getSimpleType(String name, Element simpleTypeDecl, Object[] attrValues, XSDocumentInfo schemaDoc, SchemaGrammar grammar) { 191 XInt finalAttr = (XInt)attrValues[XSAttributeChecker.ATTIDX_FINAL]; 192 int finalProperty = finalAttr == null ? schemaDoc.fFinalDefault : finalAttr.intValue(); 193 // annotation?,(list|restriction|union) 194 Element child = DOMUtil.getFirstChildElement(simpleTypeDecl); 195 XSAnnotationImpl [] annotations = null; 196 if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { 197 XSAnnotationImpl annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); 198 if (annotation != null) 199 annotations = new XSAnnotationImpl [] {annotation}; 200 child = DOMUtil.getNextSiblingElement(child); 201 } 202 else { 203 String text = DOMUtil.getSyntheticAnnotation(simpleTypeDecl); 204 if (text != null) { 205 XSAnnotationImpl annotation = traverseSyntheticAnnotation(simpleTypeDecl, text, attrValues, false, schemaDoc); 206 annotations = new XSAnnotationImpl[] {annotation}; 207 } 208 } 209 // (list|restriction|union) 210 if (child == null) { 211 reportSchemaError("s4s-elt-must-match.2", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))"}, simpleTypeDecl); 212 return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION); 213 } 214 // derivation type: restriction/list/union 215 String varietyProperty = DOMUtil.getLocalName(child); 216 short refType = XSConstants.DERIVATION_RESTRICTION; 217 boolean restriction = false, list = false, union = false; 218 if (varietyProperty.equals(SchemaSymbols.ELT_RESTRICTION)) { 219 refType = XSConstants.DERIVATION_RESTRICTION; 220 restriction = true; 221 } 222 else if (varietyProperty.equals(SchemaSymbols.ELT_LIST)) { 223 refType = XSConstants.DERIVATION_LIST; 224 list = true; 225 } 226 else if (varietyProperty.equals(SchemaSymbols.ELT_UNION)) { 227 refType = XSConstants.DERIVATION_UNION; 228 union = true; 229 } 230 else { 231 reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", varietyProperty}, simpleTypeDecl); 232 return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION); 233 } 234 // nothing should follow this element 235 Element nextChild = DOMUtil.getNextSiblingElement(child); 236 if (nextChild != null) { 237 reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", DOMUtil.getLocalName(nextChild)}, nextChild); 238 } 239 // General Attribute Checking: get base/item/member types 240 Object[] contentAttrs = fAttrChecker.checkAttributes(child, false, schemaDoc); 241 QName baseTypeName = (QName)contentAttrs[restriction ? 242 XSAttributeChecker.ATTIDX_BASE : 243 XSAttributeChecker.ATTIDX_ITEMTYPE]; 244 @SuppressWarnings("unchecked") 245 List<QName> memberTypes = (ArrayList<QName>)contentAttrs[XSAttributeChecker.ATTIDX_MEMBERTYPES]; 246 //content = {annotation?,simpleType?...} 247 Element content = DOMUtil.getFirstChildElement(child); 248 //check content (annotation?, ...) 249 if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_ANNOTATION)) { 250 XSAnnotationImpl annotation = traverseAnnotationDecl(content, contentAttrs, false, schemaDoc); 251 if (annotation != null ) { 252 if(annotations == null) { 253 annotations = new XSAnnotationImpl [] {annotation}; 254 } 255 else { 256 XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2]; 257 tempArray[0] = annotations[0]; 258 annotations = tempArray; 259 annotations[1] = annotation; 260 } 261 } 262 content = DOMUtil.getNextSiblingElement(content); 263 } 264 else { 265 String text = DOMUtil.getSyntheticAnnotation(child); 266 if (text != null) { 267 XSAnnotationImpl annotation = traverseSyntheticAnnotation(child, text, contentAttrs, false, schemaDoc); 268 if (annotations == null) { 269 annotations = new XSAnnotationImpl [] {annotation}; 270 } 271 else { 272 XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2]; 273 tempArray[0] = annotations[0]; 274 annotations = tempArray; 275 annotations[1] = annotation; 276 } 277 } 278 } 279 // get base type from "base" attribute 280 XSSimpleType baseValidator = null; 281 if ((restriction || list) && baseTypeName != null) { 282 baseValidator = findDTValidator(child, name, baseTypeName, refType, schemaDoc); 283 // if its the built-in type, return null from here 284 if (baseValidator == null && fIsBuiltIn) { 285 fIsBuiltIn = false; 286 return null; 287 } 288 } 289 // get types from "memberTypes" attribute 290 List<XSObject> dTValidators = null; 291 XSSimpleType dv = null; 292 XSObjectList dvs; 293 if (union && memberTypes != null && memberTypes.size() > 0) { 294 int size = memberTypes.size(); 295 dTValidators = new ArrayList<>(size); 296 // for each qname in the list 297 for (int i = 0; i < size; i++) { 298 // get the type decl 299 dv = findDTValidator(child, name, memberTypes.get(i), 300 XSConstants.DERIVATION_UNION, schemaDoc); 301 if (dv != null) { 302 // if it's a union, expand it 303 if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { 304 dvs = dv.getMemberTypes(); 305 for (int j = 0; j < dvs.getLength(); j++) 306 dTValidators.add(dvs.item(j)); 307 } else { 308 dTValidators.add(dv); 309 } 310 } 311 } 312 } 313 314 // check if there is a child "simpleType" 315 if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE)) { 316 if (restriction || list) { 317 // it's an error for both "base" and "simpleType" to appear 318 if (baseTypeName != null) { 319 reportSchemaError(list ? "src-simple-type.3.a" : "src-simple-type.2.a", null, content); 320 } 321 if (baseValidator == null) { 322 // traverse this child to get the base type 323 baseValidator = traverseLocal(content, schemaDoc, grammar); 324 } 325 // get the next element 326 content = DOMUtil.getNextSiblingElement(content); 327 } 328 else if (union) { 329 if (dTValidators == null) { 330 dTValidators = new ArrayList<>(2); 331 } 332 do { 333 // traverse this child to get the member type 334 dv = traverseLocal(content, schemaDoc, grammar); 335 if (dv != null) { 336 // if it's a union, expand it 337 if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { 338 dvs = dv.getMemberTypes(); 339 for (int j = 0; j < dvs.getLength(); j++) { 340 dTValidators.add(dvs.item(j)); 341 } 342 } 343 else { 344 dTValidators.add(dv); 345 } 346 } 347 // get the next element 348 content = DOMUtil.getNextSiblingElement(content); 349 } while (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE)); 350 } 351 } 352 else if ((restriction || list) && baseTypeName == null) { 353 // it's an error if neither "base/itemType" nor "simpleType" appears 354 reportSchemaError(list ? "src-simple-type.3.b" : "src-simple-type.2.b", null, child); 355 } 356 else if (union && (memberTypes == null || memberTypes.size() == 0)) { 357 // it's an error if "memberTypes" is empty and no "simpleType" appears 358 reportSchemaError("src-union-memberTypes-or-simpleTypes", null, child); 359 } 360 // error finding "base" or error traversing "simpleType". 361 // don't need to report an error, since some error has been reported. 362 if ((restriction || list) && baseValidator == null) { 363 fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); 364 return errorType(name, schemaDoc.fTargetNamespace, 365 restriction ? XSConstants.DERIVATION_RESTRICTION : XSConstants.DERIVATION_LIST); 366 } 367 // error finding "memberTypes" or error traversing "simpleType". 368 // don't need to report an error, since some error has been reported. 369 if (union && (dTValidators == null || dTValidators.size() == 0)) { 370 fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); 371 return errorType(name, schemaDoc.fTargetNamespace, 372 XSConstants.DERIVATION_UNION); 373 } 374 // item type of list types can't have list content 375 if (list && isListDatatype(baseValidator)) { 376 reportSchemaError("cos-st-restricts.2.1", new Object[]{name, baseValidator.getName()}, child); 377 fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); 378 return errorType(name, schemaDoc.fTargetNamespace, 379 XSConstants.DERIVATION_LIST); 380 } 381 // create the simple type based on the "base" type 382 XSSimpleType newDecl = null; 383 if (restriction) { 384 newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, 385 annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); 386 } 387 else if (list) { 388 newDecl = fSchemaHandler.fDVFactory.createTypeList(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, 389 annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); 390 } 391 else if (union) { 392 XSSimpleType[] memberDecls = dTValidators.toArray(new XSSimpleType[dTValidators.size()]); 393 newDecl = fSchemaHandler.fDVFactory.createTypeUnion(name, schemaDoc.fTargetNamespace, (short)finalProperty, memberDecls, 394 annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); 395 } 396 // now traverse facets, if it's derived by restriction 397 if (restriction && content != null) { 398 FacetInfo fi = traverseFacets(content, baseValidator, schemaDoc); 399 content = fi.nodeAfterFacets; 400 401 try { 402 fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); 403 newDecl.applyFacets(fi.facetdata, fi.fPresentFacets, fi.fFixedFacets, fValidationState); 404 } catch (InvalidDatatypeFacetException ex) { 405 reportSchemaError(ex.getKey(), ex.getArgs(), child); 406 // Recreate the type, ignoring the facets 407 newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, 408 annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); 409 } 410 } 411 // no element should appear after this point 412 if (content != null) { 413 if (restriction) { 414 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); 415 } 416 else if (list) { 417 reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_LIST, "(annotation?, (simpleType?))", DOMUtil.getLocalName(content)}, content); 418 } 419 else if (union) { 420 reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_UNION, "(annotation?, (simpleType*))", DOMUtil.getLocalName(content)}, content); 421 } 422 } 423 fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); 424 // return the new type 425 return newDecl; 426 } 427 428 //@param: elm - top element 429 //@param: baseTypeStr - type (base/itemType/memberTypes) 430 //@param: baseRefContext: whether the caller is using this type as a base for restriction, union or list 431 //return XSSimpleType available for the baseTypeStr, null if not found or disallowed. 432 // also throws an error if the base type won't allow itself to be used in this context. 433 // REVISIT: can this code be re-used? 434 private XSSimpleType findDTValidator(Element elm, String refName, 435 QName baseTypeStr, short baseRefContext, 436 XSDocumentInfo schemaDoc) { 437 if (baseTypeStr == null) 438 return null; 439 440 XSTypeDefinition baseType = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, baseTypeStr, elm); 441 if (baseType == null) { 442 return null; 443 } 444 if (baseType.getTypeCategory() != XSTypeDefinition.SIMPLE_TYPE) { 445 reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); 446 return null; 447 } 448 449 // if it's a complex type, or if its restriction of anySimpleType 450 if (baseType == SchemaGrammar.fAnySimpleType && 451 baseRefContext == XSConstants.DERIVATION_RESTRICTION) { 452 // if the base type is anySimpleType and the current type is 453 // a S4S built-in type, return null. (not an error). 454 if (checkBuiltIn(refName, schemaDoc.fTargetNamespace)) { 455 return null; 456 } 457 reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); 458 return null; 459 } 460 461 if ((baseType.getFinal() & baseRefContext) != 0) { 462 if (baseRefContext == XSConstants.DERIVATION_RESTRICTION) { 463 reportSchemaError("st-props-correct.3", new Object[]{refName, baseTypeStr.rawname}, elm); 464 } 465 else if (baseRefContext == XSConstants.DERIVATION_LIST) { 466 reportSchemaError("cos-st-restricts.2.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); 467 } 468 else if (baseRefContext == XSConstants.DERIVATION_UNION) { 469 reportSchemaError("cos-st-restricts.3.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); 470 } 471 return null; 472 } 473 474 return (XSSimpleType)baseType; 475 } 476 477 // check whethe the type denoted by the name and namespace is a S4S 478 // built-in type. update fIsBuiltIn at the same time. 479 private final boolean checkBuiltIn(String name, String namespace) { 480 if (namespace != SchemaSymbols.URI_SCHEMAFORSCHEMA) 481 return false; 482 if (SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(name) != null) 483 fIsBuiltIn = true; 484 return fIsBuiltIn; 485 } 486 487 // find if a datatype validator is a list or has list datatype member. 488 private boolean isListDatatype(XSSimpleType validator) { 489 if (validator.getVariety() == XSSimpleType.VARIETY_LIST) 490 return true; 491 492 if (validator.getVariety() == XSSimpleType.VARIETY_UNION) { 493 XSObjectList temp = validator.getMemberTypes(); 494 for (int i = 0; i < temp.getLength(); i++) { 495 if (((XSSimpleType)temp.item(i)).getVariety() == XSSimpleType.VARIETY_LIST) { 496 return true; 497 } 498 } 499 } 500 501 return false; 502 }//isListDatatype(XSSimpleTypeDecl):boolean 503 504 private XSSimpleType errorType(String name, String namespace, short refType) { 505 XSSimpleType stringType = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getTypeDefinition("string"); 506 switch (refType) { 507 case XSConstants.DERIVATION_RESTRICTION: 508 return fSchemaHandler.fDVFactory.createTypeRestriction(name, namespace, (short)0, 509 stringType, null); 510 case XSConstants.DERIVATION_LIST: 511 return fSchemaHandler.fDVFactory.createTypeList(name, namespace, (short)0, 512 stringType, null); 513 case XSConstants.DERIVATION_UNION: 514 return fSchemaHandler.fDVFactory.createTypeUnion(name, namespace, (short)0, 515 new XSSimpleType[]{stringType}, null); 516 } 517 518 return null; 519 } 520 521 }//class XSDSimpleTypeTraverser