传送与接收 XML


如果需要用非同步对象传送复杂阶层的数据,可以使用 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 数据。


展开阅读全文