PHP输出XML无效导致JS读取xmlDoc为空的问题及解决方法
PHP返回XML无法被前端JS识别的问题修复方案
问题背景
需要实现JS+PHP联动,将数据库中的数据渲染为前端表格,过程中遇到PHP返回的XML无法被JS正常解析的问题。
原始代码
初始PHP代码(两种XML生成方案均失效)
<?php $serverName = "localhost"; $userName = "***"; $password = "***"; $DBName = "DataBase1"; // Connect to DB $connection = mysqli_connect($serverName, $userName, $password, $DBName); if (!$connection) { die("Connection failed: " . mysqli_connect_error()); } else { //echo "Connected to DB<br>"; } // Collect data $selectionSD = $connection->query("SELECT * FROM `SensorData`"); $selectionSL = $connection->query("SELECT * FROM `SensorLog`"); // Generating XML file //$xmlSD = new XMLWriter(); //$xmlSD->openUri("php://output"); //$xmlSD->startDocument(); //$xmlSD->setIndent(true); //$xmlSD->startElement("SensorDataTable"); //while ($row = mysqli_fetch_assoc($selectionSD)) //{ // $xmlSD->startElement("SensorData"); // $xmlSD->startElement("ID"); // $xmlSD->writeRaw($row["ID"]); // $xmlSD->endElement(); // $xmlSD->startElement("SID"); // $xmlSD->writeRaw($row["SID"]); // $xmlSD->endElement(); // $xmlSD->startElement("Value"); // $xmlSD->writeRaw($row["Value"]); // $xmlSD->endElement(); // $xmlSD->startElement("Comment"); // $xmlSD->writeRaw($row["Comment"]); // $xmlSD->endElement(); // $xmlSD->startElement("DateTime"); // $xmlSD->writeRaw($row["DateTime"]); // $xmlSD->endElement(); // $xmlSD->endElement(); //} //$xmlSD->endElement(); //header("Content-type: text/xml"); //$xmlSD->flush(); //$xmlSD->endDocument(); // Test code $document = new DOMDocument('1.0', 'utf-8'); $document->formatOutput = true; $root = $document->createElement('SensorDataTable'); $root = $document->appendChild($root); while ($row = mysqli_fetch_assoc($selectionSD)) { $node = $document->createElement('SensorData'); $node = $root->appendChild($node); // ID $dataNode = $document->createElement('ID'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["ID"]); $data = $dataNode->appendChild($data); // SID $dataNode = $document->createElement('SID'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["SID"]); $data = $dataNode->appendChild($data); // Value $dataNode = $document->createElement('Value'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["Value"]); $data = $dataNode->appendChild($data); // Comment $dataNode = $document->createElement('Comment'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["Comment"]); $data = $dataNode->appendChild($data); // DateTime $dataNode = $document->createElement('DateTime'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["DateTime"]); $data = $dataNode->appendChild($data); } echo $document->saveXML(); // Close DB connection $connection->close(); ?>
上述代码中注释段为首次使用的XMLWriter生成方案,未注释段为改用DOMDocument的测试方案,两种方案均未解决问题。
前端JS解析代码
console.log(xml); let i; const xmlDoc = xml.responseXML; if (xmlDoc === null) { console.log("Failed to get response."); } let table = "<tr><th>SID</th><th>Value</th></tr>"; const x = xmlDoc.getElementsByTagName("SensorData"); for (i = 0; i < x.length; i++) { table += "<tr><td class='center'>" + x[i].getElementsByTagName("SID")[0].childNodes[0].nodeValue + "</td><td class='center'>" + x[i].getElementsByTagName("Value")[0].childNodes[0].nodeValue + "</td></tr>"; } console.log("Changing DB display"); document.getElementById("DB").innerHTML = table;
代码中xml变量指向PHP接口的访问路径。
问题现象
- JS运行时提示
xmlDoc为null,但读取本地静态XML文件时逻辑完全正常 - 直接访问PHP接口,输出的XML内容格式完全符合预期,如下:
<?xml version="1.0" encoding="utf-8"?> <SensorDataTable> <SensorData> <ID>1</ID> <SID>1</SID> <Value>19.50</Value> <Comment>DHT_Temp</Comment> <DateTime>2021-10-04 12:57:51</DateTime> </SensorData> <SensorData> <ID>2</ID> <SID>2</SID> <Value>57.50</Value> <Comment>DHT_Humi</Comment> <DateTime>2021-10-04 12:57:55</DateTime> </SensorData> <SensorData> <ID>3</ID> <SID>1</SID> <Value>19.60</Value> <Comment>DHT_Temp</Comment> <DateTime>2021-10-04 12:58:29</DateTime> </SensorData> <SensorData> <ID>4</ID> <SID>2</SID> <Value>57.20</Value> <Comment>DHT_Humi</Comment> <DateTime>2021-10-04 12:58:32</DateTime> </SensorData> </SensorDataTable>
根因分析
PHP默认返回的Content-Type响应头为text/html,浏览器接收到响应后不会将其识别为XML格式,因此XMLHttpRequest.responseXML属性会返回null。
修复方案
在PHP输出XML内容前,添加响应头声明指定返回内容格式为XML:header("Content-type: text/xml");
修复后的完整PHP代码
<?php $serverName = "localhost"; $userName = "***"; $password = "***"; $DBName = "LIDAc"; // Connect to DB $connection = mysqli_connect($serverName, $userName, $password, $DBName); if (!$connection) { die("Connection failed: " . mysqli_connect_error()); } // Collect data $selectionSD = $connection->query("SELECT * FROM `SensorData`"); $selectionSL = $connection->query("SELECT * FROM `SensorLog`"); // Generate XML file $document = new DOMDocument('1.0', 'utf-8'); $document->formatOutput = true; $root = $document->createElement('SensorDataTable'); $root = $document->appendChild($root); while ($row = mysqli_fetch_assoc($selectionSD)) { $node = $document->createElement('SensorData'); $node = $root->appendChild($node); // ID $dataNode = $document->createElement('ID'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["ID"]); $data = $dataNode->appendChild($data); // SID $dataNode = $document->createElement('SID'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["SID"]); $data = $dataNode->appendChild($data); // Value $dataNode = $document->createElement('Value'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["Value"]); $data = $dataNode->appendChild($data); // Comment $dataNode = $document->createElement('Comment'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["Comment"]); $data = $dataNode->appendChild($data); // DateTime $dataNode = $document->createElement('DateTime'); $dataNode = $node->appendChild($dataNode); $data = $document->createTextNode($row["DateTime"]); $data = $dataNode->appendChild($data); } header("Content-type: text/xml"); echo $document->saveXML(); // Close DB connection $connection->close(); ?>
内容的提问来源于stack exchange,提问作者Lenny
相关产品推荐
相关产品推荐

