[FEATURE] explode hstore algorithm (#8212)

This commit is contained in:
Etienne Trimaille 2018-11-09 09:00:29 +03:00 committed by Mathieu Pellerin
parent df81e554f8
commit 6e16651d96
11 changed files with 673 additions and 0 deletions

View 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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;barrier&quot;=&gt;&quot;wall&quot;,&quot;cuisine&quot;=&gt;&quot;chinese&quot;,&quot;internet_access&quot;=&gt;&quot;yes&quot;</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>&quot;amenity&quot;=&gt;&quot;fuel&quot;,&quot;building&quot;=&gt;&quot;roof&quot;,&quot;name&quot;=&gt;&quot;foo&quot;</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>&quot;building&quot;=&gt;&quot;yes&quot;</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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;cuisine&quot;=&gt;&quot;burger&quot;,&quot;name&quot;=&gt;&quot;bar&quot;,&quot;operator&quot;=&gt;&quot;foo&quot;</ogr:hstore>
</ogr:hstore>
</gml:featureMember>
<gml:featureMember>
<ogr:hstore fid="polys.4">
<ogr:hstore>&quot;amenity&quot;=&gt;&quot;bank&quot;,&quot;atm&quot;=&gt;&quot;yes&quot;</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>&quot;stars&quot;=&gt;&quot;5&quot;,&quot;tourism&quot;=&gt;&quot;hotel&quot;</ogr:hstore>
</ogr:hstore>
</gml:featureMember>
</ogr:FeatureCollection>

View 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>

View 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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;barrier&quot;=&gt;&quot;wall&quot;,&quot;cuisine&quot;=&gt;&quot;chinese&quot;,&quot;internet_access&quot;=&gt;&quot;yes&quot;</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>&quot;amenity&quot;=&gt;&quot;fuel&quot;,&quot;building&quot;=&gt;&quot;roof&quot;,&quot;name&quot;=&gt;&quot;foo&quot;</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>&quot;building&quot;=&gt;&quot;yes&quot;</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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;cuisine&quot;=&gt;&quot;burger&quot;,&quot;name&quot;=&gt;&quot;bar&quot;,&quot;operator&quot;=&gt;&quot;foo&quot;</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>&quot;amenity&quot;=&gt;&quot;bank&quot;,&quot;atm&quot;=&gt;&quot;yes&quot;</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>&quot;stars&quot;=&gt;&quot;5&quot;,&quot;tourism&quot;=&gt;&quot;hotel&quot;</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>

View 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>

View 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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;barrier&quot;=&gt;&quot;wall&quot;</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>&quot;amenity&quot;=&gt;&quot;fuel&quot;,&quot;building&quot;=&gt;&quot;roof&quot;,&quot;name&quot;=&gt;&quot;foo&quot;</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>&quot;building&quot;=&gt;&quot;yes&quot;</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>&quot;amenity&quot;=&gt;&quot;restaurant&quot;,&quot;name&quot;=&gt;&quot;bar&quot;,&quot;operator&quot;=&gt;&quot;foo&quot;</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>&quot;amenity&quot;=&gt;&quot;bank&quot;,&quot;atm&quot;=&gt;&quot;yes&quot;</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>&quot;stars&quot;=&gt;&quot;5&quot;,&quot;tourism&quot;=&gt;&quot;hotel&quot;</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>

View 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>

View File

@ -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:

View File

@ -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

View 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 &parameters, 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

View 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 &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
///@endcond PRIVATE
#endif // QGSALGORITHMEXPLODEHSTORE_H

View File

@ -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() );