1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.xsdc; 18 19 import com.android.xsdc.tag.*; 20 21 import org.xml.sax.Attributes; 22 import org.xml.sax.Locator; 23 import org.xml.sax.SAXException; 24 import org.xml.sax.helpers.DefaultHandler; 25 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.LinkedHashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Stack; 33 import java.util.stream.Collectors; 34 35 import javax.xml.namespace.QName; 36 37 public class XsdHandler extends DefaultHandler { 38 private static class State { 39 final String name; 40 final Map<String, String> attributeMap; 41 final List<XsdTag> tags; 42 boolean deprecated; 43 boolean finalValue; 44 Nullability nullability; 45 State(String name, Map<String, String> attributeMap)46 State(String name, Map<String, String> attributeMap) { 47 this.name = name; 48 this.attributeMap = Collections.unmodifiableMap(attributeMap); 49 tags = new ArrayList<>(); 50 deprecated = false; 51 finalValue = false; 52 nullability = Nullability.UNKNOWN; 53 } 54 } 55 56 private XmlSchema schema; 57 private final Stack<State> stateStack; 58 private final Map<String, String> namespaces; 59 private Locator locator; 60 private boolean documentationFlag; 61 private boolean enumerationFlag; 62 private List<XsdTag> enumTags; 63 private List<String> includeList; 64 XsdHandler()65 public XsdHandler() { 66 stateStack = new Stack<>(); 67 namespaces = new HashMap<>(); 68 documentationFlag = false; 69 enumerationFlag = false; 70 enumTags = new ArrayList<>(); 71 includeList = new ArrayList<>(); 72 } 73 getSchema()74 public XmlSchema getSchema() { 75 return schema; 76 } 77 78 @Override setDocumentLocator(Locator locator)79 public void setDocumentLocator(Locator locator) { 80 this.locator = locator; 81 } 82 83 @Override startPrefixMapping(String prefix, String uri)84 public void startPrefixMapping(String prefix, String uri) { 85 namespaces.put(prefix, uri); 86 } 87 88 @Override endPrefixMapping(String prefix)89 public void endPrefixMapping(String prefix) { 90 namespaces.remove(prefix); 91 } 92 parseQName(String str)93 private QName parseQName(String str) throws XsdParserException { 94 if (str == null) return null; 95 String[] parsed = str.split(":"); 96 if (parsed.length == 2) { 97 return new QName(namespaces.get(parsed[0]), parsed[1]); 98 } else if (parsed.length == 1) { 99 return new QName(null, str); 100 } 101 throw new XsdParserException(String.format("QName parse error : %s", str)); 102 } 103 parseQNames(String str)104 private List<QName> parseQNames(String str) throws XsdParserException { 105 List<QName> qNames = new ArrayList<>(); 106 if (str == null) return qNames; 107 String[] parsed = str.split("\\s+"); 108 for (String s : parsed) { 109 qNames.add(parseQName(s)); 110 } 111 return qNames; 112 } 113 114 @Override startElement( String uri, String localName, String qName, Attributes attributes)115 public void startElement( 116 String uri, String localName, String qName, Attributes attributes) { 117 // we need to copy attributes because it is mutable.. 118 Map<String, String> attributeMap = new HashMap<>(); 119 for (int i = 0; i < attributes.getLength(); ++i) { 120 attributeMap.put(attributes.getLocalName(i), attributes.getValue(i)); 121 } 122 if (!documentationFlag) { 123 stateStack.push(new State(localName, attributeMap)); 124 } 125 if (localName == "documentation") { 126 documentationFlag = true; 127 } 128 } 129 130 @Override endElement(String uri, String localName, String qName)131 public void endElement(String uri, String localName, String qName) throws SAXException { 132 if (documentationFlag && localName != "documentation") { 133 return; 134 } 135 try { 136 State state = stateStack.pop(); 137 switch (state.name) { 138 case "schema": 139 schema = makeSchema(state); 140 break; 141 case "element": 142 stateStack.peek().tags.add(makeElement(state)); 143 break; 144 case "attribute": 145 stateStack.peek().tags.add(makeAttribute(state)); 146 break; 147 case "attributeGroup": 148 stateStack.peek().tags.add(makeAttributeGroup(state)); 149 break; 150 case "complexType": 151 stateStack.peek().tags.add(makeComplexType(state)); 152 break; 153 case "complexContent": 154 stateStack.peek().tags.add(makeComplexContent(state)); 155 break; 156 case "simpleContent": 157 stateStack.peek().tags.add(makeSimpleContent(state)); 158 break; 159 case "restriction": 160 if (enumerationFlag) { 161 stateStack.peek().tags.add(makeEnumRestriction(state)); 162 enumerationFlag = false; 163 } else { 164 stateStack.peek().tags.add(makeGeneralRestriction(state)); 165 } 166 break; 167 case "extension": 168 stateStack.peek().tags.add(makeGeneralExtension(state)); 169 break; 170 case "simpleType": 171 stateStack.peek().tags.add(makeSimpleType(state)); 172 break; 173 case "list": 174 stateStack.peek().tags.add(makeSimpleTypeList(state)); 175 break; 176 case "union": 177 stateStack.peek().tags.add(makeSimpleTypeUnion(state)); 178 break; 179 case "sequence": 180 stateStack.peek().tags.addAll(makeSequence(state)); 181 break; 182 case "choice": 183 stateStack.peek().tags.addAll(makeChoice(state)); 184 break; 185 case "all": 186 stateStack.peek().tags.addAll(makeAll(state)); 187 break; 188 case "enumeration": 189 stateStack.peek().tags.add(makeEnumeration(state)); 190 enumerationFlag = true; 191 break; 192 case "group": 193 stateStack.peek().tags.add(makeGroup(state)); 194 break; 195 case "fractionDigits": 196 case "length": 197 case "maxExclusive": 198 case "maxInclusive": 199 case "maxLength": 200 case "minExclusive": 201 case "minInclusive": 202 case "minLength": 203 case "pattern": 204 case "totalDigits": 205 case "whiteSpace": 206 // Tags under simpleType <restriction>. They are ignored. 207 break; 208 case "annotation": 209 stateStack.peek().deprecated = isDeprecated(state.attributeMap, state.tags, 210 stateStack.peek().deprecated); 211 stateStack.peek().finalValue = isFinalValue(state.attributeMap, state.tags, 212 stateStack.peek().finalValue); 213 stateStack.peek().nullability = getNullability(state.attributeMap, state.tags, 214 stateStack.peek().nullability); 215 break; 216 case "appinfo": 217 // They function like comments, so are ignored. 218 break; 219 case "documentation": 220 documentationFlag = false; 221 break; 222 case "key": 223 case "keyref": 224 case "selector": 225 case "field": 226 case "unique": 227 // These tags are not related to xml parsing. 228 // They are using when validating xml files via xsd file. 229 // So they are ignored. 230 break; 231 case "include": 232 addInclude(state); 233 break; 234 default: 235 throw new XsdParserException(String.format("unsupported tag : %s", state.name)); 236 } 237 } catch (XsdParserException e) { 238 throw new SAXException( 239 String.format("Line %d, Column %d - %s", 240 locator.getLineNumber(), locator.getColumnNumber(), e.getMessage())); 241 } 242 } 243 makeSchema(State state)244 private XmlSchema makeSchema(State state) { 245 Map<String, XsdElement> elementMap = new LinkedHashMap<>(); 246 Map<String, XsdType> typeMap = new LinkedHashMap<>(); 247 Map<String, XsdAttribute> attrMap = new LinkedHashMap<>(); 248 Map<String, XsdAttributeGroup> attrGroupMap = new LinkedHashMap<>(); 249 Map<String, XsdGroup> groupMap = new LinkedHashMap<>(); 250 251 state.tags.addAll(enumTags); 252 for (XsdTag tag : state.tags) { 253 if (tag == null) continue; 254 if (tag instanceof XsdElement) { 255 elementMap.put(tag.getName(), (XsdElement) tag); 256 } else if (tag instanceof XsdAttribute) { 257 attrMap.put(tag.getName(), (XsdAttribute) tag); 258 } else if (tag instanceof XsdAttributeGroup) { 259 attrGroupMap.put(tag.getName(), (XsdAttributeGroup) tag); 260 } else if (tag instanceof XsdType) { 261 typeMap.put(tag.getName(), (XsdType) tag); 262 } else if (tag instanceof XsdGroup) { 263 groupMap.put(tag.getName(), (XsdGroup) tag); 264 } 265 } 266 267 return new XmlSchema(elementMap, typeMap, attrMap, attrGroupMap, groupMap, includeList); 268 } 269 makeElement(State state)270 private XsdElement makeElement(State state) throws XsdParserException { 271 String name = state.attributeMap.get("name"); 272 QName typename = parseQName(state.attributeMap.get("type")); 273 QName ref = parseQName(state.attributeMap.get("ref")); 274 String isAbstract = state.attributeMap.get("abstract"); 275 String defVal = state.attributeMap.get("default"); 276 String substitutionGroup = state.attributeMap.get("substitutionGroup"); 277 String maxOccurs = state.attributeMap.get("maxOccurs"); 278 279 if ("true".equals(isAbstract)) { 280 throw new XsdParserException("abstract element is not supported."); 281 } 282 if (defVal != null) { 283 throw new XsdParserException("default value of an element is not supported."); 284 } 285 if (substitutionGroup != null) { 286 throw new XsdParserException("substitution group of an element is not supported."); 287 } 288 289 boolean multiple = false; 290 if (maxOccurs != null) { 291 if (maxOccurs.equals("0")) return null; 292 if (maxOccurs.equals("unbounded") || Integer.parseInt(maxOccurs) > 1) multiple = true; 293 } 294 295 XsdType type = null; 296 if (typename != null) { 297 type = new XsdType(null, typename); 298 } 299 for (XsdTag tag : state.tags) { 300 if (tag == null) continue; 301 if (tag instanceof XsdType) { 302 type = (XsdType) tag; 303 } 304 } 305 306 return setDeprecatedAndFinal(new XsdElement(name, ref, type, multiple), state.deprecated, 307 state.finalValue, state.nullability); 308 } 309 makeAttribute(State state)310 private XsdAttribute makeAttribute(State state) throws XsdParserException { 311 String name = state.attributeMap.get("name"); 312 QName typename = parseQName(state.attributeMap.get("type")); 313 QName ref = parseQName(state.attributeMap.get("ref")); 314 String defVal = state.attributeMap.get("default"); 315 String use = state.attributeMap.get("use"); 316 317 if (use != null && use.equals("prohibited")) return null; 318 319 boolean required = false; 320 if (use != null && use.equals("required")) { 321 required = true; 322 } 323 324 XsdType type = null; 325 if (typename != null) { 326 type = new XsdType(null, typename); 327 } 328 for (XsdTag tag : state.tags) { 329 if (tag == null) continue; 330 if (tag instanceof XsdType) { 331 type = (XsdType) tag; 332 } 333 } 334 335 return setDeprecatedAndFinal(new XsdAttribute(name, ref, type, required), state.deprecated, 336 state.finalValue, state.nullability); 337 } 338 makeAttributeGroup(State state)339 private XsdAttributeGroup makeAttributeGroup(State state) throws XsdParserException { 340 String name = state.attributeMap.get("name"); 341 QName ref = parseQName(state.attributeMap.get("ref")); 342 343 List<XsdAttribute> attributes = new ArrayList<>(); 344 List<XsdAttributeGroup> attributeGroups = new ArrayList<>(); 345 346 for (XsdTag tag : state.tags) { 347 if (tag == null) continue; 348 if (tag instanceof XsdAttribute) { 349 attributes.add((XsdAttribute) tag); 350 } else if (tag instanceof XsdAttributeGroup) { 351 attributeGroups.add((XsdAttributeGroup) tag); 352 } 353 } 354 355 return setDeprecatedAndFinal(new XsdAttributeGroup(name, ref, attributes, attributeGroups), 356 state.deprecated, state.finalValue, state.nullability); 357 } 358 makeGroup(State state)359 private XsdGroup makeGroup(State state) throws XsdParserException { 360 String name = state.attributeMap.get("name"); 361 QName ref = parseQName(state.attributeMap.get("ref")); 362 363 List<XsdElement> elements = new ArrayList<>(); 364 365 for (XsdTag tag: state.tags) { 366 if (tag == null) continue; 367 if (tag instanceof XsdElement) { 368 elements.add((XsdElement) tag); 369 } 370 } 371 372 return setDeprecatedAndFinal(new XsdGroup(name, ref, elements), state.deprecated, 373 state.finalValue, state.nullability); 374 } 375 makeComplexType(State state)376 private XsdComplexType makeComplexType(State state) throws XsdParserException { 377 String name = state.attributeMap.get("name"); 378 String isAbstract = state.attributeMap.get("abstract"); 379 String mixed = state.attributeMap.get("mixed"); 380 381 if ("true".equals(isAbstract)) { 382 throw new XsdParserException("abstract complex type is not supported."); 383 } 384 if ("true".equals(mixed)) { 385 throw new XsdParserException("mixed option of a complex type is not supported."); 386 } 387 388 List<XsdAttribute> attributes = new ArrayList<>(); 389 List<XsdAttributeGroup> attributeGroups = new ArrayList<>(); 390 List<XsdElement> elements = new ArrayList<>(); 391 XsdComplexType type = null; 392 XsdGroup group = null; 393 394 for (XsdTag tag : state.tags) { 395 if (tag == null) continue; 396 if (tag instanceof XsdAttribute) { 397 attributes.add((XsdAttribute) tag); 398 } else if (tag instanceof XsdAttributeGroup) { 399 attributeGroups.add((XsdAttributeGroup) tag); 400 } else if (tag instanceof XsdGroup) { 401 group = (XsdGroup) tag; 402 } else if (tag instanceof XsdElement) { 403 elements.add((XsdElement) tag); 404 } else if (tag instanceof XsdComplexContent) { 405 XsdComplexContent child = (XsdComplexContent) tag; 406 type = setDeprecatedAndFinal(new XsdComplexContent(name, child.getBase(), 407 child.getAttributes(), child.getAttributeGroups(), 408 child.getElements(), child.getGroup()), state.deprecated, state.finalValue, 409 state.nullability); 410 } else if (tag instanceof XsdSimpleContent) { 411 XsdSimpleContent child = (XsdSimpleContent) tag; 412 type = setDeprecatedAndFinal(new XsdSimpleContent(name, child.getBase(), 413 child.getAttributes()), state.deprecated, state.finalValue, 414 state.nullability); 415 } 416 } 417 418 return (type != null) ? type : setDeprecatedAndFinal(new XsdComplexContent(name, null, 419 attributes, attributeGroups, elements, group), state.deprecated, state.finalValue, 420 state.nullability); 421 } 422 makeComplexContent(State state)423 private XsdComplexContent makeComplexContent(State state) throws XsdParserException { 424 String mixed = state.attributeMap.get("mixed"); 425 if ("true".equals(mixed)) { 426 throw new XsdParserException("mixed option of a complex content is not supported."); 427 } 428 429 XsdComplexContent content = null; 430 for (XsdTag tag : state.tags) { 431 if (tag == null) continue; 432 if (tag instanceof XsdGeneralExtension) { 433 XsdGeneralExtension extension = (XsdGeneralExtension) tag; 434 content = new XsdComplexContent(null, extension.getBase(), 435 extension.getAttributes(), extension.getAttributeGroups(), 436 extension.getElements(), extension.getGroup()); 437 } else if (tag instanceof XsdGeneralRestriction) { 438 XsdGeneralRestriction restriction = (XsdGeneralRestriction) tag; 439 XsdType base = restriction.getBase(); 440 if (base.getRef() != null && base.getRef().getNamespaceURI().equals( 441 XsdConstants.XSD_NAMESPACE)) { 442 // restriction of base 'xsd:anyType' is equal to complex content definition 443 content = new XsdComplexContent(null, null, restriction.getAttributes(), 444 restriction.getAttributeGroups(), restriction.getElements(), 445 restriction.getGroup()); 446 } else { 447 // otherwise ignore restrictions 448 content = new XsdComplexContent(null, base, null, null, null, null); 449 } 450 } 451 } 452 453 return setDeprecatedAndFinal(content, state.deprecated, state.finalValue, 454 state.nullability); 455 } 456 makeSimpleContent(State state)457 private XsdSimpleContent makeSimpleContent(State state) { 458 XsdSimpleContent content = null; 459 460 for (XsdTag tag : state.tags) { 461 if (tag == null) continue; 462 if (tag instanceof XsdGeneralExtension) { 463 XsdGeneralExtension extension = (XsdGeneralExtension) tag; 464 content = new XsdSimpleContent(null, extension.getBase(), 465 extension.getAttributes()); 466 } else if (tag instanceof XsdGeneralRestriction) { 467 XsdGeneralRestriction restriction = (XsdGeneralRestriction) tag; 468 content = new XsdSimpleContent(null, restriction.getBase(), null); 469 } 470 } 471 472 return setDeprecatedAndFinal(content, state.deprecated, state.finalValue, 473 state.nullability); 474 } 475 makeGeneralRestriction(State state)476 private XsdGeneralRestriction makeGeneralRestriction(State state) throws XsdParserException { 477 QName base = parseQName(state.attributeMap.get("base")); 478 479 XsdType type = null; 480 if (base != null) { 481 type = new XsdType(null, base); 482 } 483 List<XsdAttribute> attributes = new ArrayList<>(); 484 List<XsdAttributeGroup> attributeGroups = new ArrayList<>(); 485 List<XsdElement> elements = new ArrayList<>(); 486 XsdGroup group = null; 487 for (XsdTag tag : state.tags) { 488 if (tag == null) continue; 489 if (tag instanceof XsdAttribute) { 490 attributes.add((XsdAttribute) tag); 491 } else if (tag instanceof XsdAttributeGroup) { 492 attributeGroups.add((XsdAttributeGroup) tag); 493 } else if (tag instanceof XsdElement) { 494 elements.add((XsdElement) tag); 495 } else if (tag instanceof XsdGroup) { 496 group = (XsdGroup) tag; 497 } 498 } 499 500 return setDeprecatedAndFinal(new XsdGeneralRestriction(type, attributes, attributeGroups, 501 elements, group), state.deprecated, state.finalValue, state.nullability); 502 } 503 makeGeneralExtension(State state)504 private XsdGeneralExtension makeGeneralExtension(State state) throws XsdParserException { 505 QName base = parseQName(state.attributeMap.get("base")); 506 507 List<XsdAttribute> attributes = new ArrayList<>(); 508 List<XsdAttributeGroup> attributeGroups = new ArrayList<>(); 509 List<XsdElement> elements = new ArrayList<>(); 510 XsdGroup group = null; 511 for (XsdTag tag : state.tags) { 512 if (tag == null) continue; 513 if (tag instanceof XsdAttribute) { 514 attributes.add((XsdAttribute) tag); 515 } else if (tag instanceof XsdAttributeGroup) { 516 attributeGroups.add((XsdAttributeGroup) tag); 517 } else if (tag instanceof XsdElement) { 518 elements.add((XsdElement) tag); 519 } else if (tag instanceof XsdGroup) { 520 group = (XsdGroup) tag; 521 } 522 } 523 return setDeprecatedAndFinal(new XsdGeneralExtension(new XsdType(null, base), attributes, 524 attributeGroups, elements, group), state.deprecated, state.finalValue, 525 state.nullability); 526 } 527 makeSimpleType(State state)528 private XsdSimpleType makeSimpleType(State state) throws XsdParserException { 529 String name = state.attributeMap.get("name"); 530 XsdSimpleType type = null; 531 for (XsdTag tag : state.tags) { 532 if (tag == null) continue; 533 if (tag instanceof XsdList) { 534 type = new XsdList(name, ((XsdList) tag).getItemType()); 535 } else if (tag instanceof XsdGeneralRestriction) { 536 type = new XsdRestriction(name, ((XsdGeneralRestriction) tag).getBase(), null); 537 } else if (tag instanceof XsdEnumRestriction) { 538 if (name == null) { 539 throw new XsdParserException( 540 "The name of simpleType for enumeration must be set."); 541 } 542 type = new XsdRestriction(name, ((XsdEnumRestriction) tag).getBase(), 543 ((XsdEnumRestriction) tag).getEnums()); 544 enumTags.add(type); 545 } else if (tag instanceof XsdUnion) { 546 type = new XsdUnion(name, ((XsdUnion) tag).getMemberTypes()); 547 } 548 } 549 return setDeprecatedAndFinal(type, state.deprecated, state.finalValue, state.nullability); 550 } 551 makeSimpleTypeList(State state)552 private XsdList makeSimpleTypeList(State state) throws XsdParserException { 553 QName itemTypeName = parseQName(state.attributeMap.get("itemType")); 554 555 XsdType itemType = null; 556 if (itemTypeName != null) { 557 itemType = new XsdType(null, itemTypeName); 558 } 559 for (XsdTag tag : state.tags) { 560 if (tag == null) continue; 561 if (tag instanceof XsdType) { 562 itemType = (XsdType) tag; 563 } 564 } 565 return setDeprecatedAndFinal(new XsdList(null, itemType), state.deprecated, 566 state.finalValue, state.nullability); 567 } 568 makeSimpleTypeUnion(State state)569 private XsdUnion makeSimpleTypeUnion(State state) throws XsdParserException { 570 List<QName> memberTypeNames = parseQNames(state.attributeMap.get("memberTypes")); 571 List<XsdType> memberTypes = memberTypeNames.stream().map( 572 ref -> new XsdType(null, ref)).collect(Collectors.toList()); 573 574 for (XsdTag tag : state.tags) { 575 if (tag == null) continue; 576 if (tag instanceof XsdType) { 577 memberTypes.add((XsdType) tag); 578 } 579 } 580 581 return setDeprecatedAndFinal(new XsdUnion(null, memberTypes), state.deprecated, 582 state.finalValue, state.nullability); 583 } 584 makeSequence(State state)585 private static List<XsdTag> makeSequence(State state) throws XsdParserException { 586 String minOccurs = state.attributeMap.get("minOccurs"); 587 String maxOccurs = state.attributeMap.get("maxOccurs"); 588 589 if (minOccurs != null || maxOccurs != null) { 590 throw new XsdParserException( 591 "minOccurs, maxOccurs options of a sequence is not supported"); 592 } 593 594 List<XsdTag> elementsAndGroup = new ArrayList<>(); 595 for (XsdTag tag : state.tags) { 596 if (tag == null) continue; 597 if (tag instanceof XsdElement) { 598 if (maxOccurs != null && (maxOccurs.equals("unbounded") 599 || Integer.parseInt(maxOccurs) > 1)) { 600 ((XsdElement)tag).setMultiple(true); 601 } 602 elementsAndGroup.add(tag); 603 } else if (tag instanceof XsdGroup) { 604 elementsAndGroup.add(tag); 605 } 606 } 607 return elementsAndGroup; 608 } 609 makeChoice(State state)610 private static List<XsdTag> makeChoice(State state) throws XsdParserException { 611 String maxOccurs = state.attributeMap.get("maxOccurs"); 612 List<XsdTag> elementsAndGroup = new ArrayList<>(); 613 614 for (XsdTag tag : state.tags) { 615 if (tag == null) continue; 616 if (tag instanceof XsdElement) { 617 if (maxOccurs != null && (maxOccurs.equals("unbounded") 618 || Integer.parseInt(maxOccurs) > 1)) { 619 ((XsdElement)tag).setMultiple(true); 620 } 621 XsdElement element = (XsdElement)tag; 622 elementsAndGroup.add((XsdTag) setDeprecatedAndFinal(new XsdChoice(element.getName(), 623 element.getRef(), element.getType(), element.isMultiple()), 624 element.isDeprecated(), element.isFinalValue(), element.getNullability())); 625 } else if (tag instanceof XsdGroup) { 626 elementsAndGroup.add(tag); 627 } 628 } 629 return elementsAndGroup; 630 } 631 makeAll(State state)632 private static List<XsdElement> makeAll(State state) throws XsdParserException { 633 List<XsdElement> elements = new ArrayList<>(); 634 for (XsdTag tag : state.tags) { 635 if (tag == null) continue; 636 if (tag instanceof XsdElement) { 637 XsdElement element = (XsdElement)tag; 638 elements.add(setDeprecatedAndFinal(new XsdAll(element.getName(), element.getRef(), 639 element.getType(), element.isMultiple()), element.isDeprecated(), 640 element.isFinalValue(), element.getNullability())); 641 } 642 } 643 return elements; 644 } 645 makeEnumeration(State state)646 private XsdEnumeration makeEnumeration(State state) throws XsdParserException { 647 String value = state.attributeMap.get("value"); 648 return setDeprecatedAndFinal(new XsdEnumeration(value), state.deprecated, 649 state.finalValue, state.nullability); 650 } 651 makeEnumRestriction(State state)652 private XsdEnumRestriction makeEnumRestriction(State state) throws XsdParserException { 653 QName base = parseQName(state.attributeMap.get("base")); 654 655 XsdType type = null; 656 if (base != null) { 657 type = new XsdType(null, base); 658 } 659 List<XsdEnumeration> enums = new ArrayList<>(); 660 for (XsdTag tag : state.tags) { 661 if (tag == null) continue; 662 if (tag instanceof XsdEnumeration) { 663 enums.add((XsdEnumeration) tag); 664 } 665 } 666 667 return setDeprecatedAndFinal(new XsdEnumRestriction(type, enums), state.deprecated, 668 state.finalValue, state.nullability); 669 } 670 addInclude(State state)671 private void addInclude(State state) throws XsdParserException { 672 String fileName = state.attributeMap.get("schemaLocation"); 673 includeList.add(fileName); 674 } 675 isDeprecated(Map<String, String> attributeMap,List<XsdTag> tags, boolean deprecated)676 private boolean isDeprecated(Map<String, String> attributeMap,List<XsdTag> tags, 677 boolean deprecated) throws XsdParserException { 678 String name = attributeMap.get("name"); 679 if ("Deprecated".equals(name)) { 680 return true; 681 } 682 return deprecated; 683 } 684 isFinalValue(Map<String, String> attributeMap,List<XsdTag> tags, boolean finalValue)685 private boolean isFinalValue(Map<String, String> attributeMap,List<XsdTag> tags, 686 boolean finalValue) throws XsdParserException { 687 String name = attributeMap.get("name"); 688 if ("final".equals(name)) { 689 return true; 690 } 691 return finalValue; 692 } 693 getNullability(Map<String, String> attributeMap,List<XsdTag> tags, Nullability nullability)694 private Nullability getNullability(Map<String, String> attributeMap,List<XsdTag> tags, 695 Nullability nullability) throws XsdParserException { 696 String name = attributeMap.get("name"); 697 if ("nullable".equals(name)) { 698 return Nullability.NULLABLE; 699 } else if ("nonnull".equals(name)) { 700 return Nullability.NON_NULL; 701 } 702 return nullability; 703 } 704 setDeprecatedAndFinal(T tag, boolean deprecated, boolean finalValue, Nullability nullability)705 private static <T extends XsdTag> T setDeprecatedAndFinal(T tag, boolean deprecated, 706 boolean finalValue, Nullability nullability) { 707 if (tag != null) { 708 tag.setDeprecated(deprecated); 709 tag.setFinalValue(finalValue); 710 tag.setNullability(nullability); 711 } 712 return tag; 713 } 714 } 715