Skip to content

Commit

Permalink
Merge branch 'OSGeo:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
a0x8o authored Jul 31, 2024
2 parents c609837 + c95081c commit 403c5fe
Show file tree
Hide file tree
Showing 20 changed files with 824 additions and 318 deletions.
30 changes: 30 additions & 0 deletions autotest/ogr/data/gml/min_example/ft1_schema.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:ft1="http://www.esdi-humboldt.eu/hale/shp/entwick" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.esdi-humboldt.eu/hale/shp/entwick">
<import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
<element name="entwick" substitutionGroup="gml:AbstractFeature">
<complexType>
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element minOccurs="0" name="arokstatus" type="decimal"/>
<element minOccurs="0" name="oa_nr" type="decimal"/>
<element minOccurs="0" name="bezeich" type="string"/>
<element minOccurs="0" name="aktennr" type="string"/>
<element minOccurs="0" name="quelle" type="string"/>
<element minOccurs="0" name="dat_erst" type="date"/>
<element minOccurs="0" name="erst_ID" type="decimal"/>
<element minOccurs="0" name="bearbeiter" type="string"/>
<element minOccurs="0" name="dat_geneh" type="date"/>
<element minOccurs="0" name="inkraft" type="date"/>
<element minOccurs="0" name="bemerk" type="string"/>
<element minOccurs="0" name="sonderfest" type="string"/>
<element minOccurs="0" name="SHAPE_Leng" type="decimal"/>
<element minOccurs="0" name="SHAPE_Area" type="decimal"/>
<element minOccurs="0" name="ars" type="string"/>
<element minOccurs="0" name="UUID" type="string"/>
<element minOccurs="0" name="geometry" type="gml:MultiSurfacePropertyType"/>
</sequence>
</extension>
</complexContent>
</complexType>
</element>
</schema>
31 changes: 31 additions & 0 deletions autotest/ogr/data/gml/min_example/ft2_schema.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:ft2="http://www.esdi-humboldt.eu/hale/shp/sanier" xmlns:xlink="http://www.w3.org/1999/xlink" targetNamespace="http://www.esdi-humboldt.eu/hale/shp/sanier" elementFormDefault="qualified" attributeFormDefault="unqualified">
<import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
<element name="sanier" substitutionGroup="gml:AbstractFeature">
<complexType>
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element name="arokstatus" minOccurs="0" type="string"/>
<element name="oa_nr" minOccurs="0" type="string"/>
<element name="bezeich" minOccurs="0" type="string"/>
<element name="aktennr" minOccurs="0" type="string"/>
<element name="dat_erst" minOccurs="0" type="date"/>
<element name="erst_ID" minOccurs="0" type="string"/>
<element name="bearbeiter" minOccurs="0" type="string"/>
<element name="dat_geneh" minOccurs="0" type="date"/>
<element name="inkraft" minOccurs="0" type="date"/>
<element name="bemerk" minOccurs="0" type="string"/>
<element name="sonderfest" minOccurs="0" type="string"/>
<element name="ars" minOccurs="0" type="string"/>
<element name="ars_text" minOccurs="0" type="string"/>
<element name="UUID" minOccurs="0" type="string"/>
<element name="SHAPE_Leng" minOccurs="0" type="decimal"/>
<element name="SHAPE_Area" minOccurs="0" type="decimal"/>
<element name="quelle" minOccurs="0" type="string"/>
<element name="geometry" minOccurs="0" type="gml:MultiSurfacePropertyType"/>
</sequence>
</extension>
</complexContent>
</complexType>
</element>
</schema>
55 changes: 55 additions & 0 deletions autotest/ogr/data/gml/min_example/minimal_example.gml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions autotest/ogr/data/gml/min_example/minimal_example.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.esdi-humboldt.eu/hale/shp/sanier">
<import namespace="http://www.esdi-humboldt.eu/hale/shp/entwick" schemaLocation="ft1_schema.xsd"/>
<include schemaLocation="ft2_schema.xsd"/>
</schema>
178 changes: 178 additions & 0 deletions autotest/ogr/ogr_gml.py
Original file line number Diff line number Diff line change
Expand Up @@ -4448,3 +4448,181 @@ def test_ogr_gml_ogr2ogr_from_layers_with_inconsistent_srs(
gdal.VSIFCloseL(f)

assert b"<gml:boundedBy><gml:Null /></gml:boundedBy>" in data


####################################################################################
# Test if gml can access and use imported schemas along with included schemas
# Open option is set to NO to disable the functionality


def test_ogr_gml_USE_SCHEMA_IMPORT_NO(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

ds = gdal.OpenEx(
tmp_path / "minimal_example.gml", open_options=["USE_SCHEMA_IMPORT=NO"]
)
layer_count = ds.GetLayerCount()
assert (
layer_count != 2
), f"Expected number of layers as '1' without open option set, but got {layer_count} "


###############################################################################
# Test if gml can access and use imported schemas along with included schemas
# Open option is set to YES to enable the functionality


def test_ogr_gml_USE_SCHEMA_IMPORT_YES(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

ds = gdal.OpenEx(
tmp_path / "minimal_example.gml", open_options=["USE_SCHEMA_IMPORT=YES"]
)

layer_count = ds.GetLayerCount()
assert (
layer_count == 2
), f"Expected number of layers as '2' with open option set, but got {layer_count} "


###############################################################################
# Test if gml can access and use imported schemas along with included schemas
# Config option is set to YES to enable the functionality


def test_ogr_gml_GML_USE_SCHEMA_IMPORT_YES(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

with gdal.config_option("GML_USE_SCHEMA_IMPORT", "YES"):
ds = ogr.Open(tmp_path / "minimal_example.gml")

layer_count = ds.GetLayerCount()
assert (
layer_count == 2
), f"Expected number of layers as '2' with config option set, but got {layer_count} "


###############################################################################
# Test if gml can access and use imported schemas along with included schemas
# Config option is set to NO to disable the functionality


def test_ogr_gml_GML_USE_SCHEMA_IMPORT_NO(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

with gdal.config_option("GML_USE_SCHEMA_IMPORT", "NO"):
ds = ogr.Open(tmp_path / "minimal_example.gml")

layer_count = ds.GetLayerCount()
assert (
layer_count == 1
), f"Expected number of layers as '1' without config option set, but got {layer_count} "


########################################################################################################
# Test if gml can access and use imported schemas along with included schemas with some features testing
# Open option is set to TRUE to enable the functionality


def test_ogr_gml_get_layers_by_name_from_imported_schema(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

ds = gdal.OpenEx(
tmp_path / "minimal_example.gml", open_options=["USE_SCHEMA_IMPORT=YES"]
)
layer_count = ds.GetLayerCount()
assert layer_count == 2, f"Expected number of layers as '2', but got {layer_count} "

# layer sanier
lyr = ds.GetLayerByName("sanier")
feat = lyr.GetNextFeature()
assert lyr is not None, "cannot find sanier"

arokstatus = feat.GetFieldAsString("arokstatus")
assert (
arokstatus == "Rechtsbestand"
), f"Expected 'arokstatus' to be 'Rechtsbestand', but got {arokstatus}"

# layer entwick
lyr = ds.GetLayerByName("entwick")
feat = lyr.GetNextFeature()
assert lyr is not None, "cannot find entwick"

shape_len = feat.GetFieldAsDouble("SHAPE_Leng")
assert (
shape_len == 8266.565325510000000
), f"Expected 'shape_len' to be '8266.565325510000000', but got {shape_len}"


#######################################################################################################
# Test if gml can access and use imported schemas along with included schemas with some features testing
# Open option is set to TRUE to enable the functionality


def test_ogr_gml_get_layers_by_name_from_imported_schema_more_tests(tmp_path):

# copy schema files and gml
shutil.copy("data/gml/min_example/ft1_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/ft2_schema.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.xsd", tmp_path)
shutil.copy("data/gml/min_example/minimal_example.gml", tmp_path)

ds = gdal.OpenEx(
tmp_path / "minimal_example.gml", open_options=["USE_SCHEMA_IMPORT=YES"]
)

layer_count = ds.GetLayerCount()
assert layer_count == 2, f"Expected number of layers as '2', but got {layer_count} "

# layer entwick
lyr = ds.GetLayerByName("entwick")
feat = lyr.GetNextFeature()
shape_len = feat.GetFieldAsDouble("SHAPE_Leng")
assert (
shape_len == 8266.565325510000000
), f"Expected 'shape_len' to be '8266.565325510000000', but got {shape_len}"

oa_nr = feat.GetFieldAsDouble("oa_nr")
assert isinstance(
oa_nr, float
), f"Expected 'oa_nr' to be of type 'float', but got {type(oa_nr).__name__}"
assert oa_nr == 430070, f"Expected oa_nr to be '430070', but got {oa_nr}"

# layer sanier
lyr = ds.GetLayerByName("sanier")
feat = lyr.GetNextFeature()
oa_nr = feat.GetFieldAsString("oa_nr")
assert isinstance(
oa_nr, str
), f"Expected 'oa_nr' to be of type 'str', but got {type(oa_nr).__name__}"
assert oa_nr == "430050", f"Expected oa_nr to be '430050', but got {oa_nr}"

dat_erst = feat.GetFieldAsDateTime("dat_erst")
assert isinstance(
dat_erst, list
), f"Expected 'dat_erst' to be of type 'list', but got {type(dat_erst)}"
54 changes: 53 additions & 1 deletion autotest/ogr/ogr_hana.py
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,56 @@ def create_feature(fid, geom_wkt=None):
layer.CommitTransaction()


###############################################################################
# Test REAL_VECTOR type


def test_ogr_hana_38():
conn = create_connection()
layer_name = get_test_name()
table_name = f'"{gdaltest.hana_schema_name}"."{layer_name}"'
execute_sql(
conn,
f"CREATE COLUMN TABLE {table_name} (ID INT PRIMARY KEY, EMB1 REAL_VECTOR(3), EMB2 REAL_VECTOR)",
)
execute_sql(
conn,
f"INSERT INTO {table_name} VALUES (1, TO_REAL_VECTOR('[0.1,0.2,0.3]'), TO_REAL_VECTOR('[0.1,0.2,0.3]'))",
)

def check_value(expected):
ds = open_datasource(0)
layer = ds.GetLayerByName(layer_name)
layer_defn = layer.GetLayerDefn()
assert layer.GetLayerDefn().GetFieldCount() == 2
field_emb1 = layer_defn.GetFieldDefn(layer_defn.GetFieldIndex("EMB1"))
assert field_emb1.GetType() == ogr.OFTBinary
assert field_emb1.GetWidth() == 16
field_emb2 = layer_defn.GetFieldDefn(layer_defn.GetFieldIndex("EMB2"))
assert field_emb2.GetType() == ogr.OFTBinary
assert field_emb2.GetWidth() == 65000
check_feature_count(layer, 1)
feat = layer.GetNextFeature()
assert feat.GetFieldAsBinary("EMB1") == expected
assert feat.GetFieldAsBinary("EMB2") == expected

# '[0.1,0.2,0.3]'
vec0 = b"\x03\x00\x00\x00\xCD\xCC\xCC\x3D\xCD\xCC\x4C\x3E\x9A\x99\x99\x3E"
# '[0.1,0.2,0.1]'
vec1 = b"\x03\x00\x00\x00\xCD\xCC\xCC\x3D\xCD\xCC\x4C\x3E\xCD\xCC\xCC\x3D"

check_value(vec0)

ds = open_datasource(1)
layer = ds.GetLayerByName(layer_name)
feat = layer.GetNextFeature()
feat.SetField("EMB1", vec1)
feat.SetField("EMB2", vec1)
layer.SetFeature(feat)

check_value(vec1)


###############################################################################
# Create a table from data/poly.shp

Expand Down Expand Up @@ -1248,7 +1298,9 @@ def create_tpoly_table(ds, layer_name="TPOLY"):
def get_connection_str():
uri = gdal.GetConfigOption("OGR_HANA_CONNECTION_STRING", None)
if uri is not None:
conn_str = uri + ";ENCRYPT=YES;SSL_VALIDATE_CERTIFICATE=false;CHAR_AS_UTF8=1"
if "ENCRYPT" not in uri:
uri += ";ENCRYPT=YES"
conn_str = uri + ";SSL_VALIDATE_CERTIFICATE=false;CHAR_AS_UTF8=1"
else:
pytest.skip("OGR_HANA_CONNECTION_STRING not set")

Expand Down
11 changes: 11 additions & 0 deletions doc/source/drivers/vector/gml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ The following configuration options are available:

Equivalent of :oo:`READ_MODE`. See :ref:`gml_performance`.

- .. config:: GML_USE_SCHEMA_IMPORT
:choices: YES, NO

Equivalent of :oo:`USE_SCHEMA_IMPORT`.


Parsers
-------
Expand Down Expand Up @@ -626,6 +631,12 @@ The following open options are supported:
Whether to use gml:boundedBy at feature level as feature geometry,
if there are no other geometry.

- .. oo:: USE_SCHEMA_IMPORT
:choices: YES, NO
:default: NO

Whether to use schema imports in XSD files so that
the feature types corresponding to imported schema can be detected.

.. note::

Expand Down
4 changes: 3 additions & 1 deletion frmts/ogcapi/gdalogcapidataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,9 @@ ParseXMLSchema(const std::string &osURL,

std::vector<GMLFeatureClass *> apoClasses;
bool bFullyUnderstood = false;
bool bHaveSchema = GMLParseXSD(osURL.c_str(), apoClasses, bFullyUnderstood);
bool bUseSchemaImports = false;
bool bHaveSchema = GMLParseXSD(osURL.c_str(), bUseSchemaImports, apoClasses,
bFullyUnderstood);
if (bHaveSchema && apoClasses.size() == 1)
{
auto poGMLFeatureClass = apoClasses[0];
Expand Down
8 changes: 6 additions & 2 deletions ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ bool OGRGMLDataSource::Open(GDALOpenInfo *poOpenInfo)
const char *pszExposeFid =
CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "EXPOSE_FID",
CPLGetConfigOption("GML_EXPOSE_FID", nullptr));

if (pszExposeFid)
bExposeFid = CPLTestBool(pszExposeFid);

Expand Down Expand Up @@ -1124,9 +1125,12 @@ bool OGRGMLDataSource::Open(GDALOpenInfo *poOpenInfo)
if (bHasFoundXSD)
{
std::vector<GMLFeatureClass *> aosClasses;
bool bUseSchemaImports = CPLFetchBool(
poOpenInfo->papszOpenOptions, "USE_SCHEMA_IMPORT",
CPLTestBool(CPLGetConfigOption("GML_USE_SCHEMA_IMPORT", "NO")));
bool bFullyUnderstood = false;
bHaveSchema =
GMLParseXSD(osXSDFilename, aosClasses, bFullyUnderstood);
bHaveSchema = GMLParseXSD(osXSDFilename, bUseSchemaImports,
aosClasses, bFullyUnderstood);

if (bHaveSchema && !bFullyUnderstood && bIsWFSJointLayer)
{
Expand Down
3 changes: 3 additions & 0 deletions ogr/ogrsf_frmts/gml/ogrgmldriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ void RegisterOGRGML()
" <Option name='USE_BBOX' type='boolean' description='Whether "
"to use gml:boundedBy at feature level as feature geometry, "
"if there are no other geometry' default='NO'/>"
" <Option name='USE_SCHEMA_IMPORT' type='boolean' "
"description='Whether "
"to read schema for imports along with includes or not' default='NO'/>"
"</OpenOptionList>");

poDriver->SetMetadataItem(
Expand Down
Loading

0 comments on commit 403c5fe

Please sign in to comment.