AJAX XML

Serving XML, parsing it client-side, and why JSON won.

Beginner
Key PointsXML is verbose but supports attributes, namespaces and schema validation.

Serving XML

PHP
<?php
// /api/users.xml.php
header("Content-Type: application/xml; charset=utf-8");

$doc = new DOMDocument("1.0", "UTF-8");
$doc->formatOutput = true;

$root = $doc->createElement("users");
$doc->appendChild($root);

foreach ([["1", "Tom", "tom@example.com"], ["2", "Amy", "amy@example.com"]] as [$id, $name, $email]) {
    $u = $doc->createElement("user");
    $u->setAttribute("id", $id);
    $u->appendChild($doc->createElement("name", $name));
    $u->appendChild($doc->createElement("email", $email));
    $root->appendChild($u);
}

echo $doc->saveXML();
Output
<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user id="1">
    <name>Tom</name>
    <email>tom@example.com</email>
  </user>
  <user id="2">
    <name>Amy</name>
    <email>amy@example.com</email>
  </user>
</users>

Parsing on the client

JavaScript
async function loadUsers() {
  const res = await fetch("/api/users.xml.php");
  const text = await res.text();

  const doc = new DOMParser().parseFromString(text, "application/xml");

  const err = doc.querySelector("parsererror");
  if (err) throw new Error("XML 解析失败: " + err.textContent);

  const users = [...doc.querySelectorAll("user")].map(u => ({
    id: u.getAttribute("id"),
    name: u.querySelector("name").textContent,
    email: u.querySelector("email").textContent,
  }));

  console.log(users);
}

The parsed structure:

Output
[{ id: "1", name: "Tom", email: "tom@example.com" },
 { id: "2", name: "Amy", email: "amy@example.com" }]
DOMParser does not throw on failure; it produces a document containing <parsererror>. Skip that check and you get a confusing null-property error later.

XML vs JSON

AspectXMLJSON
Verbosity高,成对标签低
Attributes支持不支持,只能嵌套
Namespaces支持不支持
SchemaXSD / DTDJSON Schema
Native in JS需要 DOMParserJSON.parse
Binary需 Base64需 Base64
Typical useSOAP、RSS、Office 文档、企业集成REST API、配置文件

Supporting both

Serve different formats based on the Accept header — content negotiation.

PHP
<?php
$items = [
    ["id" => 1, "name" => "Tom"],
    ["id" => 2, "name" => "Amy"],
];

$accept = $_SERVER["HTTP_ACCEPT"] ?? "application/json";

if (str_contains($accept, "application/xml")) {
    header("Content-Type: application/xml; charset=utf-8");

    $doc = new DOMDocument("1.0", "UTF-8");
    $root = $doc->createElement("items");
    $doc->appendChild($root);
    foreach ($items as $it) {
        $n = $doc->createElement("item");
        $n->setAttribute("id", (string)$it["id"]);
        $n->appendChild($doc->createElement("name", $it["name"]));
        $root->appendChild($n);
    }
    echo $doc->saveXML();
} else {
    header("Content-Type: application/json; charset=utf-8");
    echo json_encode($items, JSON_UNESCAPED_UNICODE);
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<items><item id="1"><name>Tom</name></item><item id="2"><name>Amy</name></item></items>
New endpoints should return JSON by default. XML is only for legacy integrations — SOAP, banking, government systems.

Friends & Partners