diff --git a/contrib/format-xml/pom.xml b/contrib/format-xml/pom.xml
index d32c38df37a..6c253df20ca 100644
--- a/contrib/format-xml/pom.xml
+++ b/contrib/format-xml/pom.xml
@@ -18,7 +18,8 @@
limitations under the License.
-->
-
+
4.0.0
@@ -36,7 +37,16 @@
drill-java-exec
${project.version}
-
+
+ org.apache.ws.xmlschema
+ xmlschema-core
+ 2.3.0
+
+
+ org.apache.ws.xmlschema
+ xmlschema-walker
+ 2.3.0
+
org.apache.drill.exec
@@ -81,4 +91,4 @@
-
\ No newline at end of file
+
diff --git a/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/XMLReader.java b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/XMLReader.java
index fac7b11fead..8d1fb59ff76 100644
--- a/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/XMLReader.java
+++ b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/XMLReader.java
@@ -59,7 +59,7 @@
public class XMLReader implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(XMLReader.class);
- private static final String ATTRIBUTE_MAP_NAME = "attributes";
+ public static final String ATTRIBUTE_MAP_NAME = "attributes";
private final Stack fieldNameStack;
private final Stack rowWriterStack;
diff --git a/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaUtils.java b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaUtils.java
new file mode 100644
index 00000000000..194f640a9a1
--- /dev/null
+++ b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaUtils.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.drill.exec.store.xml.xsd;
+
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.exec.record.metadata.SchemaBuilder;
+import org.apache.drill.exec.record.metadata.TupleMetadata;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import org.apache.ws.commons.schema.XmlSchema;
+import org.apache.ws.commons.schema.XmlSchemaCollection;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+
+import org.apache.ws.commons.schema.XmlSchemaObject;
+import org.apache.ws.commons.schema.walker.XmlSchemaWalker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.transform.stream.StreamSource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+public class DrillXSDSchemaUtils {
+ private static final MinorType DEFAULT_TYPE = MinorType.VARCHAR;
+ private static final Logger logger = LoggerFactory.getLogger(DrillXSDSchemaUtils.class);
+
+ /**
+ * This map maps the data types defined by the XSD definition to Drill data types.
+ */
+ public static final ImmutableMap XML_TYPE_MAPPINGS = ImmutableMap.builder()
+ .put("BASE64BINARY", MinorType.VARBINARY)
+ .put("BOOLEAN", MinorType.BIT)
+ .put("DATE", MinorType.DATE)
+ .put("DATETIME", MinorType.TIMESTAMP)
+ .put("DECIMAL", MinorType.VARDECIMAL)
+ .put("DOUBLE", MinorType.FLOAT8)
+ .put("DURATION", MinorType.INTERVAL)
+ .put("FLOAT", MinorType.FLOAT4)
+ .put("HEXBINARY", MinorType.VARBINARY)
+ .put("STRING", MinorType.VARCHAR)
+ .put("TIME", MinorType.TIME)
+ .build();
+
+ /**
+ * This function is only used for testing, but accepts a XSD file as input rather than a {@link InputStream}
+ * @param filename A {@link String} containing an XSD file.
+ * @return A {@link TupleMetadata} containing a Drill representation of the XSD schema.
+ * @throws IOException If anything goes wrong or the file is not found.
+ */
+ @VisibleForTesting
+ public static TupleMetadata getSchema(String filename) throws IOException {
+ InputStream inputStream = Files.newInputStream(Paths.get(filename));
+ return processSchema(inputStream);
+ }
+
+ /**
+ * Returns a {@link TupleMetadata} of the schema from an XSD file from an InputStream.
+ * @param inputStream A {@link InputStream} containing an XSD file.
+ * @return A {@link TupleMetadata} of the schema from the XSD file.
+ */
+ public static TupleMetadata getSchema(InputStream inputStream) {
+ return processSchema(inputStream);
+ }
+
+ private static TupleMetadata processSchema(InputStream inputStream) {
+ XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
+ schemaCollection.read(new StreamSource(inputStream));
+
+ DrillXSDSchemaVisitor schemaVisitor = new DrillXSDSchemaVisitor(new SchemaBuilder());
+ XmlSchema[] schemas = schemaCollection.getXmlSchemas();
+ XmlSchemaWalker walker = new XmlSchemaWalker(schemaCollection, schemaVisitor);
+
+ // Walk all the schemata.
+ for (XmlSchema schema : schemas) {
+ for (XmlSchemaObject schemaObject : schema.getItems()) {
+ if (schemaObject instanceof XmlSchemaElement) {
+ walker.walk((XmlSchemaElement) schemaObject);
+ }
+ }
+ }
+ return schemaVisitor.getDrillSchema();
+ }
+
+ /**
+ * Returns a {@link MinorType} of the corresponding XML Data Type. Defaults to VARCHAR if unknown
+ * @param xmlType A String of the XML Data Type
+ * @return A {@link MinorType} of the Drill data type.
+ */
+ public static MinorType getDrillDataType(String xmlType) {
+ try {
+ MinorType type = DrillXSDSchemaUtils.XML_TYPE_MAPPINGS.get(xmlType);
+ if (type == null) {
+ return DEFAULT_TYPE;
+ } else {
+ return type;
+ }
+ } catch (NullPointerException e) {
+ logger.warn("Unknown data type found in XSD reader: {}. Returning VARCHAR.", xmlType);
+ return DEFAULT_TYPE;
+ }
+ }
+}
diff --git a/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaVisitor.java b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaVisitor.java
new file mode 100644
index 00000000000..83fcf270e5c
--- /dev/null
+++ b/contrib/format-xml/src/main/java/org/apache/drill/exec/store/xml/xsd/DrillXSDSchemaVisitor.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.drill.exec.store.xml.xsd;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.drill.common.exceptions.UserException;
+import org.apache.drill.common.types.TypeProtos.DataMode;
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.exec.record.metadata.MapBuilder;
+import org.apache.drill.exec.record.metadata.SchemaBuilder;
+import org.apache.drill.exec.record.metadata.TupleMetadata;
+import org.apache.ws.commons.schema.XmlSchemaAll;
+import org.apache.ws.commons.schema.XmlSchemaAny;
+import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
+import org.apache.ws.commons.schema.XmlSchemaChoice;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.walker.XmlSchemaAttrInfo;
+import org.apache.ws.commons.schema.walker.XmlSchemaTypeInfo;
+import org.apache.ws.commons.schema.walker.XmlSchemaVisitor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import static org.apache.drill.exec.store.xml.XMLReader.ATTRIBUTE_MAP_NAME;
+
+
+/**
+ * This class transforms an XSD schema into a Drill Schema.
+ */
+public class DrillXSDSchemaVisitor implements XmlSchemaVisitor {
+ private static final Logger logger = LoggerFactory.getLogger(DrillXSDSchemaVisitor.class);
+ private SchemaBuilder builder;
+ private MapBuilder currentMapBuilder;
+ private int nestingLevel;
+
+ /**
+ * Table to hold attribute info as it is traversed. We construct the
+ * attributes map for all the attributes when the walker tells us we're
+ * at the end of all the element decl's attributes.
+ *
+ * Uses {@link LinkedHashMap} to ensure deterministic behavior which facilitates testability.
+ * In this situation it probably does not matter, but it's a good practice.
+ */
+ private HashMap> attributeInfoTable =
+ new LinkedHashMap<>();
+
+ public DrillXSDSchemaVisitor(SchemaBuilder builder) {
+ this.builder = builder;
+ this.nestingLevel = 0;
+ }
+
+ /**
+ * Returns a {@link TupleMetadata} representation of the schema contained in an XSD file. This method should only
+ * be called after the walk method of XmlSchemaWalker has been called.
+ * @return A {@link TupleMetadata} representation of the XSD schema.
+ */
+ public TupleMetadata getDrillSchema() {
+ return builder.build();
+ }
+
+ /**
+ * Handles global elements establishing a map for the child elements and attributes (if any).
+ *
+ * TBD: Does not handle case where multiple elements have the same name as in:
+ * {@code
+ *
+ *
+ *
+ * }
+ * There is also the case where they are ambiguous unless namespaces are used:
+ * {@code
+ *
+ *
+ * }
+ */
+ @Override
+ public void onEnterElement(XmlSchemaElement xmlSchemaElement, XmlSchemaTypeInfo xmlSchemaTypeInfo, boolean b) {
+ assert nestingLevel >= 0;
+ boolean isRepeated = xmlSchemaElement.getMaxOccurs() > 1;
+ String fieldName = xmlSchemaElement.getName();
+ //
+ // Note that the child name in constant ATTRIBUTE_MAP_NAME is reserved and cannot be used
+ // by any child element.
+ // TODO: There are many other things we want to refuse. E.g., if there are mixed content elements.
+ //
+ if (StringUtils.equals(ATTRIBUTE_MAP_NAME, fieldName)) {
+ throw UserException.dataReadError()
+ .message("XML schema contains a field named " + ATTRIBUTE_MAP_NAME + " which is a " +
+ "reserved word for XML schemata.")
+ .build(logger);
+ }
+
+ if (xmlSchemaTypeInfo.getType().name().equalsIgnoreCase("COMPLEX")) {
+ // Start a map here.
+ logger.debug("Starting map {}.", xmlSchemaElement.getName());
+
+ // There are two cases, if the element belongs to a complex object or not. If it does not, the currentMapBuilder
+ // will be null. We therefore have to get a MapBuilder object from the SchemaBuilder and save it as the
+ // current MapBuilder.
+ //
+ // In either case, we also need to determine whether the element in question is an array or not. If it is,
+ // we set the data mode to repeated.
+ if (currentMapBuilder == null) {
+ // global element declaration
+ assert nestingLevel == 0;
+ assert xmlSchemaElement.getMaxOccurs() == 1;
+ assert xmlSchemaElement.getMinOccurs() == 1;
+ currentMapBuilder = builder.addMap(fieldName);
+ } else {
+ // local element decl or element reference
+ // If the current schema element is repeated (IE an array) record it as such.
+ if (isRepeated) {
+ currentMapBuilder = currentMapBuilder.addMapArray(fieldName);
+ } else {
+ currentMapBuilder = currentMapBuilder.addMap(fieldName);
+ }
+ }
+ nestingLevel++;
+ } else {
+ // If the field is a simple type, simply add it to the schema.
+ MinorType dataType = DrillXSDSchemaUtils.getDrillDataType(xmlSchemaTypeInfo.getBaseType().name());
+ if (currentMapBuilder == null) {
+ // global element decl case
+ // Now, strictly speaking an XML document cannot just be a single simple type
+ // element, but for testing reasons, it is convenient to allow this.
+ // If the current map is null, it means we are not in a nested construct
+ assert nestingLevel == 0;
+ assert xmlSchemaElement.getMaxOccurs() == 1;
+ assert xmlSchemaElement.getMinOccurs() == 1;
+ builder.addNullable(fieldName, dataType);
+ } else {
+ // Otherwise, write to the current map builder
+ if (isRepeated) {
+ currentMapBuilder.add(fieldName, dataType, DataMode.REPEATED);
+ logger.debug("Adding array {}.", xmlSchemaElement.getName());
+ } else {
+ currentMapBuilder.addNullable(fieldName, dataType);
+ logger.debug("Adding field {}.", xmlSchemaElement.getName());
+ }
+ }
+ // For simple types, nestingLevel is not increased.
+ }
+ }
+
+ @Override
+ public void onExitElement(XmlSchemaElement xmlSchemaElement, XmlSchemaTypeInfo xmlSchemaTypeInfo, boolean b) {
+ assert nestingLevel >= 0;
+ if (xmlSchemaTypeInfo.getType().name().equalsIgnoreCase("COMPLEX")) {
+ assert nestingLevel >= 1;
+ // This section closes out a nested object. If the nesting level is greater than 0, we make a call to
+ // resumeMap which gets us the parent map. If we have arrived at the root level, then we need to get a
+ // schema builder and clear out the currentMapBuilder by setting it to null.
+ assert currentMapBuilder != null;
+ logger.debug("Ending map {}.", xmlSchemaElement.getName());
+ if (nestingLevel > 1) {
+ currentMapBuilder = currentMapBuilder.resumeMap();
+ } else {
+ builder = currentMapBuilder.resumeSchema();
+ currentMapBuilder = null;
+ }
+ nestingLevel--;
+ }
+ }
+
+ /**
+ * This method just gathers the elements up into a table.
+ */
+ @Override
+ public void onVisitAttribute(XmlSchemaElement xmlSchemaElement, XmlSchemaAttrInfo xmlSchemaAttrInfo) {
+ List list =
+ attributeInfoTable.getOrDefault(xmlSchemaElement, new ArrayList<>());
+ list.add(xmlSchemaAttrInfo);
+ attributeInfoTable.put(xmlSchemaElement, list);
+ }
+
+ /**
+ * Called for each element decl once all its attributes have been previously
+ * processed by onVisitAttribute.
+ *
+ * Constructs the map for the special attributes child element of each element.
+ * Note: does not construct an attribute child map if there are no attributes.
+ *
+ * Only supports attributes with no-namespace on their qnames.
+ * Or rather, ignores namespaces. Only deals with local names.
+ *
+ * TBD: needs to check for attributes with namespaced names
+ * and at minimum reject them.
+ */
+ @Override
+ public void onEndAttributes(XmlSchemaElement xmlSchemaElement, XmlSchemaTypeInfo xmlSchemaTypeInfo) {
+ List attrs = attributeInfoTable.get(xmlSchemaElement);
+ attributeInfoTable.remove(xmlSchemaElement); // clean up the table
+ // the currentMapBuilder can be null for a global element decl of simple type.
+ if (attrs != null && currentMapBuilder != null) {
+ logger.debug("Starting map {}.", xmlSchemaElement.getName() + "/attributes");
+ assert attrs.size() >= 1;
+ currentMapBuilder = currentMapBuilder.addMap(ATTRIBUTE_MAP_NAME);
+ attrs.forEach(attr -> {
+ String attrName = attr.getAttribute().getName();
+ MinorType dataType = DrillXSDSchemaUtils.getDrillDataType(attr.getType().getBaseType().name());
+ currentMapBuilder = currentMapBuilder.addNullable(attrName, dataType);
+ logger.debug("Adding attribute {}.", attrName);
+
+ });
+ logger.debug("Ending map {}.", xmlSchemaElement.getName() + "/attributes");
+ currentMapBuilder = currentMapBuilder.resumeMap();
+ }
+ }
+
+ @Override
+ public void onEnterSubstitutionGroup(XmlSchemaElement xmlSchemaElement) {
+ // no op
+ }
+
+ @Override
+ public void onExitSubstitutionGroup(XmlSchemaElement xmlSchemaElement) {
+ // no op
+ }
+
+ @Override
+ public void onEnterAllGroup(XmlSchemaAll xmlSchemaAll) {
+ // no op
+ }
+
+ @Override
+ public void onExitAllGroup(XmlSchemaAll xmlSchemaAll) {
+ // no op
+ }
+
+ @Override
+ public void onEnterChoiceGroup(XmlSchemaChoice xmlSchemaChoice) {
+ // no op
+ }
+
+ @Override
+ public void onExitChoiceGroup(XmlSchemaChoice xmlSchemaChoice) {
+ // no op
+ }
+
+ @Override
+ public void onEnterSequenceGroup(XmlSchemaSequence xmlSchemaSequence) {
+ // no op
+ }
+
+ @Override
+ public void onExitSequenceGroup(XmlSchemaSequence xmlSchemaSequence) {
+ // no op
+ }
+
+ @Override
+ public void onVisitAny(XmlSchemaAny xmlSchemaAny) {
+ // no op
+ }
+
+ @Override
+ public void onVisitAnyAttribute(XmlSchemaElement xmlSchemaElement, XmlSchemaAnyAttribute xmlSchemaAnyAttribute) {
+ // no op
+ }
+}
diff --git a/contrib/format-xml/src/test/java/org/apache/drill/exec/store/xml/xsd/TestXSDSchema.java b/contrib/format-xml/src/test/java/org/apache/drill/exec/store/xml/xsd/TestXSDSchema.java
new file mode 100644
index 00000000000..58868f163f3
--- /dev/null
+++ b/contrib/format-xml/src/test/java/org/apache/drill/exec/store/xml/xsd/TestXSDSchema.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.drill.exec.store.xml.xsd;
+
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.util.DrillFileUtils;
+import org.apache.drill.exec.record.metadata.MapBuilder;
+import org.apache.drill.exec.record.metadata.SchemaBuilder;
+import org.apache.drill.exec.record.metadata.TupleMetadata;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestXSDSchema {
+
+ @Test
+ public void testSimpleXSD() throws Exception {
+ File simple_xsd = DrillFileUtils.getResourceAsFile("/xsd/simple.xsd");
+ TupleMetadata schema = DrillXSDSchemaUtils.getSchema(simple_xsd.getPath());
+
+ TupleMetadata expectedSchema = new SchemaBuilder()
+ .addMap("shiporder")
+ .addMap("attributes")
+ .addNullable("orderid", MinorType.VARCHAR)
+ .resumeMap()
+ .addNullable("orderperson", MinorType.VARCHAR)
+ .addMap("shipto")
+ .addNullable("name", MinorType.VARCHAR)
+ .addNullable("address", MinorType.VARCHAR)
+ .addNullable("city", MinorType.VARCHAR)
+ .addNullable("country", MinorType.VARCHAR)
+ .resumeMap()
+ .addMapArray("item")
+ .addNullable("title", MinorType.VARCHAR)
+ .addNullable("note", MinorType.VARCHAR)
+ .addNullable("quantity", MinorType.VARDECIMAL)
+ .addNullable("price", MinorType.VARDECIMAL)
+ .resumeMap()
+ .resumeSchema()
+ .buildSchema();
+ assertTrue(expectedSchema.isEquivalent(schema));
+ }
+
+
+ @Test
+ public void testComplexXSD() throws Exception {
+ File complex_xsd = DrillFileUtils.getResourceAsFile("/xsd/complex.xsd");
+ TupleMetadata schema = DrillXSDSchemaUtils.getSchema(complex_xsd.getPath());
+
+ SchemaBuilder sb1 = new SchemaBuilder();
+ MapBuilder sb2 = sb1
+ .addNullable("comment", MinorType.VARCHAR) // global comment element
+ .addMap("infoType")
+ .addMap("attributes")
+ .addNullable("kind", MinorType.VARCHAR)
+ .resumeMap()
+ .resumeSchema()
+ .addMap("purchaseOrder") // global purchaseOrder element
+ .addMap("attributes")
+ .addNullable("orderDate", MinorType.DATE) // an attribute
+ .addNullable("confirmDate", MinorType.DATE) // an attribute
+ .resumeMap()
+ .addMap("shipTo")
+ .addMap("attributes")
+ .addNullable("country", MinorType.VARCHAR) // an attribute
+ .resumeMap()
+ .addNullable("name", MinorType.VARCHAR)
+ .addNullable("street", MinorType.VARCHAR)
+ .addNullable("city", MinorType.VARCHAR)
+ .addNullable("state", MinorType.VARCHAR)
+ .addNullable("zip", MinorType.VARDECIMAL)
+ .resumeMap(); // end shipTo
+ MapBuilder sb3 = sb2
+ .addMap("billTo")
+ .addMap("attributes")
+ .addNullable("country", MinorType.VARCHAR) // an attribute
+ .resumeMap()
+ .addNullable("name", MinorType.VARCHAR)
+ .addNullable("street", MinorType.VARCHAR)
+ .addNullable("city", MinorType.VARCHAR)
+ .addNullable("state", MinorType.VARCHAR)
+ .addNullable("zip", MinorType.VARDECIMAL)
+ .resumeMap();
+ MapBuilder sb4 = sb3
+ .addNullable("comment", MinorType.VARCHAR)
+ .addMap("items")
+ .addMapArray("item")
+ .addMap("attributes")
+ .addNullable("partNum", MinorType.VARCHAR) // an attribute
+ .resumeMap()
+ .addNullable("productName", MinorType.VARCHAR)
+ .addNullable("quantity", MinorType.VARDECIMAL)
+ .addNullable("USPrice", MinorType.VARDECIMAL)
+ .addNullable("comment", MinorType.VARCHAR)
+ .addNullable("shipDate", MinorType.DATE)
+ .resumeMap() // end item
+ .resumeMap(); // end items
+
+ TupleMetadata expectedSchema = sb4.resumeSchema().build();
+ assertTrue(expectedSchema.isEquivalent(schema));
+ }
+}
diff --git a/contrib/format-xml/src/test/resources/xsd/complex.xsd b/contrib/format-xml/src/test/resources/xsd/complex.xsd
new file mode 100644
index 00000000000..f15b9effaea
--- /dev/null
+++ b/contrib/format-xml/src/test/resources/xsd/complex.xsd
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Purchase order schema for Example.Microsoft.com.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/format-xml/src/test/resources/xsd/simple.xsd b/contrib/format-xml/src/test/resources/xsd/simple.xsd
new file mode 100644
index 00000000000..3eb6e7675f9
--- /dev/null
+++ b/contrib/format-xml/src/test/resources/xsd/simple.xsd
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/exec/jdbc-all/pom.xml b/exec/jdbc-all/pom.xml
index 4ea4f06e3b5..64a2196bab6 100644
--- a/exec/jdbc-all/pom.xml
+++ b/exec/jdbc-all/pom.xml
@@ -33,7 +33,7 @@
"package.namespace.prefix" equals to "oadd.". It can be overridden if necessary within any profile -->
oadd.
- 40500000
+ 44500000
@@ -230,6 +230,14 @@
org.apache.commons
commons-compress
+
+ org.apache.ws.xmlschema
+ xmlschema-core
+
+
+ org.apache.ws.xmlschema
+ xmlschema-walker
+
io.airlift
aircompressor
diff --git a/pom.xml b/pom.xml
index 418885d0ca1..8baa6f7022d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -366,6 +366,7 @@
**/*.sqllog
**/*.sqllog2
**/*.syslog
+ **/*.xsd
**/*.xls
**/*.xlsx
**/*.syslog1
@@ -686,7 +687,7 @@
${maven.multiModuleProjectDirectory}/header
- **/*.accdb
+**/*.accdb
**/*.access_log
**/.asf.yaml
**/*.autotools
@@ -777,6 +778,7 @@
**/*.woff2
**/*.xls
**/*.xlsx
+ **/*.xsd
SLASHSTAR_STYLE