Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.regnosys.rosetta.translate.datamodel.xsd.BeansXsdParser Maven / Gradle / Ivy
package com.regnosys.rosetta.translate.datamodel.xsd;
import static org.apache.xmlbeans.SchemaType.BTC_ANY_URI;
import static org.apache.xmlbeans.SchemaType.BTC_BASE_64_BINARY;
import static org.apache.xmlbeans.SchemaType.BTC_BOOLEAN;
import static org.apache.xmlbeans.SchemaType.BTC_DATE;
import static org.apache.xmlbeans.SchemaType.BTC_DATE_TIME;
import static org.apache.xmlbeans.SchemaType.BTC_DECIMAL;
import static org.apache.xmlbeans.SchemaType.BTC_DOUBLE;
import static org.apache.xmlbeans.SchemaType.BTC_DURATION;
import static org.apache.xmlbeans.SchemaType.BTC_FLOAT;
import static org.apache.xmlbeans.SchemaType.BTC_G_DAY;
import static org.apache.xmlbeans.SchemaType.BTC_G_MONTH;
import static org.apache.xmlbeans.SchemaType.BTC_G_MONTH_DAY;
import static org.apache.xmlbeans.SchemaType.BTC_G_YEAR;
import static org.apache.xmlbeans.SchemaType.BTC_G_YEAR_MONTH;
import static org.apache.xmlbeans.SchemaType.BTC_HEX_BINARY;
import static org.apache.xmlbeans.SchemaType.BTC_ID;
import static org.apache.xmlbeans.SchemaType.BTC_IDREF;
import static org.apache.xmlbeans.SchemaType.BTC_INTEGER;
import static org.apache.xmlbeans.SchemaType.BTC_NON_NEGATIVE_INTEGER;
import static org.apache.xmlbeans.SchemaType.BTC_NORMALIZED_STRING;
import static org.apache.xmlbeans.SchemaType.BTC_NOTATION;
import static org.apache.xmlbeans.SchemaType.BTC_POSITIVE_INTEGER;
import static org.apache.xmlbeans.SchemaType.BTC_QNAME;
import static org.apache.xmlbeans.SchemaType.BTC_STRING;
import static org.apache.xmlbeans.SchemaType.BTC_TIME;
import static org.apache.xmlbeans.SchemaType.BTC_TOKEN;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.xml.namespace.QName;
import org.apache.xmlbeans.QNameSet;
import org.apache.xmlbeans.SchemaGlobalElement;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import com.codahale.metrics.Timer;
import com.codahale.metrics.Timer.Context;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.regnosys.rosetta.common.util.UrlUtils;
import com.regnosys.rosetta.translate.IngesterGenerator;
import com.regnosys.rosetta.translate.datamodel.Attribute;
import com.regnosys.rosetta.translate.datamodel.AttributeImpl;
import com.regnosys.rosetta.translate.datamodel.Cardinality;
import com.regnosys.rosetta.translate.datamodel.Entity;
import com.regnosys.rosetta.translate.datamodel.EntityImpl;
import com.regnosys.rosetta.translate.datamodel.ModelParser;
import com.regnosys.rosetta.translate.datamodel.NamespaceName;
import com.regnosys.rosetta.translate.datamodel.Schema;
import com.regnosys.rosetta.translate.datamodel.SimpleType;
public class BeansXsdParser implements ModelParser {
private Map basicTypes = basicTypes();
@Override
public Schema parseModel(URL input) {
try {
Timer timer = IngesterGenerator.GENERATOR_METRICS.timer("XSD model parse");
Context time = timer.time();
List objectList = new ArrayList<>();
XmlObject object = XmlObject.Factory.parse(UrlUtils.openURL(input),
new XmlOptions().setDocumentSourceName(input.toString()));
objectList.add(object);
// enabling this to be able to load referenced xsd as streams
XmlOptions options = new XmlOptions();
options.setCompileDownloadUrls();
SchemaTypeSystem sts = XmlBeans.compileXsd(objectList.toArray(new XmlObject[0]),
XmlBeans.getBuiltinTypeSystem(), options);
Map mappedEntities = new HashMap<>();
SchemaGlobalElement[] globalElements = sts.globalElements();
Map> substitutions = findSubstitutions(globalElements);
Collection attributes = Arrays.stream(globalElements)
.map(el -> convert(el, mappedEntities, globalElements, substitutions)).distinct()
.collect(Collectors.toList());
// Careful! Collection can be very large and has caused the Maven
// build to run out of heap
// LOGGER.debug("{}", attributes);
SchemaType[] globalTypes = sts.globalTypes();
Arrays.stream(globalTypes)
.forEach(gt -> getOrCreateEntity(mappedEntities, globalElements, gt, substitutions));
Collection globalEntities = attributes.stream().map(a -> a.getType()).collect(Collectors.toList());
time.stop();
return new Schema(attributes, globalEntities);
} catch (XmlException | IOException e) {
throw new RuntimeException("Error parsing input xsd file", e);
}
}
private Attribute convert(SchemaGlobalElement el, Map mappedEntities,
SchemaGlobalElement[] globalElements, Map> substitutions) {
QName name = el.getName();
String localName = name.getLocalPart();
SchemaType type = el.getType();
Entity entity = getOrCreateEntity(mappedEntities, globalElements, type, substitutions);
Cardinality card = el.getMaxOccurs() == null || el.getMaxOccurs().longValue() <= 1 ? Cardinality.SINGLE
: Cardinality.MULTIPLE;
return new AttributeImpl(localName, card, entity);
}
private Entity createEntity(SchemaType type, Map mappedEntities,
SchemaGlobalElement[] globalElements, Map> substitutions) {
Entity parent = null;
if (!type.isBuiltinType()) {
parent = getOrCreateEntity(mappedEntities, globalElements, type.getBaseType(), substitutions);
}
QName name = type.getName();
if (name == null) {
// this type is defined without its own name inside an element
// use the elements name
name = type.getContainerField().getName();
}
NamespaceName ns = new NamespaceName(name.getNamespaceURI(), name.getLocalPart());
/*
* || type.getBuiltinTypeCode()>0 || type.isSimpleType()
*/
return new EntityImpl(ns, parent, type.getSimpleVariety() == 1);
}
private Entity populateEntity(SchemaType type, Map mappedEntities,
SchemaGlobalElement[] globalElements, Entity entity,
Map> substitutions) {
List attributes = entity.getAttributes();
if (type.hasElementWildcards()) {
addWildCardAttributes(attributes, type.qnameSetForWildcardElements(), mappedEntities, globalElements,
substitutions);
}
SchemaProperty[] elementProperties = type.getElementProperties();
for (SchemaProperty prop : elementProperties) {
Collection subs = substitutions.get(prop.getName());
if (subs != null) {
subs.forEach(sge -> attributes.add(convert(sge, mappedEntities, globalElements, substitutions)));
}
attributes.add(convert(prop, mappedEntities, globalElements, substitutions));
}
SchemaProperty[] attributeProperties = type.getAttributeProperties();
for (SchemaProperty att : attributeProperties) {
attributes.add(convert(att, mappedEntities, globalElements, substitutions));
}
return entity;
}
private Attribute convert(SchemaProperty prop, Map mappedEntities,
SchemaGlobalElement[] globalElements, Map> substitutions) {
String name = prop.getName().getLocalPart();
Entity type = getOrCreateEntity(mappedEntities, globalElements, prop.getType(), substitutions);
Cardinality card = prop.getMaxOccurs() == null || prop.getMaxOccurs().longValue() > 1 ? Cardinality.MULTIPLE
: Cardinality.SINGLE;
return new AttributeImpl(name, card, type);
}
private void addWildCardAttributes(List attributes, QNameSet wildcards,
Map mappedEntities, SchemaGlobalElement[] globalElements,
Map> substitutions) {
for (SchemaGlobalElement el : globalElements) {
if (wildcards.contains(el.getName())) {
attributes.add(convert(el, mappedEntities, globalElements, substitutions));
}
}
}
private Entity getOrCreateEntity(Map mappedEntities, SchemaGlobalElement[] globalElements,
SchemaType type, Map> substitutions) {
Entity ent = mappedEntities.get(type);
if (type.isSimpleType()) {
Integer typeNum = type.getBuiltinTypeCode();
ent = basicTypes.get(typeNum);
}
if (ent == null) {
ent = createEntity(type, mappedEntities, globalElements, substitutions);
mappedEntities.put(type, ent);
populateEntity(type, mappedEntities, globalElements, ent, substitutions);
}
return ent;
}
private Map> findSubstitutions(SchemaGlobalElement[] globalElements) {
List globalElementsWithSubstitutionGroup = Arrays.stream(globalElements)
.filter(e -> e.substitutionGroup() != null).collect(Collectors.toList());
Multimap substitutionsMultimap = ArrayListMultimap.create();
globalElementsWithSubstitutionGroup.stream().map(SchemaGlobalElement::substitutionGroup).forEach(
e -> Arrays.stream(e.substitutionGroupMembers()).forEach(qName -> substitutionsMultimap.put(qName, e)));
Map> substitutionsMap = substitutionsMultimap.asMap();
globalElementsWithSubstitutionGroup.stream()
.forEach(e -> substitutionsMultimap.put(e.substitutionGroup().getName(), e));
return substitutionsMap;
}
private static Map basicTypes() {
return ImmutableMap.builder().put(BTC_STRING, SimpleType.stringType("string"))
.put(BTC_BOOLEAN, SimpleType.booleanType("boolean"))
.put(BTC_BASE_64_BINARY, SimpleType.stringType("base64Binary"))
.put(BTC_HEX_BINARY, SimpleType.stringType("hexBinary")).put(BTC_FLOAT, SimpleType.decimalType("float"))
.put(BTC_DECIMAL, SimpleType.decimalType("decimal")).put(BTC_DOUBLE, SimpleType.decimalType("float"))
.put(BTC_ANY_URI, SimpleType.stringType("anyURI")).put(BTC_QNAME, SimpleType.stringType("QName"))
.put(BTC_NOTATION, SimpleType.stringType("NOTATION"))
.put(BTC_DURATION, SimpleType.stringType("duration"))
.put(BTC_DATE_TIME, SimpleType.dateTimeType("dateTime")).put(BTC_TIME, SimpleType.timeType("time"))
.put(BTC_DATE, SimpleType.dateType("date")).put(BTC_G_YEAR_MONTH, SimpleType.dateType("gYearMonth"))
.put(BTC_G_YEAR, SimpleType.dateType("gYear")).put(BTC_G_MONTH_DAY, SimpleType.dateType("gMonthDay"))
.put(BTC_G_DAY, SimpleType.dateType("gDay")).put(BTC_G_MONTH, SimpleType.dateType("gMonth"))
.put(BTC_INTEGER, SimpleType.intType("integer"))
.put(BTC_POSITIVE_INTEGER, SimpleType.intType("positiveInteger"))
.put(BTC_NON_NEGATIVE_INTEGER, SimpleType.intType("nonNegativeInteger"))
.put(BTC_NORMALIZED_STRING, SimpleType.stringType("normalizedString"))
.put(BTC_TOKEN, SimpleType.stringType("token")).put(BTC_ID, SimpleType.stringType("ID"))
.put(BTC_IDREF, SimpleType.stringType("IDREF")).build();
}
}