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