Skip to content

feat(validator): accept the legacy KML namespaces - #15

Merged
danielebarbaro merged 1 commit into
fix/xml-parsing-and-error-handlingfrom
feat/legacy-kml-namespaces
Sep 8, 2026
Merged

feat(validator): accept the legacy KML namespaces#15
danielebarbaro merged 1 commit into
fix/xml-parsing-and-error-handlingfrom
feat/legacy-kml-namespaces

Conversation

@danielebarbaro

Copy link
Copy Markdown
Contributor

Stacked on #14. Base branch is fix/xml-parsing-and-error-handling, not main. Both PRs rewrite loadFromString(), so branching this one off main would guarantee a conflict. Merge #14 first and this retargets to main on its own.

Problem

Legacy namespaces are rejected outright

KmlValidator hardcoded a single namespace and demanded an exact match:

protected string $namespace = 'http://www.opengis.net/kml/2.2';
// ...
if (! isset($namespaces['']) || $namespaces[''] !== $this->namespace) {
    throw new KmlException('Invalid or missing KML namespace');
}

KML predates the OGC. Google Earth and a long tail of exporters emit http://earth.google.com/kml/2.0, 2.1 and 2.2, and those files are still very much in circulation. Every one of them fails with Invalid or missing KML namespace and cannot be parsed at all.

Verified before the change:

KML 2.1 ns: KmlException -> Invalid or missing KML namespace

The namespace config key was inert, and setting it broke everything

KmlParser::__construct() reads config('kml-parser.namespace'). KmlValidator does not, and it runs first. So the key had no effect on what was accepted, and pointing it at anything other than 2.2 made the parser reject every document: validation still demanded 2.2, and the config value was only used afterwards for XPath registration.

XPath was registered against the assumed namespace

Even if validation had let a 2.1 document through, registerXPathNamespace('kml', $this->namespace) bound the prefix to 2.2. Every //kml:Placemark query would have matched nothing, so the parser would have quietly returned empty arrays instead of failing.

Fix

  • KmlValidator takes a list of accepted namespaces, defaulting to KmlValidator::DEFAULT_NAMESPACES (OGC 2.2 plus the three earth.google.com variants).
  • The validator records the namespace the document declared and exposes it through documentNamespace().
  • KmlParser registers XPath against that namespace, so queries run against what the file actually says.
  • New config key supported_namespaces. KmlParser merges it with the existing namespace key and hands the result to the validator, so namespace finally does something.
  • KmlValidator keeps working outside Laravel: the defaults are a class constant, and it never touches the container.

Tests

tests/NamespaceSupportTest.php:

  • a 2.2 document parses (unchanged behaviour)
  • 2.0, 2.1 and 2.2 earth.google.com documents parse end to end, placemarks and document name included — these fail on main
  • a genuinely wrong namespace is still rejected
  • a namespace added through supported_namespaces is accepted
  • the primary namespace key alone is enough, with supported_namespaces empty
  • documentNamespace() reports what the document declared

Breaking change

KmlValidator::$namespace (protected, string) is replaced by $namespaces (protected, array). Only relevant to anyone subclassing the validator. Worth a changelog line.

Documents that were previously rejected are now accepted, which is the point, but it does mean loadFromString() succeeds on input that used to throw.

KmlValidator hardcoded the OGC 2.2 namespace and rejected everything
else, so any document exported before the OGC took the format over
(earth.google.com/kml/2.0, 2.1 and 2.2, still common in the wild) failed
validation with "Invalid or missing KML namespace" and could not be
parsed at all.

The accepted namespaces are now a list, configurable through the new
supported_namespaces key, and XPath is registered against the namespace
the document actually declares rather than the one we assumed. That last
part is what makes a 2.1 document parse end to end instead of validating
and then returning no placemarks.

The validator also ignored the kml-parser.namespace config entirely,
even though KmlParser read it. Setting that key made every document
invalid, since validation still demanded 2.2. KmlParser now passes the
configured namespaces to the validator, so the key finally does what it
says. KmlValidator keeps working standalone, defaulting to the known
namespaces without touching the container.
@danielebarbaro
danielebarbaro merged commit 1d06a29 into fix/xml-parsing-and-error-handling Sep 8, 2026
19 checks passed
@danielebarbaro
danielebarbaro deleted the feat/legacy-kml-namespaces branch September 8, 2026 12:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant