/* * citygml4j - The Open Source Java API for CityGML * https://github.com/citygml4j * * Copyright 2013-2017 Claus Nagel <claus.nagel@gmail.com> * * 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.citygml4j.xml.schema; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import com.sun.xml.xsom.XSAttGroupDecl; import com.sun.xml.xsom.XSAttributeDecl; import com.sun.xml.xsom.XSAttributeUse; import com.sun.xml.xsom.XSComplexType; import com.sun.xml.xsom.XSElementDecl; import com.sun.xml.xsom.XSSchema; import com.sun.xml.xsom.XSSchemaSet; import com.sun.xml.xsom.XSSimpleType; import com.sun.xml.xsom.XSType; public class Schema { final XSSchemaSet schemaSet; final SchemaHandler handler; final XSSchema schema; final String namespaceURI; private final HashMap<String, ElementDecl> uniqueElements; private final HashMap<String, List<ElementDecl>> multipleElements; private final HashMap<ElementDecl, HashMap<String, ElementDecl>> localElements; public Schema(XSSchemaSet schemaSet, String namespaceURI, SchemaHandler handler) { this.schemaSet = schemaSet; this.handler = handler; this.namespaceURI = namespaceURI; schema = schemaSet.getSchema(namespaceURI); if (schema == null) throw new IllegalStateException("no XSSchema associated with the namespace '" + namespaceURI + "'."); uniqueElements = new HashMap<String, ElementDecl>(); multipleElements = new HashMap<String, List<ElementDecl>>(); localElements = new HashMap<ElementDecl, HashMap<String,ElementDecl>>(); } public XSSchema getXSSchema() { return schema; } public String getNamespaceURI() { return namespaceURI; } public XSSchemaSet getXSSchemaSet() { return schemaSet; } public ElementDecl getGlobalElementDecl(String localName) { XSElementDecl decl = schema.getElementDecl(localName); return decl != null ? new ElementDecl(decl, this) : null; } public ElementDecl getElementDecl(String localName, ElementDecl parent) { ElementDecl element = null; HashMap<String, ElementDecl> local = null; if (parent != null) { local = localElements.get(parent); if (local != null) element = local.get(localName); } if (element == null) { List<ElementDecl> candidates = getElementDecls(localName); if (candidates.size() == 1) element = candidates.get(0); else if (parent != null) { List<XSElementDecl> children = parent.getChildElements(); for (ElementDecl candidate : candidates) { if (candidate.isGlobal()) { for (XSElementDecl child : children) { if (child.canBeSubstitutedBy(candidate.getXSElementDecl())) { element = candidate; break; } } if (element != null) break; } else { if (children.contains(candidate.getXSElementDecl())) { element = candidate; break; } } } if (element != null) { if (local == null) { local = new HashMap<String, ElementDecl>(); localElements.put(parent, local); } local.put(localName, element); } } } return element; } public List<ElementDecl> getElementDecls(final String localName) { if (multipleElements.containsKey(localName)) return multipleElements.get(localName); final List<ElementDecl> elements = new ArrayList<ElementDecl>(); ElementDecl element = uniqueElements.get(localName); if (element != null) elements.add(element); else { SchemaWalker schemaWalker = new SchemaWalker() { @Override public void schema(XSSchema schema) { for (XSElementDecl e : schema.getElementDecls().values()) if (shouldWalk() && addToVisited(e)) elementDecl(e); for (XSComplexType t : schema.getComplexTypes().values()) if (shouldWalk() && addToVisited(t)) t.visit(this); } @Override public void elementDecl(XSElementDecl decl) { if (localName.equals(decl.getName()) && schema.getTargetNamespace().equals(decl.getTargetNamespace())) elements.add(new ElementDecl(decl, Schema.this)); if (decl.getType().isLocal() && shouldWalk() && addToVisited(decl.getType())) decl.getType().visit(this); } public void complexType(XSComplexType type) { if (shouldWalk() && addToVisited(type.getContentType())) type.getContentType().visit(this); } @Override public void attGroupDecl(XSAttGroupDecl decl) { } @Override public void attributeDecl(XSAttributeDecl decl) { } @Override public void attributeUse(XSAttributeUse use) { } @Override public void simpleType(XSSimpleType simpleType) { } }; schemaWalker.visit(schema); if (elements.size() > 1) multipleElements.put(localName, elements); else if (elements.size() == 1) uniqueElements.put(localName, elements.get(0)); } return elements; } public boolean haveSameTypeDefinition(List<ElementDecl> elementDecls) { Iterator<ElementDecl> iter = elementDecls.iterator(); ElementDecl first = iter.next(); XSType refType = first.getXSElementDecl().getType(); while (iter.hasNext()) if (iter.next().getXSElementDecl().getType() != refType) return false; return true; } }