Javascript，XML 轉 JSON
Tags: javascript, xml, json, tutorial
Published: 2022-08-02 03:19:21


## 本篇要解決的問題

平常調用公司同事給的 API，大部份收到的都是 JSON，但總會遇到資料格式是 XML 的狀況，像是一些政府公開資料。而把 XML 轉成 JSON，在用迴圈渲染資料上頁面時會比較方便，也比較習慣。

找了幾個套件，發現大小都蠻大的，而比較小的卻只能在 Node.js 上執行，後來千找萬找，找到了一個很輕量的，XML 轉 JSON，及 JSON 轉 XML，二個加起來不到 10 K。

因為 function 在官方說明頁面就有了，因此本篇除了推薦這個套件，也會實作取一個政府公開的 XML 資料，並放進開源的地圖 OSM 裡，再加上 marker，製作一個捷運站點地圖。

本篇使用的程式碼來源：

[https://goessner.net/download/prj/jsonxml/](https://goessner.net/download/prj/jsonxml/)

最後實作出的 Demo 頁：

[https://letswritetw.github.io/letswrite-xml-to-json/](https://letswritetw.github.io/letswrite-xml-to-json/)

---

## 下載 JS 程式碼

進到官方說明頁面後，會看見有二個 JS 檔可以下載：

- [json2xml.js](https://goessner.net/download/prj/jsonxml/json2xml.js)
- [xml2json.js](https://goessner.net/download/prj/jsonxml/xml2json.js)

本篇會使用的是 xml2json.js，將取到的 XML 資料轉成 JSON。

下載好 xml2json.js 後，別急，還有一個 function 需要複製下來，說明文件往下滑一點，會看到一個名為 `parseXml` 的 function，把這個 function 的程式碼存下來，就可以準備來實作資料轉檔了。

本篇的 Demo，有將 JS 下載起來，並合併成檔案，是為了方便以後要用時可以取用，範例程式碼會用 `import` 的方式引入。

```javascript
import { parseXml, xml2json } from 'xml2json';

fetch('xxxxxxx')
  .then(res => res.text())
  .then(res => {
    let data = xml2json(parseXml(res), '')
    console.log(JSON.parse(data));
  })
```

---

## 取 XML 資料並轉成 JSON

這次在政府開放資料平台上，找到一個 XML 的資料：[臺北捷運車站資料服務](https://data.gov.tw/dataset/131734)，裡面會回傳捷運各個站的地址、座標。

把資料 fetch 回來，console.log 會看到回來的資料：

```javascript
import { parseXml, xml2json } from 'xml2json';

document.addEventListener('DOMContentLoaded', () => {
	
  const api = 'https://ptx.transportdata.tw/MOTC/v2/Rail/Metro/Station/TRTC?$format=xml';
  fetch(api)
    .then(res => res.text())
    .then(res => {
      const data = xml2json(parseXml(res), '')
      console.log(JSON.parse(data));
    })

})
```

得到的資料會像這樣：

![XML 轉 JSON 後的資料](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64wrm5slkrz0b1sspu01.png)

可以看到所有捷運站的資料都在 `data.ArrayOfStation.Station` 裡，把它存進變數後就可以來使用。

---

## 轉出 JSON 的資料放進 OSM

這幾天正在回頭看 Leaflet.js + OpenStreetMap，本篇來做一個把資料裡的座標丟進開源地圖的 Demo。

Leaflet + OSM 的學習筆記在這，這邊不會把每一行在做什麼的說明都寫出來，請各位自己打開連結看囉：

- [建地圖、marker、事件、換圖層](https://www.letswrite.tw/leaflet-osm-basic/)
- [移動中心點、抓目前地點](https://www.letswrite.tw/leaflet-osm-locate/)

Demo 頁上主要就是地圖繪好後，把每個捷運站的座標寫進 marker 裡，marker 綁 Popup 寫捷運站的名稱及地址。

繪製地圖的部份，找一個深色模式的地圖：

```javascript
const center = [25.03, 121.57];
const zoom = 13;
const map = L.map('map').setView(center, zoom);
L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
  attribution: '&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
}).addTo(map);
```

第一步繪上基本地圖的樣子：

![繪製地圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bliy5surtzvtr1ckixw6.jpg)

接著就是把從 XML 轉成 JSON 的資料，用迴圈把座標、站名、地址給取出來，建 marker 放上地圖。

```javascript
Array.prototype.forEach.call(dataFormat, data => {
  let lat = data.StationPosition.PositionLat;
  let lon = data.StationPosition.PositionLon;
  let name = data.StationName.Zh_tw + '站';
  let address = data.StationAddress;
  let marker = L.marker([lat, lon], {
    title: name
  }).bindPopup(`<b>${name}</b><br/>${address}`)
    .addTo(map);
})
```

本篇的 Demo 有客製 marker 的樣式，最後出來會像這樣：

![marker 放上地圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zqbi9op71xu95i1c9tlq.png)

最後放上一個套件，下一篇文章會寫到的「[Leaflet.Locate](https://www.letswrite.tw/leaflet-plugins/)」，點擊左上角的箭頭按鈕，便可以定位目前所在的位置，看到附近有什麼捷運站了。