mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[FEATURE] explode hstore algorithm (#8212)
This commit is contained in:
parent
df81e554f8
commit
6e16651d96
49
python/plugins/processing/tests/testdata/custom/hstore.gml
vendored
Normal file
49
python/plugins/processing/tests/testdata/custom/hstore.gml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ hstore.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.0">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","barrier"=>"wall","cuisine"=>"chinese","internet_access"=>"yes"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.1">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"fuel","building"=>"roof","name"=>"foo"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.2">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,6 3,6 3,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"building"=>"yes"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.3">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","cuisine"=>"burger","name"=>"bar","operator"=>"foo"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.4">
|
||||
<ogr:hstore>"amenity"=>"bank","atm"=>"yes"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore fid="polys.5">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"stars"=>"5","tourism"=>"hotel"</ogr:hstore>
|
||||
</ogr:hstore>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
30
python/plugins/processing/tests/testdata/custom/hstore.xsd
vendored
Normal file
30
python/plugins/processing/tests/testdata/custom/hstore.xsd
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="hstore" type="ogr:hstore_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="hstore_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="hstore" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
109
python/plugins/processing/tests/testdata/expected/hstore_all_keys.gml
vendored
Normal file
109
python/plugins/processing/tests/testdata/expected/hstore_all_keys.gml
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ hstore_all_keys.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.0">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","barrier"=>"wall","cuisine"=>"chinese","internet_access"=>"yes"</ogr:hstore>
|
||||
<ogr:tourism xsi:nil="true"/>
|
||||
<ogr:stars xsi:nil="true"/>
|
||||
<ogr:atm xsi:nil="true"/>
|
||||
<ogr:operator xsi:nil="true"/>
|
||||
<ogr:name xsi:nil="true"/>
|
||||
<ogr:building xsi:nil="true"/>
|
||||
<ogr:internet_access>yes</ogr:internet_access>
|
||||
<ogr:cuisine>chinese</ogr:cuisine>
|
||||
<ogr:barrier>wall</ogr:barrier>
|
||||
<ogr:amenity>restaurant</ogr:amenity>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.1">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"fuel","building"=>"roof","name"=>"foo"</ogr:hstore>
|
||||
<ogr:tourism xsi:nil="true"/>
|
||||
<ogr:stars xsi:nil="true"/>
|
||||
<ogr:atm xsi:nil="true"/>
|
||||
<ogr:operator xsi:nil="true"/>
|
||||
<ogr:name>foo</ogr:name>
|
||||
<ogr:building>roof</ogr:building>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:barrier xsi:nil="true"/>
|
||||
<ogr:amenity>fuel</ogr:amenity>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.2">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,6 3,6 3,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"building"=>"yes"</ogr:hstore>
|
||||
<ogr:tourism xsi:nil="true"/>
|
||||
<ogr:stars xsi:nil="true"/>
|
||||
<ogr:atm xsi:nil="true"/>
|
||||
<ogr:operator xsi:nil="true"/>
|
||||
<ogr:name xsi:nil="true"/>
|
||||
<ogr:building>yes</ogr:building>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:barrier xsi:nil="true"/>
|
||||
<ogr:amenity xsi:nil="true"/>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.3">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","cuisine"=>"burger","name"=>"bar","operator"=>"foo"</ogr:hstore>
|
||||
<ogr:tourism xsi:nil="true"/>
|
||||
<ogr:stars xsi:nil="true"/>
|
||||
<ogr:atm xsi:nil="true"/>
|
||||
<ogr:operator>foo</ogr:operator>
|
||||
<ogr:name>bar</ogr:name>
|
||||
<ogr:building xsi:nil="true"/>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine>burger</ogr:cuisine>
|
||||
<ogr:barrier xsi:nil="true"/>
|
||||
<ogr:amenity>restaurant</ogr:amenity>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.4">
|
||||
<ogr:hstore>"amenity"=>"bank","atm"=>"yes"</ogr:hstore>
|
||||
<ogr:tourism xsi:nil="true"/>
|
||||
<ogr:stars xsi:nil="true"/>
|
||||
<ogr:atm>yes</ogr:atm>
|
||||
<ogr:operator xsi:nil="true"/>
|
||||
<ogr:name xsi:nil="true"/>
|
||||
<ogr:building xsi:nil="true"/>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:barrier xsi:nil="true"/>
|
||||
<ogr:amenity>bank</ogr:amenity>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_all_keys fid="polys.5">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"stars"=>"5","tourism"=>"hotel"</ogr:hstore>
|
||||
<ogr:tourism>hotel</ogr:tourism>
|
||||
<ogr:stars>5</ogr:stars>
|
||||
<ogr:atm xsi:nil="true"/>
|
||||
<ogr:operator xsi:nil="true"/>
|
||||
<ogr:name xsi:nil="true"/>
|
||||
<ogr:building xsi:nil="true"/>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:barrier xsi:nil="true"/>
|
||||
<ogr:amenity xsi:nil="true"/>
|
||||
</ogr:hstore_all_keys>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
100
python/plugins/processing/tests/testdata/expected/hstore_all_keys.xsd
vendored
Normal file
100
python/plugins/processing/tests/testdata/expected/hstore_all_keys.xsd
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="hstore_all_keys" type="ogr:hstore_all_keys_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="hstore_all_keys_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="hstore" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="tourism" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="stars" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="atm" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="operator" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="building" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="internet_access" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cuisine" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="barrier" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="amenity" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
67
python/plugins/processing/tests/testdata/expected/hstore_two_fields.gml
vendored
Normal file
67
python/plugins/processing/tests/testdata/expected/hstore_two_fields.gml
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ hstore_two_fields.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.0">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","barrier"=>"wall"</ogr:hstore>
|
||||
<ogr:internet_access>yes</ogr:internet_access>
|
||||
<ogr:cuisine>chinese</ogr:cuisine>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.1">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"fuel","building"=>"roof","name"=>"foo"</ogr:hstore>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.2">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,6 3,6 3,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"building"=>"yes"</ogr:hstore>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.3">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"amenity"=>"restaurant","name"=>"bar","operator"=>"foo"</ogr:hstore>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine>burger</ogr:cuisine>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.4">
|
||||
<ogr:hstore>"amenity"=>"bank","atm"=>"yes"</ogr:hstore>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:hstore_two_fields fid="polys.5">
|
||||
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
|
||||
<ogr:hstore>"stars"=>"5","tourism"=>"hotel"</ogr:hstore>
|
||||
<ogr:internet_access xsi:nil="true"/>
|
||||
<ogr:cuisine xsi:nil="true"/>
|
||||
<ogr:doesntexist xsi:nil="true"/>
|
||||
</ogr:hstore_two_fields>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
51
python/plugins/processing/tests/testdata/expected/hstore_two_fields.xsd
vendored
Normal file
51
python/plugins/processing/tests/testdata/expected/hstore_two_fields.xsd
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
|
||||
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureCollectionType">
|
||||
<xs:attribute name="lockId" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="scope" type="xs:string" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="hstore_two_fields" type="ogr:hstore_two_fields_Type" substitutionGroup="gml:_Feature"/>
|
||||
<xs:complexType name="hstore_two_fields_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="hstore" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="internet_access" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cuisine" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="doesntexist" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
@ -914,6 +914,32 @@ tests:
|
||||
name: expected/zm_dropped.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: native:explodehstorefield
|
||||
name: Test explode HStore field with all keys
|
||||
params:
|
||||
EXPECTED_FIELDS: ''
|
||||
FIELD: hstore
|
||||
INPUT:
|
||||
name: custom/hstore.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/hstore_all_keys.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:explodehstorefield
|
||||
name: Test explode HStore field with 2 fields
|
||||
params:
|
||||
EXPECTED_FIELDS: internet_access,cuisine,doesntexist
|
||||
FIELD: hstore
|
||||
INPUT:
|
||||
name: custom/hstore.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/hstore_two_fields.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:pointonsurface
|
||||
name: Point on polygon surface
|
||||
params:
|
||||
|
@ -38,6 +38,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmdropgeometry.cpp
|
||||
processing/qgsalgorithmdropmzvalues.cpp
|
||||
processing/qgsalgorithmexplode.cpp
|
||||
processing/qgsalgorithmexplodehstore.cpp
|
||||
processing/qgsalgorithmextendlines.cpp
|
||||
processing/qgsalgorithmextenttolayer.cpp
|
||||
processing/qgsalgorithmextractbyattribute.cpp
|
||||
|
184
src/analysis/processing/qgsalgorithmexplodehstore.cpp
Normal file
184
src/analysis/processing/qgsalgorithmexplodehstore.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmexplodehstore.h
|
||||
---------------------
|
||||
begin : September 2018
|
||||
copyright : (C) 2018 by Etienne Trimaille
|
||||
email : etienne dot trimaille at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsalgorithmexplodehstore.h"
|
||||
#include "qgshstoreutils.h"
|
||||
#include "qgsprocessingutils.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsExplodeHstoreAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "explodehstorefield" );
|
||||
}
|
||||
|
||||
QString QgsExplodeHstoreAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Explode HStore Field" );
|
||||
}
|
||||
|
||||
QStringList QgsExplodeHstoreAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "field,explode,hstore,osm,openstreetmap" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsExplodeHstoreAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector table" );
|
||||
}
|
||||
|
||||
QString QgsExplodeHstoreAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "vectortable" );
|
||||
}
|
||||
|
||||
QString QgsExplodeHstoreAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm creates a copy of the input layer and adds a new field for every unique key in the HStore field.\n"
|
||||
"The expected field list is an optional comma separated list. By default, all unique keys are added. If this list is specified, only these fields are added and the HStore field is updated." );
|
||||
}
|
||||
|
||||
QgsProcessingAlgorithm *QgsExplodeHstoreAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsExplodeHstoreAlgorithm();
|
||||
}
|
||||
|
||||
void QgsExplodeHstoreAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
|
||||
QObject::tr( "Input layer" ) ) );
|
||||
addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ),
|
||||
QObject::tr( "HStore field" ), QVariant(), QStringLiteral( "INPUT" ) ) );
|
||||
addParameter( new QgsProcessingParameterString( QStringLiteral( "EXPECTED_FIELDS" ), QObject::tr( "Expected list of fields separated by a comma" ), QVariant(), false, true ) );
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Exploded" ) ) );
|
||||
}
|
||||
|
||||
QVariantMap QgsExplodeHstoreAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
|
||||
int attrSourceCount = source->fields().count();
|
||||
|
||||
QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
|
||||
int fieldIndex = source->fields().lookupField( fieldName );
|
||||
if ( fieldIndex < 0 )
|
||||
throw QgsProcessingException( QObject::tr( "Invalid HStore field" ) );
|
||||
|
||||
QStringList expectedFields;
|
||||
QString fieldList = parameterAsString( parameters, QStringLiteral( "EXPECTED_FIELDS" ), context );
|
||||
if ( ! fieldList.trimmed().isEmpty() )
|
||||
{
|
||||
expectedFields = fieldList.split( ',' );
|
||||
}
|
||||
|
||||
QList<QString> fieldsToAdd;
|
||||
QHash<QgsFeatureId, QVariantMap> hstoreFeatures;
|
||||
QList<QgsFeature> features;
|
||||
|
||||
double step = source->featureCount() > 0 ? 50.0 / source->featureCount() : 1;
|
||||
int i = 0;
|
||||
QgsFeatureIterator featIterator = source->getFeatures( );
|
||||
QgsFeature feat;
|
||||
while ( featIterator.nextFeature( feat ) )
|
||||
{
|
||||
i++;
|
||||
if ( feedback->isCanceled() )
|
||||
break;
|
||||
|
||||
double progress = i * step;
|
||||
if ( progress >= 50 )
|
||||
feedback->setProgress( 50.0 );
|
||||
else
|
||||
feedback->setProgress( progress );
|
||||
|
||||
QVariantMap currentHStore = QgsHstoreUtils::parse( feat.attribute( fieldName ).toString() );
|
||||
for ( const QString &key : currentHStore.keys() )
|
||||
{
|
||||
if ( expectedFields.isEmpty() && ! fieldsToAdd.contains( key ) )
|
||||
fieldsToAdd.insert( 0, key );
|
||||
}
|
||||
hstoreFeatures.insert( feat.id(), currentHStore );
|
||||
features.append( feat );
|
||||
}
|
||||
|
||||
if ( ! expectedFields.isEmpty() )
|
||||
{
|
||||
fieldsToAdd = expectedFields;
|
||||
}
|
||||
|
||||
QgsFields hstoreFields;
|
||||
for ( const QString &fieldName : fieldsToAdd )
|
||||
{
|
||||
hstoreFields.append( QgsField( fieldName, QVariant::String ) );
|
||||
}
|
||||
|
||||
QgsFields outFields = QgsProcessingUtils::combineFields( source->fields(), hstoreFields );
|
||||
|
||||
QString sinkId;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, sinkId, outFields, source->wkbType(), source->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
|
||||
|
||||
QList<int> fieldIndicesInput = QgsProcessingUtils::fieldNamesToIndices( QStringList(), source->fields() );
|
||||
int attrCount = attrSourceCount + fieldsToAdd.count();
|
||||
QgsFeature outFeature;
|
||||
step = !features.empty() ? 50.0 / features.count() : 1;
|
||||
i = 0;
|
||||
for ( const QgsFeature &feat : qgis::as_const( features ) )
|
||||
{
|
||||
i++;
|
||||
if ( feedback->isCanceled() )
|
||||
break;
|
||||
|
||||
feedback->setProgress( i * step + 50.0 );
|
||||
|
||||
QgsAttributes outAttributes( attrCount );
|
||||
|
||||
const QgsAttributes attrs( feat.attributes() );
|
||||
for ( int i = 0; i < fieldIndicesInput.count(); ++i )
|
||||
outAttributes[i] = attrs[fieldIndicesInput[i]];
|
||||
|
||||
QVariantMap currentHStore = hstoreFeatures.take( feat.id() );
|
||||
|
||||
QString current;
|
||||
for ( int i = 0; i < fieldsToAdd.count(); ++i )
|
||||
{
|
||||
current = fieldsToAdd.at( i );
|
||||
if ( currentHStore.contains( current ) )
|
||||
{
|
||||
outAttributes[attrSourceCount + i] = currentHStore.take( current );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! expectedFields.isEmpty() )
|
||||
{
|
||||
outAttributes[fieldIndex] = QgsHstoreUtils::build( currentHStore );
|
||||
}
|
||||
|
||||
outFeature.setGeometry( QgsGeometry( feat.geometry() ) );
|
||||
outFeature.setAttributes( outAttributes );
|
||||
sink->addFeature( outFeature, QgsFeatureSink::FastInsert );
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), sinkId );
|
||||
return outputs;
|
||||
}
|
||||
|
||||
///@endcond
|
54
src/analysis/processing/qgsalgorithmexplodehstore.h
Normal file
54
src/analysis/processing/qgsalgorithmexplodehstore.h
Normal file
@ -0,0 +1,54 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmexplodehstore.h
|
||||
---------------------
|
||||
begin : September 2018
|
||||
copyright : (C) 2018 by Etienne Trimaille
|
||||
email : etienne dot trimaille at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSALGORITHMEXPLODEHSTORE_H
|
||||
#define QGSALGORITHMEXPLODEHSTORE_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native explode hstore algorithm.
|
||||
*/
|
||||
class QgsExplodeHstoreAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
QgsExplodeHstoreAlgorithm() = default;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QStringList tags() const override;
|
||||
QString shortHelpString() const override;
|
||||
|
||||
protected:
|
||||
QgsProcessingAlgorithm *createInstance() const override;
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QVariantMap processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMEXPLODEHSTORE_H
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "qgsalgorithmdropgeometry.h"
|
||||
#include "qgsalgorithmdropmzvalues.h"
|
||||
#include "qgsalgorithmexplode.h"
|
||||
#include "qgsalgorithmexplodehstore.h"
|
||||
#include "qgsalgorithmextendlines.h"
|
||||
#include "qgsalgorithmextenttolayer.h"
|
||||
#include "qgsalgorithmextractbyattribute.h"
|
||||
@ -158,6 +159,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsDropGeometryAlgorithm() );
|
||||
addAlgorithm( new QgsDropMZValuesAlgorithm() );
|
||||
addAlgorithm( new QgsExplodeAlgorithm() );
|
||||
addAlgorithm( new QgsExplodeHstoreAlgorithm() );
|
||||
addAlgorithm( new QgsExtendLinesAlgorithm() );
|
||||
addAlgorithm( new QgsExtentToLayerAlgorithm() );
|
||||
addAlgorithm( new QgsExtractByAttributeAlgorithm() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user