最近在使用 PHP 5.2 的 SimpleXML 的時候發現了一個奇怪的問題,就是 SimpleXML 對於處理 HTML Special Characters 有不一致處理行為的情況。
這樣的問題將造成由 SimpleXML 產生的 XML 無法再次由 SimpleXML 開啟,我認為這是一個嚴重的 Bug。以下是官方 Bug Trace System 相關的討論文獻。
http://bugs.php.net/bug.php?id=36795
主要的問題是在於使用 SimpleXMLElement::addChild() 與 SimpleXMLElement::addAttribute() 在設定文字時,僅會針對 <> 進行 Escaping 的動作,對於其他的 HTML Special Characters 並不會進行處理。問題來了,當使用 Array Access 的方式操作 DOM 時,卻不會發生這樣的情況。
讓我們寫支程式來測試一下
$testString = '$testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/>';
echo $testString."\r\n";
$simpleXMLElement = new SimpleXMLElement('<root/>');
$simpleXMLElement->testcase_1 = $testString;
$simpleXMLElement->addChild('testcase_2', $testString);
$xml = $simpleXMLElement->asXml();
echo $xml."\r\n";
try {
$readSimpleXMLElement = new SimpleXMLElement($xml);
} catch (Exception $e) {
echo 'no~~';
}
print_r($readSimpleXMLElement);
程式執行結果
$testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/> <?xml version="1.0"?> <root> <testcase_1>$testString = Html Special Characters = ©<> , Html Special Characters (encode) = &copy;&lt;&gt;, Html Tag=<tag/></testcase_1> <testcase_2>$testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/></testcase_2> </root> Warning: SimpleXMLElement::__construct() [simplexmlelement.--construct]: Entity: line 2: parser error : Entity 'copy' not defined
發現問題了嗎?使用addChild有正確將 <> 進行 Escape,但是除了 <> 以外的 HTML 保留字卻不會轉換 (&必須轉換為&)。那要如何解決呢?最簡單的方法就是自行轉換 & 字元為 & 後再送給 addChild(),我們修改一下程式碼,如下:
$testString = '$testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/>';
echo $testString."\r\n";
$simpleXMLElement = new SimpleXMLElement('<root/>');
$simpleXMLElement->testcase_1 = $testString;
$simpleXMLElement->addChild('testcase_2', preg_replace('/&/', '&', $testString));
$xml = $simpleXMLElement->asXml();
echo $xml."\r\n";
try {
$readSimpleXMLElement = new SimpleXMLElement($xml);
} catch (Exception $e) {
echo 'no~~';
}
print_r($readSimpleXMLElement);
程式執行結果
$testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/>
<?xml version="1.0"?>
<root>
<testcase_1>$testString = Html Special Characters = ©<> , Html Special Characters (encode) = &copy;&lt;&gt;, Html Tag=<tag/></testcase_1>
<testcase_2>$testString = Html Special Characters = ©<> , Html Special Characters (encode) = &copy;&lt;&gt;, Html Tag=<tag/></testcase_2>
</root>
SimpleXMLElement Object
(
[testcase_1] => $testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/>
[testcase_2] => $testString = Html Special Characters = ©<> , Html Special Characters (encode) = ©<>, Html Tag=<tag/>
)
沒問題了,如果有使用到 addAttribute() 也要進行一樣的處理喔。當然你也可以採用 Array Access 的方式操作 DOM,但是如果遇到 Namespace 的處理就避免不了要處理這個問題了。
HTML 保留字請參考: