@dunguel/expo-geo-parser 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,7 +60,9 @@ class KMLParser(
60
60
  companion object {
61
61
  fun parse(input: InputStream, sourceType: String, onFeatures: (List<Map<String, Any?>>, Boolean) -> Unit): Map<String, Any?> {
62
62
  val handler = KMLParser(onFeatures = onFeatures)
63
- val factory = SAXParserFactory.newInstance().apply { isNamespaceAware = true }
63
+ // Some KML files in the wild contain prefixed tags without proper xmlns declarations.
64
+ // Parsing without namespace enforcement keeps the stream parser resilient on Android.
65
+ val factory = SAXParserFactory.newInstance().apply { isNamespaceAware = false }
64
66
  try {
65
67
  factory.newSAXParser().parse(input, handler)
66
68
  } catch (e: Exception) {
@@ -77,14 +79,14 @@ class KMLParser(
77
79
  }
78
80
 
79
81
  override fun startElement(uri: String?, localName: String?, qName: String?, attrs: Attributes?) {
80
- val name = stripped(localName ?: qName ?: "")
82
+ val name = resolveElementName(localName, qName)
81
83
  elementStack.add(name)
82
84
  textBuffer.clear()
83
85
 
84
86
  when (name) {
85
87
  "Document" -> documentDepth++
86
- "Style" -> { currentStyleId = attrs?.getValue("id"); buildingStyle = StyleInfo() }
87
- "StyleMap" -> { inStyleMap = true; currentStyleMapId = attrs?.getValue("id") }
88
+ "Style" -> { currentStyleId = getAttribute(attrs, "id"); buildingStyle = StyleInfo() }
89
+ "StyleMap" -> { inStyleMap = true; currentStyleMapId = getAttribute(attrs, "id") }
88
90
  "Pair" -> if (inStyleMap) { inPair = true; currentPairKey = ""; currentPairStyleUrl = "" }
89
91
  "LineStyle" -> inLineStyle = true
90
92
  "PolyStyle" -> inPolyStyle = true
@@ -92,7 +94,7 @@ class KMLParser(
92
94
  "Icon" -> if (inIconStyle) inIconHref = true
93
95
  "Placemark" -> {
94
96
  inPlacemark = true
95
- currentFeatureId = attrs?.getValue("id")
97
+ currentFeatureId = getAttribute(attrs, "id")
96
98
  currentFeatureName = ""
97
99
  currentFeatureDescription = ""
98
100
  currentFeatureStyleUrl = ""
@@ -103,7 +105,7 @@ class KMLParser(
103
105
  multiGeometries = mutableListOf()
104
106
  }
105
107
  "ExtendedData" -> if (inPlacemark) inExtendedData = true
106
- "Data", "SimpleData" -> if (inPlacemark && inExtendedData) currentExtendedDataName = attrs?.getValue("name") ?: ""
108
+ "Data", "SimpleData" -> if (inPlacemark && inExtendedData) currentExtendedDataName = getAttribute(attrs, "name") ?: ""
107
109
  "Point" -> { currentGeometryType = "Point"; pointCoord = listOf() }
108
110
  "LineString" -> { currentGeometryType = "LineString"; lineCoords = listOf() }
109
111
  "LinearRing" -> currentRing = listOf()
@@ -123,7 +125,7 @@ class KMLParser(
123
125
  }
124
126
 
125
127
  override fun endElement(uri: String?, localName: String?, qName: String?) {
126
- val name = stripped(localName ?: qName ?: "")
128
+ val name = resolveElementName(localName, qName)
127
129
  val text = textBuffer.toString().trim()
128
130
  val parent = elementStack.dropLast(1).lastOrNull() ?: ""
129
131
  textBuffer.clear()
@@ -217,6 +219,25 @@ class KMLParser(
217
219
  return if (idx >= 0) name.substring(idx + 1) else name
218
220
  }
219
221
 
222
+ private fun resolveElementName(localName: String?, qName: String?): String {
223
+ val raw = localName?.takeIf { it.isNotEmpty() } ?: qName ?: ""
224
+ return stripped(raw)
225
+ }
226
+
227
+ private fun getAttribute(attrs: Attributes?, name: String): String? {
228
+ if (attrs == null) return null
229
+ attrs.getValue(name)?.let { return it }
230
+
231
+ for (index in 0 until attrs.length) {
232
+ val local = attrs.getLocalName(index)
233
+ if (local == name) return attrs.getValue(index)
234
+
235
+ val qName = attrs.getQName(index)
236
+ if (stripped(qName) == name) return attrs.getValue(index)
237
+ }
238
+ return null
239
+ }
240
+
220
241
  private fun isCollectionContainer(name: String): Boolean =
221
242
  name == "Document" || name == "Folder"
222
243
 
@@ -12,11 +12,36 @@ export type Feature = {
12
12
  geometry: Geometry;
13
13
  properties: Record<string, unknown>;
14
14
  };
15
- export type Geometry = {
16
- type: string;
17
- coordinates?: number[][];
18
- geometries?: Geometry[];
15
+ export type Position = [number, number, ...number[]];
16
+ export type PointGeometry = {
17
+ type: "Point";
18
+ coordinates: Position;
19
19
  };
20
+ export type MultiPointGeometry = {
21
+ type: "MultiPoint";
22
+ coordinates: Position[];
23
+ };
24
+ export type LineStringGeometry = {
25
+ type: "LineString";
26
+ coordinates: Position[];
27
+ };
28
+ export type MultiLineStringGeometry = {
29
+ type: "MultiLineString";
30
+ coordinates: Position[][];
31
+ };
32
+ export type PolygonGeometry = {
33
+ type: "Polygon";
34
+ coordinates: Position[][];
35
+ };
36
+ export type MultiPolygonGeometry = {
37
+ type: "MultiPolygon";
38
+ coordinates: Position[][][];
39
+ };
40
+ export type GeometryCollectionGeometry = {
41
+ type: "GeometryCollection";
42
+ geometries: Geometry[];
43
+ };
44
+ export type Geometry = PointGeometry | MultiPointGeometry | LineStringGeometry | MultiLineStringGeometry | PolygonGeometry | MultiPolygonGeometry | GeometryCollectionGeometry;
20
45
  export type FeatureCollection = {
21
46
  type: "FeatureCollection";
22
47
  name?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoGeoParser.types.d.ts","sourceRoot":"","sources":["../src/ExpoGeoParser.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAEjF,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"ExpoGeoParser.types.d.ts","sourceRoot":"","sources":["../src/ExpoGeoParser.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAEjF,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,QAAQ,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,QAAQ,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,QAAQ,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,kBAAkB,GAClB,kBAAkB,GAClB,uBAAuB,GACvB,eAAe,GACf,oBAAoB,GACpB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoGeoParser.types.js","sourceRoot":"","sources":["../src/ExpoGeoParser.types.ts"],"names":[],"mappings":"","sourcesContent":["export type GeoFileType = \"kml\" | \"kmz\" | \"zip\" | \"geojson\" | \"json\" | \"unknown\";\n\nexport type File = {\n uri: string;\n fileName?: string | null;\n extension?: string | null;\n type: GeoFileType;\n uti?: string | null;\n};\n\nexport type Feature = {\n type: \"Feature\";\n id?: string | number;\n geometry: Geometry;\n properties: Record<string, unknown>;\n};\n\nexport type Geometry = {\n type: string;\n coordinates?: number[][];\n geometries?: Geometry[];\n};\n\nexport type FeatureCollection = {\n type: \"FeatureCollection\";\n name?: string;\n description?: string;\n sourceType?: GeoFileType;\n features: Feature[];\n};\n\nexport type ParseFeaturesEvent = {\n features: Feature[];\n isLast: boolean;\n};\n"]}
1
+ {"version":3,"file":"ExpoGeoParser.types.js","sourceRoot":"","sources":["../src/ExpoGeoParser.types.ts"],"names":[],"mappings":"","sourcesContent":["export type GeoFileType = \"kml\" | \"kmz\" | \"zip\" | \"geojson\" | \"json\" | \"unknown\";\n\nexport type File = {\n uri: string;\n fileName?: string | null;\n extension?: string | null;\n type: GeoFileType;\n uti?: string | null;\n};\n\nexport type Feature = {\n type: \"Feature\";\n id?: string | number;\n geometry: Geometry;\n properties: Record<string, unknown>;\n};\n\nexport type Position = [number, number, ...number[]];\n\nexport type PointGeometry = {\n type: \"Point\";\n coordinates: Position;\n};\n\nexport type MultiPointGeometry = {\n type: \"MultiPoint\";\n coordinates: Position[];\n};\n\nexport type LineStringGeometry = {\n type: \"LineString\";\n coordinates: Position[];\n};\n\nexport type MultiLineStringGeometry = {\n type: \"MultiLineString\";\n coordinates: Position[][];\n};\n\nexport type PolygonGeometry = {\n type: \"Polygon\";\n coordinates: Position[][];\n};\n\nexport type MultiPolygonGeometry = {\n type: \"MultiPolygon\";\n coordinates: Position[][][];\n};\n\nexport type GeometryCollectionGeometry = {\n type: \"GeometryCollection\";\n geometries: Geometry[];\n};\n\nexport type Geometry =\n | PointGeometry\n | MultiPointGeometry\n | LineStringGeometry\n | MultiLineStringGeometry\n | PolygonGeometry\n | MultiPolygonGeometry\n | GeometryCollectionGeometry;\n\nexport type FeatureCollection = {\n type: \"FeatureCollection\";\n name?: string;\n description?: string;\n sourceType?: GeoFileType;\n features: Feature[];\n};\n\nexport type ParseFeaturesEvent = {\n features: Feature[];\n isLast: boolean;\n};\n"]}
package/package.json CHANGED
@@ -1,43 +1,43 @@
1
1
  {
2
- "name": "@dunguel/expo-geo-parser",
3
- "version": "0.5.1",
4
- "description": "A high-performance Expo native module for parsing geospatial files like KML, KMZ, and other formats, extracting polygons, markers, and spatial data efficiently on iOS and Android.",
5
- "main": "build/index.js",
6
- "types": "build/index.d.ts",
7
- "scripts": {
8
- "build": "expo-module build",
9
- "clean": "expo-module clean",
10
- "lint": "expo-module lint",
11
- "test": "expo-module test",
12
- "prepare": "expo-module prepare",
13
- "prepublishOnly": "expo-module prepublishOnly",
14
- "expo-module": "expo-module",
15
- "open:ios": "xed example/ios",
16
- "open:android": "open -a \"Android Studio\" example/android"
17
- },
18
- "keywords": [
19
- "react-native",
20
- "expo",
21
- "expo-geo-parser",
22
- "ExpoGeoParser"
23
- ],
24
- "repository": "https://github.com/guilhermedunguel/expo-geo-parser",
25
- "bugs": {
26
- "url": "https://github.com/guilhermedunguel/expo-geo-parser/issues"
27
- },
28
- "author": "Guilherme Dunguel <guilhermedunguel@gmail.com> (https://github.com/guilhermedunguel)",
29
- "license": "MIT",
30
- "homepage": "https://github.com/guilhermedunguel/expo-geo-parser#readme",
31
- "dependencies": {},
32
- "devDependencies": {
33
- "@types/react": "~19.1.1",
34
- "expo-module-scripts": "^55.0.2",
35
- "expo": "^55.0.5",
36
- "react-native": "0.82.1"
37
- },
38
- "peerDependencies": {
39
- "expo": "*",
40
- "react": "*",
41
- "react-native": "*"
42
- }
2
+ "name": "@dunguel/expo-geo-parser",
3
+ "version": "0.6.0",
4
+ "description": "A high-performance Expo native module for parsing geospatial files like KML, KMZ, and other formats, extracting polygons, markers, and spatial data efficiently on iOS and Android.",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "scripts": {
8
+ "build": "expo-module build",
9
+ "clean": "expo-module clean",
10
+ "lint": "expo-module lint",
11
+ "test": "expo-module test",
12
+ "prepare": "expo-module prepare",
13
+ "prepublishOnly": "expo-module prepublishOnly",
14
+ "expo-module": "expo-module",
15
+ "open:ios": "xed example/ios",
16
+ "open:android": "open -a \"Android Studio\" example/android"
17
+ },
18
+ "keywords": [
19
+ "react-native",
20
+ "expo",
21
+ "expo-geo-parser",
22
+ "ExpoGeoParser"
23
+ ],
24
+ "repository": "https://github.com/guilhermedunguel/expo-geo-parser",
25
+ "bugs": {
26
+ "url": "https://github.com/guilhermedunguel/expo-geo-parser/issues"
27
+ },
28
+ "author": "Guilherme Dunguel <guilhermedunguel@gmail.com> (https://github.com/guilhermedunguel)",
29
+ "license": "MIT",
30
+ "homepage": "https://github.com/guilhermedunguel/expo-geo-parser#readme",
31
+ "dependencies": {},
32
+ "devDependencies": {
33
+ "@types/react": "~19.1.1",
34
+ "expo-module-scripts": "^55.0.2",
35
+ "expo": "^55.0.5",
36
+ "react-native": "0.82.1"
37
+ },
38
+ "peerDependencies": {
39
+ "expo": "*",
40
+ "react": "*",
41
+ "react-native": "*"
42
+ }
43
43
  }
@@ -15,12 +15,52 @@ export type Feature = {
15
15
  properties: Record<string, unknown>;
16
16
  };
17
17
 
18
- export type Geometry = {
19
- type: string;
20
- coordinates?: number[][];
21
- geometries?: Geometry[];
18
+ export type Position = [number, number, ...number[]];
19
+
20
+ export type PointGeometry = {
21
+ type: "Point";
22
+ coordinates: Position;
23
+ };
24
+
25
+ export type MultiPointGeometry = {
26
+ type: "MultiPoint";
27
+ coordinates: Position[];
28
+ };
29
+
30
+ export type LineStringGeometry = {
31
+ type: "LineString";
32
+ coordinates: Position[];
33
+ };
34
+
35
+ export type MultiLineStringGeometry = {
36
+ type: "MultiLineString";
37
+ coordinates: Position[][];
22
38
  };
23
39
 
40
+ export type PolygonGeometry = {
41
+ type: "Polygon";
42
+ coordinates: Position[][];
43
+ };
44
+
45
+ export type MultiPolygonGeometry = {
46
+ type: "MultiPolygon";
47
+ coordinates: Position[][][];
48
+ };
49
+
50
+ export type GeometryCollectionGeometry = {
51
+ type: "GeometryCollection";
52
+ geometries: Geometry[];
53
+ };
54
+
55
+ export type Geometry =
56
+ | PointGeometry
57
+ | MultiPointGeometry
58
+ | LineStringGeometry
59
+ | MultiLineStringGeometry
60
+ | PolygonGeometry
61
+ | MultiPolygonGeometry
62
+ | GeometryCollectionGeometry;
63
+
24
64
  export type FeatureCollection = {
25
65
  type: "FeatureCollection";
26
66
  name?: string;