feat(parser): carry the Folder path on every placemark - #26
Merged
Conversation
Placemarks are collected with a flat //kml:Placemark query, so a document organised into folders came back as one undifferentiated list and the structure the author put there was lost. Anyone grouping a map by folder had to parse the file a second time themselves. Each placemark now carries a folder key holding the names of the Folder elements containing it, outermost first, and an empty array when it sits directly under the Document. The list stays flat, so nothing is duplicated and grouping is a one-liner for the caller. A Folder without a name contributes an empty string rather than being skipped, so the length of the path always matches the real nesting depth. Rather than walking the tree twice, each placemark is asked for its own ancestors, which also keeps this working on the legacy namespaces since the prefix is registered per node. toGeoJson() carries the path into properties, but only for a placemark that is actually in a folder, so output for flat documents is unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
//matches at any depth, which is what makes the parser find placemarks inside folders at all. It is also what makes the folders invisible: a document organised into<Folder>elements came back as one flat, undifferentiated list.That structure is not decoration. It is how the author grouped the map, and in a Google My Maps export it is usually the layer names. Anyone who needed it had to parse the file a second time themselves, which defeats the point of the package.
The README listed
Folderunder "no", with "folders are flattened, the hierarchy is lost".Fix
Every placemark carries a
folderkey:[ 'name' => 'Lago Blu', 'description' => 'A lake', 'folder' => ['Piemonte', 'Laghi'], 'type' => 'Point', 'coordinates' => [...], ]Outermost first, empty array for a placemark sitting directly under the
Document.Why a key rather than a tree
A
getFolders()returning a nested structure with the placemarks inside was the obvious alternative. It was rejected because it means the same placemarks exist in two representations that have to be kept in step, and every caller then has to decide which one to read.The flat list plus a path is smaller, has no duplication, and grouping stays a one-liner:
Unnamed folders
A
<Folder>with no<name>contributes an empty string rather than being skipped. Skipping it would make['Piemonte']mean both "one level deep inside Piemonte" and "two levels deep, inside an unnamed folder inside Piemonte". The path length always matches the real nesting depth.How it is resolved
Each placemark is asked for its own ancestors with
ancestor::kml:Folder, rather than walking the tree a second time and re-associating the results. Thekmlprefix is registered on the placemark node itself, so this keeps working on the legacyearth.google.comnamespaces, which is covered by a test rather than assumed.GeoJSON
folderis carried intoproperties, but only for a placemark that is actually in one. Adding'folder' => []to every feature of every flat document would be noise in the payload, and it matches howstyleUrlandextendedDataalready behave.A flat document produces byte-identical GeoJSON to before. The existing exact-array test in
tests/GeoJsonOutputTest.phpstill passes untouched, which is the evidence for that.Tests
tests/FolderHierarchyTest.php, 9 tests against one document containing a loose placemark, a named folder, a folder nested inside it, an unnamed folder and a sibling folder:[]earth.google.com/kml/2.1documentSuite 79 to 88. PHPStan and Pint clean.
Behaviour change
getPlacemarks()entries gain a key. Additive, but a test comparing a whole placemark array with===or Pest'stoBe()will notice. Worth a changelog line.README updated: the
Folderrow moves to supported, the shapes gainfolder, and the grouping snippet is documented.