Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move "core/parsers" into "core/utils/parsers" #77

Merged
merged 2 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/core/layers/providers/provider.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const {base, inherit, getTimeoutPromise} = require('core/utils/utils');
const G3WObject = require('core/g3wobject');
const {handleQueryResponse} = require('core/utils/geo');
const {utils:queryResponseUtils} = require('core/parsers/response/parser');
const {response: responseParser} = require('core/utils/parsers');

function Provider(options = {}) {
this._isReady = false;
Expand Down Expand Up @@ -67,7 +67,7 @@ proto.getQueryResponseTimeoutKey = function({layers=[this._layer], resolve, quer
return getTimeoutPromise({
resolve,
data: {
data: queryResponseUtils.getTimeoutData(layers),
data: responseParser.utils.getTimeoutData(layers),
query
}
});
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/layers/providers/qgisprovider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import ApplicationState from 'core/applicationstate';
const {base, inherit, XHR} = require('core/utils/utils');
const {t} = require('core/i18n/i18n.service');
const DataProvider = require('core/layers/providers/provider');
const responseParser = require('core/parsers/response/parser');
const {response: responseParser} = require('core/utils/parsers');
const RelationsService = require('core/relations/relationsservice');
const Feature = require('core/layers/features/feature');
const Parsers = require('core/parsers/parsers');
const Parsers = require('core/utils/parsers');

function QGISProvider(options = {}) {
base(this);
Expand Down
9 changes: 4 additions & 5 deletions src/app/core/parsers/parsers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const Parsers = {
vector: require('./vector/parser'),
table: require('./table/parser'),
response: require('./response/parser')
};
const Parsers = require('core/utils/parsers');

/**
* DEPRECATED: this folder will be removed after v3.4 (use "core/utils/parsers" instead)
*/
module.exports = Parsers;
308 changes: 5 additions & 303 deletions src/app/core/parsers/response/parser.js
Original file line number Diff line number Diff line change
@@ -1,304 +1,6 @@
import {G3W_FID} from 'constant';
const {t} = require('core/i18n/i18n.service');
const vectorParser = require('../vector/parser');
const geoutils = require('core/utils/ol');
const WORD_NUMERIC_FIELD_ESCAPE = 'GIS3W_ESCAPE_NUMERIC_FIELD_';
//internal utilities
const utils = {
getHandledResponsesFromResponse({response, layers, projections, id=false}) {
let multilayers = false;
const x2js = new X2JS();
const jsonresponse = x2js.xml_str2json(response);
// in case of parser return null
if (!jsonresponse) return [{
layer: layers[0],
features: []
}];
const FeatureCollection = jsonresponse.FeatureCollection;
const handledResponses = [];
if (FeatureCollection.featureMember) {
const originalFeatureMember = Array.isArray(FeatureCollection.featureMember) ? FeatureCollection.featureMember : [FeatureCollection.featureMember];
for (let i = 0; i < layers.length; i++) {
const layer = layers[i];
const layerName = id ? layer.getId() : `layer${i}`;
const featureMemberArrayAndPrefix = {
features: null,
__prefix: null
};
jsonresponse.FeatureCollection.featureMember = originalFeatureMember.filter(feature => {
const featureMember = feature[layerName];
if (featureMember) {
featureMember.g3w_fid = {
__prefix: feature.__prefix,
__text: featureMember._fid && featureMember._fid.split('.')[1]
};
if (Array.isArray(featureMember)){
featureMemberArrayAndPrefix.features = featureMember;
featureMemberArrayAndPrefix.__prefix = feature.__prefix;
return false;
}
return true;
}
});
if (featureMemberArrayAndPrefix.features) {
const prefix = featureMemberArrayAndPrefix.__prefix;
// check if features have the same fields. If not group the features with the same fields
const groupFeatures = this.groupFeaturesByFields(featureMemberArrayAndPrefix.features);
//check if features have different fields (multilayers)
if (Object.keys(groupFeatures).length > 1) {
// is a multilayers. Each feature has different fields
multilayers = true;
this.handleWMSMultiLayersResponseFromQGISSERVER({
groupFeatures,
prefix,
handledResponses,
jsonresponse,
layer,
projections
})
} else {
featureMemberArrayAndPrefix.features.forEach(feature => {
//for Each element have to add and object contain layerName and information, and __prefix
jsonresponse.FeatureCollection.featureMember.push({
[layerName]: feature,
__prefix: prefix
})
});
}
}
if (!multilayers) {
const handledResponse = this.parseLayerFeatureCollection({
jsonresponse,
layer,
projections
});
handledResponse && handledResponses.unshift(handledResponse[0]);
}
}
}
return handledResponses;
},
transformFeatures(features, projections) {
if (features.length) {
if(!!features[0].getGeometry()) {
const mainProjection = projections.layer ? projections.layer : projections.map;
const invertedAxis = mainProjection.getAxisOrientation().substr(0,2) === 'ne';
if (projections.layer && (projections.layer.getCode() !== projections.map.getCode())) {
features.forEach(feature => {
const geometry = feature.getGeometry();
feature.setGeometry(geometry.transform(projections.layer.getCode(), projections.map.getCode()))
})
}
if (invertedAxis) features = this.reverseFeaturesCoordinates(features)
}
}
return features;
},
parseLayerFeatureCollection({jsonresponse, layer, projections}) {
const x2js = new X2JS();
const layerFeatureCollectionXML = x2js.json2xml_str(jsonresponse);
const parser = new ol.format.WMSGetFeatureInfo();
const features = this.transformFeatures(parser.readFeatures(layerFeatureCollectionXML), projections);
if (features.length && this.hasFieldsStartWithNotPermittedKey) {
const properties = Object.keys(features[0].getProperties());
const numericFields = properties.filter(property => property.indexOf(WORD_NUMERIC_FIELD_ESCAPE) !== -1);
features.forEach(feature => {
numericFields.forEach(_field => {
const value = feature.get(_field);
const ori_field = _field.replace(WORD_NUMERIC_FIELD_ESCAPE, '');
feature.set(this.hasFieldsStartWithNotPermittedKey[ori_field], Array.isArray(value) ? value[0] : value);
feature.unset(_field);
})
});
}
return [{
layer,
features
}]
},
reverseFeaturesCoordinates(features) {
features.forEach(feature => {
const geometry = feature.getGeometry();
feature.setGeometry(geoutils.reverseGeometry(geometry))
});
return features
},
handleXMLStringResponseBeforeConvertToJSON({response, layers, wms}={}) {
if (!response) return; // return undefined if no response
if (!(typeof response === 'string'|| response instanceof String))
response = new XMLSerializer().serializeToString(response);
for (let i=0; i < layers.length; i++) {
const layer = layers[i];
let originalName = (wms && layer.isWmsUseLayerIds()) ? layer.getId(): layer.getName();
let sanitizeLayerName = wms ? originalName.replace(/[/\s]/g, '') : originalName.replace(/[/\s]/g, '_');
sanitizeLayerName = sanitizeLayerName.replace(/(\'+)/, '');
sanitizeLayerName = sanitizeLayerName.replace(/(\)+)/, '');
sanitizeLayerName = sanitizeLayerName.replace(/(\(+)/, '');
const reg = new RegExp(`qgs:${sanitizeLayerName}`, "g");
response = response.replace(reg, `qgs:layer${i}`);
}
const arrayQGS = [...response.matchAll(/qgs:(\d+)(\w+)/g), ...response.matchAll(/qgs:(\w+):(\w+)/g)];
arrayQGS.forEach((find, idx) => {
if (idx%2 === 0) {
if (!this.hasFieldsStartWithNotPermittedKey) this.hasFieldsStartWithNotPermittedKey = {};
const originalField = find[0].replace('qgs:', '');
this.hasFieldsStartWithNotPermittedKey[`${find[1]}${find[2]}`] = originalField;
const regex = new RegExp(`${find[0]}`, "g");
response = response.replace(regex, `qgs:${WORD_NUMERIC_FIELD_ESCAPE}${find[1]}${find[2]}`)
}
});
//PATCH id strange
const strangeChar = new RegExp(`${String.fromCharCode(0)}`, "g");
response = response.replace(strangeChar, '0');
///
return response;
},
groupFeaturesByFields(features) {
return _.groupBy(features, feature => Object.keys(feature));
},
handleWMSMultiLayersResponseFromQGISSERVER({groupFeatures, prefix, handledResponses, jsonresponse, layer, projections} = {}){
// is a multilayers. Each feature has different fields. If group has more that one feature spit it and create single features
Object.keys(groupFeatures).forEach((key, index) => {
const features = groupFeatures[key];
features.forEach((feature, sub_index) => {
jsonresponse.FeatureCollection.featureMember = {
[`layer${index}_${sub_index}`]: feature,
__prefix: prefix
};
const handledResponse = this.parseLayerFeatureCollection({
jsonresponse,
layer,
projections
});
if (handledResponse) {
const response = handledResponse[0];
response.layer = layer;
handledResponses.unshift(response);
}
});
});
},
};
const { response } = require('core/utils/parsers');

const contenttypes = {
'application/json'({layers=[], response, projections, wms=true}={}) {
const {sanitizeFidFeature} = require('core/utils/geo');
const layersFeatures = [];
const layersId = layers.map(layer => {
layersFeatures.push({
layer,
features: []
});
return wms ? layer.getWMSLayerName() : layer.getWFSLayerName();
});
const data = response;
const parseData = () => {
const defaultDataProjection = projections.layer || projections.map;
const geojson = new ol.format.GeoJSON({
defaultDataProjection,
geometryName: "geometry"
});
return geojson.readFeatures(data);
};
const features = data && parseData();
features.filter(feature => {
const featureId = feature.getId();
const g3w_fid = sanitizeFidFeature(featureId);
// in case of wms getfeature without filter return string contain layerName or layerid
const index = featureId == g3w_fid ? 0 : layersId.indexOf(currentLayerId);
if (index !== -1) {
const fields = layersFeatures[index].layer.getFields().filter(field => field.show);
const properties = feature.getProperties();
feature.set(G3W_FID, g3w_fid);
fields.forEach(field=>{
if (properties[field.name] === undefined) {
properties[field.label] !== undefined && feature.set(field.name, properties[field.label])
}
});
layersFeatures[index].features.push(feature);
}
});
return layersFeatures;
},
'application/geojson'({layers, projections, response}={}){
const handleResponse = [];
const parserGEOJson = vectorParser.get({
type: 'geojson'
});
if (response) {
layers.forEach(layer =>{
handleResponse.push({
layer,
features: parserGEOJson(response, {})
})
})
}
return handleResponse;
},
'text/html'({layers, response}={}){
const handleResponse = [];
layers.forEach(layer =>{
handleResponse.push({
layer,
rawdata: response
})
});
return handleResponse;
},
'text/plain'({layers, response}={}){
const handleResponse = [];
layers.forEach(layer =>{
handleResponse.push({
layer,
rawdata: response
})
});
return handleResponse;
},
'text/gml'({layers, response}){
const parserGML = vectorParser.get({
type: 'gml'
});
const features = parserGML({
data:response,
layer: layers[0]
});
return layers.map(layer =>({
layer,
features
}));
},
'application/vnd.ogc.gml'({response, projections, layers, wms=true}={}){
return utils.getHandledResponsesFromResponse({
response: utils.handleXMLStringResponseBeforeConvertToJSON({
layers,
response,
wms
}),
layers,
projections
});
},
not_supported_format({layers=[]}={}){
return layers.map(layer=>({
layer,
rawdata: t('warning.not_supported_format')
}))
}
};

const ResponseParser = {
get(type){
return contenttypes[type] || contenttypes.not_supported_format;
},
utils: {
getTimeoutData(layers=[]){
return layers.map(layer=>({
layer,
rawdata: 'timeout'
}))
}
}
};

module.exports = ResponseParser;
/**
* DEPRECATED: this folder will be removed after v3.4 (use "core/utils/parsers" instead)
*/
module.exports = response;
33 changes: 5 additions & 28 deletions src/app/core/parsers/table/parser.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,6 @@
const Feature = require('core/layers/features/feature');
const TableParser = function() {
this.get = function(options={}) {
const type = options.type;
let parser;
switch (type) {
case 'json':
parser = this._parserJSON.bind(this);
break;
default:
parser = this._parserJSON.bind(this);
}
return parser;
};

this._parserJSON = function(data={}) {
const {features=[]} = data;
return features.map(_feature => {
const {id, properties} = _feature;
const feature = new Feature();
feature.setProperties(properties);
feature.setId(id);
return feature;
});
}
};

module.exports = new TableParser();
const { table } = require('core/utils/parsers');

/**
* DEPRECATED: this folder will be removed after v3.4 (use "core/utils/parsers" instead)
*/
module.exports = table;