SchemaSignature.java
/*
* Copyright © 2026 IKE Network (support@ike.network)
*
* 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 network.ike.plugin.schema;
import javax.xml.XMLConstants;
import java.util.List;
import java.util.Optional;
/**
* The signature an XML Schema declares, read once and held as plain records: the named
* complex types with their base, their documentation, and their argument positions; and
* the named simple types that enumerate values (IKE-Network/ike-issues#1104).
*
* <p>A signature is what a language's abstract syntax is: a finite set of node types,
* each with typed positions. HL7's ELM, the Expression Logical Model of the CQL
* specification, publishes its signature this way in two namespaces, the expression
* nodes and the System types, and a type is identified by its namespace and its name,
* since both namespaces declare an Interval.
*
* @param types the named complex types, in declaration order across the schemas
* @param enumerations the named simple types that restrict a primitive to enumerated values
*/
public record SchemaSignature(List<TypeDefinition> types, List<Enumeration> enumerations) {
/**
* Creates a signature, copying both lists.
*
* @param types the named complex types
* @param enumerations the named enumerations
*/
public SchemaSignature {
types = List.copyOf(types);
enumerations = List.copyOf(enumerations);
}
/**
* Whether a position holds an element, a child in the document's sequence, or an
* attribute, a named value on the element itself.
*/
public enum PositionKind {
/** A child element of the type. */
ELEMENT,
/** An attribute of the type. */
ATTRIBUTE
}
/**
* A reference to a type by namespace and name: a type of the signature, a type of
* another schema the signature refers to, or a primitive of the XML Schema language.
*
* @param namespace the namespace the type is declared in, the XML Schema namespace for
* a primitive
* @param name the type's local name, {@code Expression} or {@code string}
*/
public record TypeReference(String namespace, String name) {
/**
* A reference to an XML Schema primitive, {@code string} or {@code QName}.
*
* @param name the primitive's local name
* @return the reference
*/
public static TypeReference primitive(String name) {
return new TypeReference(XMLConstants.W3C_XML_SCHEMA_NS_URI, name);
}
/**
* Whether this refers to a primitive of the XML Schema language rather than a
* declared type.
*
* @return true for a schema primitive
*/
public boolean isPrimitive() {
return XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(namespace);
}
}
/**
* One argument position of a type: a child element or an attribute, with the type of
* value it holds and how many of them the schema allows.
*
* @param name the position's name as the schema spells it, {@code operand}
* @param kind element or attribute
* @param valueType the type of value the position holds
* @param minimum the fewest values allowed, {@code 0} for optional
* @param maximum the most values allowed, or {@link #UNBOUNDED}
* @param documentation the schema's own description of this position on this type,
* empty when the schema gives none
*/
public record Position(String name, PositionKind kind, TypeReference valueType, int minimum,
int maximum, String documentation) {
/** The maximum recorded for a position the schema leaves unbounded. */
public static final int UNBOUNDED = -1;
}
/**
* One named complex type of the schema.
*
* @param namespace the namespace the type is declared in
* @param name the type's name as the schema spells it, {@code Exists}
* @param base the type it extends, if any; {@code Exists} extends
* {@code UnaryExpression}
* @param isAbstract whether the schema marks the type abstract
* @param documentation the schema's own description, empty when the schema gives none
* @param positions the type's own positions, not including those inherited from
* its base, in schema order
*/
public record TypeDefinition(String namespace, String name, Optional<TypeReference> base,
boolean isAbstract, String documentation, List<Position> positions) {
/**
* Creates a type definition, copying the positions.
*
* @param namespace the namespace
* @param name the type name
* @param base the base type, if any
* @param isAbstract whether abstract
* @param documentation the description
* @param positions the positions
*/
public TypeDefinition {
positions = List.copyOf(positions);
}
/**
* This type as a reference.
*
* @return the reference to this type
*/
public TypeReference reference() {
return new TypeReference(namespace, name);
}
}
/**
* One named simple type that enumerates its values, {@code DateTimePrecision} with
* {@code Year} through {@code Millisecond}.
*
* @param namespace the namespace the enumeration is declared in
* @param name the enumeration's name as the schema spells it
* @param documentation the schema's own description, empty when the schema gives none
* @param values the enumerated values in schema order
*/
public record Enumeration(String namespace, String name, String documentation, List<String> values) {
/**
* Creates an enumeration, copying the values.
*
* @param namespace the namespace
* @param name the enumeration name
* @param documentation the description
* @param values the values
*/
public Enumeration {
values = List.copyOf(values);
}
}
}