如果需要用非同步物件傳送複雜階層的資料,可以使用 XML。如果需要傳送 XML,只需將資料組織為 XML 的字串,open
時使用 'POST'
,並設定請求標頭的 'Content-Type'
為 'text/xml'
,再使用 send
方法將 XML 字串放在本體中傳送出去。例如:
function toXML(data) {
let xml = Object.keys(data)
.map(name => `<${name}>${data[name]}</${name}>`)
.join('');
return `<data>${xml}</data>`;
}
...
let data = { // 假設 data 實際上是由使用者提供
x : 10,
y : 20,
z : 30
};
var request = new XMLHttpRequest();
request.onreadystatechange = handleStateChange; // handleStateChange 參考至函式
request.open('POST', url);
request.setRequestHeader('Content-Type', 'text/xml');
request.send(toXML(data));
上面這個例子,伺服端會收到的 XML 字串為(底下是加了一些排版的結果):
<data>
<x>10</x>
<y>20</y>
<z>30</z>
</data>
當然,伺服端必須剖析 XML 字串,取出所要的資料進行處理。
如果伺服端傳回 XML 字串,可以使用非同步物件的 respnseXML
取得 XML 字串剖析後的 DOM 物件,之後使用 DOM API 取出想要的資料進行處理。例如在〈使用 GET 請求〉的第一個範例中,使用 innerHTML
將傳回的 HTML 字串設定為 <div>
的內部 HTML,但這樣就是伺服端寫死了客戶端的 HTML 外觀,你可以改傳回 XML,由客戶端取出資料,自行決定外觀處理。
例如,若伺服端傳回的 XML 格式如下(注意,伺服端必須設定回應標頭的 "Content-Type"
為 "text/xml"
,XML 若含中文之類的字元,則必須指定 charset
編碼):
<?xml version="1.0" encoding="UTF-8"?>
<select>
<option value="algorithm">常見演算</option>
<option value="graphic">電腦圖學</option>
<option value="pattern">設計模式</option>
</select>
以下是改寫〈使用 GET 請求〉的第一個範例,處理傳回的 XML,為了便於兩個範例對照,暫不使用之前看過的對 XMLHttpRequest
之簡單封裝:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
圖書:<br>
<select id="category">
<option>-- 選擇分類 --</option>
<option value="theory">理論基礎</option>
<option value="language">程式語言</option>
<option value="web">網頁技術</option>
</select><br><br>
採購:<div id="book"></div>
<script type="text/javascript">
document.getElementById('category').onchange = function(evt) {
let request = new XMLHttpRequest();
request.onload = function(evt) {
let req = evt.target;
if(req.status === 200) {
let select = document.createElement('select');
let xml = request.responseXML;
// 取得所有 <option>
let options = xml.getElementsByTagName('option');
Array.from(options).forEach(option => {
// 取得每個 <option> 的 value 屬性
let value = option.getAttribute('value');
// 取得每個 <option></option> 間的文字
// 注意,文字也是節點
let text = option.firstChild.nodeValue;
select.add(
new Option(text, value),
select.options[select.options.length]
);
});
let book = document.getElementById('book');
if(book.firstChild) {
book.removeChild(book.firstChild);
}
book.appendChild(select);
}
};
let time = new Date().getTime();
let url = `XML-1.php?category=${evt.target.value}&time=${time}`;
request.open('GET', url);
request.send(null);
};
</script>
</body>
</html>
上例的執行結果與〈使用 GET 請求〉的第一個範例,處理傳回的 XML,為了便於兩個範例對照,暫不使用之前看過的對 XMLHttpRequest
之簡單封裝雖然一樣,但實際上你可以用任意畫面展現傳回的 XML 資料。