Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9c31e39
GML geometry encoder: Use XMLStreamWriter
cportele May 2, 2026
e0c134f
Merge branch 'master' into nas
cportele May 8, 2026
c725682
GML geometry encoder: add USE_SURFACE_RING_CURVE option
cportele May 8, 2026
bd36c6a
GML geometry encoder: emit Surface/PolygonPatch and CompositeCurve fo…
cportele May 9, 2026
52197ad
GML geometry encoder: improve srsName mapping behavior
cportele May 11, 2026
aa5cc2a
GML geometry encoder: add srsName test
cportele May 11, 2026
77a980e
add alias field to feature schema for encoding-time property renaming
cportele May 12, 2026
c1c846b
plumb useAlias flag through encoding pipeline
cportele May 12, 2026
824af10
fix: cascade renames when rebuilding propertyTransformations keys
cportele May 13, 2026
761f243
Merge branch 'master' into nas
cportele May 13, 2026
581067a
refactor: replace useAlias plumbing with a one-shot alias→rename conv…
cportele May 13, 2026
f1a0d14
Merge branch 'master' into nas
cportele May 13, 2026
62f115a
Merge branch 'master' into nas
cportele May 14, 2026
da4163b
Add comma separation for polygon rings
cportele May 14, 2026
a185fdb
Rewrite GML geometry decoder with stack-based context model
cportele May 15, 2026
b7decc9
Add schema-resolved GML decoder for write-path use
cportele May 18, 2026
62432cc
Improve error reporting for CRS transformation failures
cportele May 18, 2026
5e3a920
amend test features
cportele May 18, 2026
5730842
Merge branch 'master' into nas-crud
azahnen Jun 2, 2026
cc5262f
Merge branch 'master' into nas-crud
cportele Jun 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ protected FeatureQueryEncoder<String, QueryOptions> getQueryEncoder() {
new QName(
namespaceNormalizer.getNamespaceURI(namespaceNormalizer.extractURI(name)),
namespaceNormalizer.getLocalName(name));
return new FeatureTokenDecoderGml(
return new FeatureTokenDecoderGmlFromWfs(
namespaces,
ImmutableList.of(qualifiedName),
featureSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@
import javax.xml.stream.XMLStreamException;

/**
* Decodes a streaming WFS response (a {@code wfs:FeatureCollection} of many features) into the
* platform's feature token stream. Path emission uses the qualified XML names directly, on the
* assumption that the consumer keys off XML-shaped paths (e.g. {@code adv:Flurstueck}, {@code
* gml:@id}). For consumers that key off the schema's property-name paths (e.g. the SQL feature
* encoder), use {@link FeatureTokenDecoderGml}.
*
* @author zahnen
*/
public class FeatureTokenDecoderGml
public class FeatureTokenDecoderGmlFromWfs
extends FeatureTokenDecoder<
byte[], FeatureSchema, SchemaMapping, ModifiableContext<FeatureSchema, SchemaMapping>> {

Expand All @@ -59,7 +65,7 @@ public class FeatureTokenDecoderGml
private OptionalInt srsDimension = OptionalInt.empty();
private ModifiableContext<FeatureSchema, SchemaMapping> context;

public FeatureTokenDecoderGml(
public FeatureTokenDecoderGmlFromWfs(
Map<String, String> namespaces,
List<QName> featureTypes,
FeatureSchema featureSchema,
Expand Down Expand Up @@ -122,7 +128,6 @@ private void feedInput(byte[] data) {
}
}

// TODO: single feature or collection
protected boolean advanceParser() {

boolean feedMeMore = false;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 2026 interactive instruments GmbH
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.ii.xtraplatform.features.gml.domain;

import de.ii.xtraplatform.crs.domain.EpsgCrs;
import java.util.List;
import java.util.Map;
import org.immutables.value.Value;

/**
* Reverse profile of the GML output configuration, consumed by the GML decoders on the input path.
* Mirrors the encoding-time options from {@code GmlConfiguration} so that input documents shaped
* like the encoder's output can be decoded losslessly. Defaults are conservative empties; an empty
* profile means the decoder runs without any reverse-mapping behaviour.
*/
@Value.Immutable
public interface FeatureTokenDecoderGmlInputProfile {

/**
* Reverse-mapping from the {@code srsName} value seen on a geometry to the resolved {@link
* EpsgCrs}. Required for input shaped after ALKIS NAS, which uses ADV URN forms such as {@code
* urn:adv:crs:DE_DHDN_3GK2_NW101} that the built-in EPSG / OGC URN parser cannot resolve.
*/
Map<String, EpsgCrs> getSrsNameMappings();

/**
* Optional prefix stripped from the value of {@code gml:id} before it is emitted as the feature
* id token. Empty string means no prefix is stripped.
*/
@Value.Default
default String getGmlIdPrefix() {
return "";
}

/**
* Path-keyed codelist declarations as carried by {@code GmlConfiguration#codelistProperties}.
* Routing of {@code xlink:href} on codelist properties is driven by the {@code FeatureSchema}'s
* own {@code codelist} constraint (analogous to the feature-reference routing driven by the
* schema's {@code FEATURE_REF}/{@code FEATURE_REF_ARRAY} type); this map is kept for completeness
* and future routing decisions that need the path-level mapping.
*/
Map<String, String> getCodelistProperties();

/**
* Reverse of {@code GmlConfiguration#featureRefTemplate}. When set, an incoming {@code
* xlink:href} on a feature-reference property is matched against the template and reduced to the
* bare {@code {{value}}} segment before being emitted as the property value. The template uses
* {@code {{value}}} as the placeholder; everything else is treated literally (e.g. {@code
* urn:adv:oid:{{value}}} on {@code urn:adv:oid:DENW36ALl800005x} yields {@code
* DENW36ALl800005x}). When unset, the href is emitted unchanged.
*/
@Value.Default
default String getFeatureRefTemplate() {
return "";
}

/**
* Reverse of {@code GmlConfiguration#codelistUriTemplate}. When set, an incoming {@code
* xlink:href} on a codelist-valued property is matched against the template (with the schema's
* codelist id substituted for {@code {{codelistId}}}) and reduced to the bare {@code {{value}}}
* segment before being emitted. When unset, the href is emitted unchanged.
*/
@Value.Default
default String getCodelistUriTemplate() {
return "";
}

/**
* Reverse of {@code GmlConfiguration#uomMappings} combined with {@code UomStyle.TEMPLATE}: keys
* are the wire-form {@code uom} attribute values written by the encoder; values are the canonical
* units (matching the {@code unit} declared on the property in the provider schema). The {@code
* uom} attribute itself is not mapped to the feature representation — the canonical unit lives in
* the schema. The decoder reverse-maps the wire value through this map and warns when the result
* does not match the schema's {@code unit}; when no entry matches, the wire value is compared
* directly.
*/
Map<String, String> getUomMappings();

/**
* When {@code true}, the decoder matches an incoming XML element local name against each schema
* property's {@code alias} (falling back to the property name if no alias is set) instead of
* matching against the property name directly. Mirrors the encoder's {@code
* GmlConfiguration#useAlias} flag: the encoder writes the alias as the element local name when
* this is on, so the decoder must look it up the same way.
*/
@Value.Default
default boolean getUseAlias() {
return false;
}

/**
* Reverse of {@code GmlConfiguration#applicationNamespaces}: prefix → URI map of the
* application-defined namespaces the encoder writes into the output. Currently informational —
* the decoder resolves prefixes through the namespace map passed to its constructor (which merges
* predefined namespaces with these); kept here so the input profile carries the full encoder-side
* configuration.
*/
Map<String, String> getApplicationNamespaces();

/**
* Reverse of {@code GmlConfiguration#defaultNamespace}: the prefix declared as the default
* namespace by the encoder. When set, property elements without an explicit {@code prefix:} in
* the schema name/alias and without a {@code objectTypeNamespaces} mapping are expected on the
* wire in this prefix's namespace; the decoder rejects mismatching elements.
*/
@Value.Default
default String getDefaultNamespace() {
return "";
}

/**
* Reverse of {@code GmlConfiguration#objectTypeNamespaces}: maps an object type's name (the
* schema's {@code objectType} value, including the feature type) to the prefix the encoder uses
* for its GML object element <em>and</em> its property elements. The decoder enforces the mapped
* prefix's namespace URI on those property elements; properties with an explicit {@code prefix:}
* in the schema name/alias override the mapping.
*/
Map<String, String> getObjectTypeNamespaces();

/**
* Reverse of {@code GmlConfiguration#variableObjectElementNames}: maps an object type's name (the
* schema's {@code objectType} value) to the wire-element-name → source-value mapping the encoder
* applied. When the wire element of the feature root matches one of the configured qualified
* names for the feature schema's {@code objectType}, the decoder accepts the element as the
* feature type and emits the mapped source value at {@link VariableObjectName#getProperty
* VariableObjectName#getProperty()}.
*/
Map<String, VariableObjectName> getVariableObjectElementNames();

/**
* Reverse of {@code GmlConfiguration#featureCollectionElementName}. When set, the decoder accepts
* a document whose root element is the configured wrapper (e.g. {@code sf:FeatureCollection}) and
* descends through it to the feature element instead of treating the wrapper as a feature type.
* The value must be in the form {@code prefix:localName}; the prefix is resolved against the
* namespace map passed to the decoder's constructor. When unset, the document root must directly
* be the feature element. Only a single feature inside the wrapper is supported — a second
* feature sibling is rejected as multi-feature ingest.
*/
@Value.Default
default String getFeatureCollectionElementName() {
return "";
}

/**
* Reverse of {@code GmlConfiguration#featureMemberElementName}. When set, the decoder expects the
* configured member element (e.g. {@code sf:featureMember}) as the child of the feature
* collection wrapper (or as the document root, when only this option is configured) and descends
* through it to the feature element. Same {@code prefix:localName} resolution as {@link
* #getFeatureCollectionElementName()}.
*/
@Value.Default
default String getFeatureMemberElementName() {
return "";
}

List<String> getXmlAttributes();

Map<String, List<String>> getValueWrap();

static FeatureTokenDecoderGmlInputProfile empty() {
return ImmutableFeatureTokenDecoderGmlInputProfile.builder().build();
}
}
Loading
Loading