• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geostyler / geostyler-wfs-parser / 9483479420

12 Jun 2024 01:26PM UTC coverage: 89.157% (-1.9%) from 91.026%
9483479420

push

github

web-flow
Merge pull request #588 from geostyler/no-attributes-layer

Update parsing of layers without attributes

32 of 37 branches covered (86.49%)

Branch coverage included in aggregate %.

10 of 11 new or added lines in 1 file covered. (90.91%)

1 existing line in 1 file now uncovered.

42 of 46 relevant lines covered (91.3%)

8.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.16
/src/WfsDataParser.ts
1
import {
2
  DataParser,
3
  VectorData,
4
  DataSchema,
5
  SchemaProperty
6
} from 'geostyler-data';
7

8
import { JSONSchema4TypeName } from 'json-schema';
9

10
const isEmpty = require('lodash/isEmpty');
2✔
11
const isFinite = require('lodash/isFinite');
2✔
12

13
import {
14
  XMLParser
15
} from 'fast-xml-parser';
16

17
import {
18
  FeatureCollection
19
} from 'geojson';
20

21
export type RequestBaseParams = {
22
  service: 'WFS';
23
  request: 'GetFeature' | 'DescribeFeatureType';
24
  exceptions?: string;
25
};
26

27
export type GetFeatureOptionalParams = {
28
  featureID?: string;
29
  propertyName?: string;
30
  sortBy?: string;
31
  srsName?: string;
32
};
33

34
export type RequestParams1_1_0 = {
35
  version: '1.1.0';
36
  typeName: string;
37
  maxFeatures?: number;
38
  outputFormat: 'application/json' | 'application/geo+json';
39
};
40

41
export type RequestParams2_0_0 = {
42
  version: '2.0.0';
43
  typeNames: string;
44
  count?: number;
45
  outputFormat: 'application/json' | 'application/geo+json';
46
};
47

48
export type RequestParams = GetFeatureOptionalParams & (RequestParams1_1_0 | RequestParams2_0_0);
49
export type DescribeFeatureTypeParams = RequestBaseParams & (RequestParams1_1_0 | RequestParams2_0_0);
50
export type GetFeatureParams = DescribeFeatureTypeParams & GetFeatureOptionalParams;
51

52
/**
53
 * Interface representing the parameters to be send to WFS
54
 */
55
export interface ReadParams {
56
  url: string;
57
  requestParams: RequestParams;
58
  fetchParams?: RequestInit;
59
}
60

61
/**
62
 * Class implementing DataParser to fetch schema and sample data
63
 * using WFS requests (DescribeFeatureType resp. GetFeature)
64
 */
65
export class WfsDataParser implements DataParser {
66

67
  /**
68
   * The name of the WfsDataParser.
69
   */
70
  public static title = 'WFS Data Parser';
2✔
71

72
  title = 'WFS Data Parser';
14✔
73

74
  /**
75
   * Generate request parameter string for a passed object
76
   *
77
   * @param {Object} params Object holding request params
78
   * @return {string} The URI encoded request parameter string joined with &
79
   */
80
  generateRequestParamString(params: any): string {
81
    return Object.keys(params)
10✔
82
      .filter(key => !isEmpty(params[key]) || isFinite(params[key]))
56✔
83
      .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
54✔
84
      .join('&');
85
  }
86

87
  /**
88
   * Map XSD datatypes (SimpleType) to json schema data stypes
89
   *
90
   * @param qualifiedXsdDataType The XSD datatype as string (including namespace)
91
   * @returns {JSONSchema4TypeName} The corresponding JSON schema type name
92
   */
93
  mapXsdTypeToJsonDataType(qualifiedXsdDataType: string): JSONSchema4TypeName {
94
    const xsdDataType = qualifiedXsdDataType.indexOf(':') > -1
42!
95
      ? qualifiedXsdDataType.split(':')[1]
96
      : qualifiedXsdDataType;
97

98
    switch (xsdDataType) {
42!
99
      case 'string':
100
        return 'string';
4✔
101
      case 'boolean':
102
        return 'boolean';
2✔
103
      case 'float':
104
      case 'double':
105
      case 'long':
106
      case 'byte':
107
      case 'decimal':
108
      case 'integer':
109
      case 'int':
110
      case 'positiveInteger':
111
      case 'negativeInteger':
112
      case 'nonPositiveInteger':
113
      case 'nonNegativeInteger':
114
      case 'short':
115
      case 'unsignedLong':
116
      case 'unsignedInt':
117
      case 'unsignedShort':
118
      case 'unsignedByte':
119
        return 'number';
34✔
120
      default:
121
        return 'string';
2✔
122
    }
123
  }
124

125
  /**
126
   * Fetch schema and sample data and transforms it to the GeoStyler data model.
127
   *
128
   * Currently, WFS service must support application/json as outputFormat
129
   * and needs CORS headers (only needed if WFS Service is not located on the same origin
130
   * as the component using this parser) to be available in responses
131
   *
132
   * @param wfsConfig The parameters of the WFS
133
   */
134
  async readData({
135
    url,
136
    requestParams,
137
    fetchParams = {}
2✔
138
  }: ReadParams): Promise<VectorData> {
139

140
    let desribeFeatureTypeOpts;
141

142
    if (!requestParams.outputFormat) {
4!
143
      requestParams.outputFormat = 'application/json';
4✔
144
    }
145

146
    if (requestParams.version === '1.1.0') {
4✔
147
      desribeFeatureTypeOpts = {
×
148
        version: requestParams.version,
149
        maxFeatures: requestParams.maxFeatures,
150
        typeName: requestParams.typeName,
151
        outputFormat: requestParams.outputFormat
152
      };
153
    } else {
154
      desribeFeatureTypeOpts = {
4✔
155
        version: requestParams.version,
156
        count: requestParams.count,
157
        typeNames: requestParams.typeNames,
158
        outputFormat: requestParams.outputFormat
159
      };
160
    }
161

162
    // Fetch data schema via describe feature type
163
    let schema: DataSchema;
164
    try {
4✔
165
      const requestParamsString =  this.generateRequestParamString({
4✔
166
        ...desribeFeatureTypeOpts,
167
        service: 'WFS',
168
        request: 'DescribeFeatureType',
169
      });
170
      const requestDescribeFeatureType = `${url}?${requestParamsString}`;
4✔
171
      const describeFeatureTypeResponse = await fetch(requestDescribeFeatureType, fetchParams);
4✔
172
      const describeFeatueTypeResult = await describeFeatureTypeResponse.text();
4✔
173
      const parser = new XMLParser({
4✔
174
        removeNSPrefix: true,
175
        ignoreDeclaration: true,
176
        ignoreAttributes: false
177
      });
178
      const result = parser.parse(describeFeatueTypeResult);
4✔
179

180
      let attributes = result?.schema?.complexType?.complexContent?.extension?.sequence?.element
4✔
181

182
      const properties: { [name: string]: SchemaProperty } = {};
4✔
183
      if (attributes) {
4✔
184
        if (!Array.isArray(attributes)) {
2✔
NEW
185
          attributes = [attributes];
×
186
        }
187
        attributes.forEach((attr: any) => {
2✔
188
          const name = attr['@_name'];
10✔
189
          const type = attr['@_type'];
10✔
190
          if (!properties[name]) {
10!
191
            const propertyType: SchemaProperty = {type: this.mapXsdTypeToJsonDataType(type)};
10✔
192
            properties[name] = propertyType;
10✔
193
          }
194
        });
195
      }
196

197
      const title = result?.schema?.element?.['@_name'];
4✔
198

199
      schema = {
4✔
200
        type: 'object',
201
        title,
202
        properties
203
      };
204
    } catch (error) {
UNCOV
205
      throw `Could not parse XML document: ${error}`;
×
206
    }
207

208
    // Fetch sample data via WFS GetFeature
209
    let exampleFeatures: FeatureCollection;
210
    try {
4✔
211
      const requestGetFeature = `${url}?${this.generateRequestParamString({
4✔
212
        ...requestParams,
213
        service: 'WFS',
214
        request: 'GetFeature',
215
        outputFormat: 'application/json',
216
      })}`;
217
      const getFeatureResponse = await fetch(requestGetFeature, fetchParams);
4✔
218
      const getFeatureResult = await getFeatureResponse.json();
4✔
219
      exampleFeatures = getFeatureResult as FeatureCollection;
4✔
220
    } catch (error) {
221
      exampleFeatures = {
×
222
        type: 'FeatureCollection',
223
        features: []
224
      };
225
    }
226

227
    return {
4✔
228
      schema,
229
      exampleFeatures
230
    };
231
  }
232

233
}
234

235
export default WfsDataParser;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc