经纬志
首页 / 实战手册 / 数据加载

KML 里的图标写相对路径,加载后全是碎图

先看结论

KML 在 Google Earth 里正常,放进网页地图后每个点都变成一个破碎的小图标。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

一份标注文件 poi.kml,图标写的是 <href>images/pin.png</href>。 在 Google Earth 中打开正常;用 omnivore.kml('poi.kml') 加载到 Leaflet 后,所有点位显示为浏览器默认的破图占位符, 网络面板里出现 GET /cookbook/images/pin.png 404。

原因

KML 规范规定,href 为相对路径时,基准是 KML 文件本身的 URL, 而不是当前页面的 URL。解析库通常按页面地址去拼, 或者把 href 原样塞给 L.icon。

上面的例子里,页面在 /cookbook/ 下,KML 在 /data/poi.kml, 正确的图标地址应是 /data/images/pin.png, 实际请求了 /cookbook/images/pin.png,自然 404。

排查过程

  1. 打开网络面板,筛选 png,看 404 的完整路径。
  2. 把该路径与 KML 的实际地址比对,看基准目录是否一致。
  3. 在 KML 里搜 <href>,看是绝对 URL、相对路径还是 file://。
  4. 把 KML 用文本编辑器打开,确认 <IconStyle> 是否真的存在,有些导出工具根本不写图标。
<Style id="s1">
  <IconStyle>
    <scale>1.0</scale>
    <Icon><href>images/pin.png</href></Icon>
  </IconStyle>
</Style>

解决方案

把 href 改成绝对路径,或在解析后统一重写图标地址。 跨域加载 KML 时相对路径几乎必然失败,绝对路径最省事。

<!-- 改成绝对路径(同源) -->
<Icon><href>/data/images/pin.png</href></Icon>

<!-- 或者内联成 data URI,彻底摆脱路径问题 -->
<Icon><href>data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ...</href></Icon>

解析端也可以拦截,把相对路径按 KML 的 URL 重新拼一次。

const kmlUrl = new URL('/data/poi.kml', location.origin);

omnivore.kml(kmlUrl.href, null, L.geoJSON(null, {
  pointToLayer: (f, ll) => {
    const href = f.properties.styleUrl || 'images/pin.png';
    const iconUrl = new URL(href, kmlUrl).href;    // 以 KML 地址为基准
    return L.marker(ll, { icon: L.icon({ iconUrl, iconSize: [24, 24] }) });
  }
})).addTo(map);

验证

网络面板中图标请求返回 200,路径以 /data/images/ 开头; 地图上所有点位显示正常图标,不再是破图。

console.assert(new URL('images/pin.png', 'http://localhost/data/poi.kml').href
  === 'http://localhost/data/images/pin.png', '基准目录仍不对');

适用版本

组件版本说明
KML / OGC2.2相对 href 以 KML 文件 URL 为基准
Leaflet.omnivore1.0.0不自动改写 href
OpenLayers9.xKML format 解析后仍需处理图标
Google Earth桌面版 / 网页版按文件位置解析,所以本地正常
引用本文

经纬志(2026)。《KML 里的图标写相对路径,加载后全是碎图》。https://www.jingweizhi.com/cookbook/kml-relative-icon.html(访问日期 2026-11-03)。