[英]CakePHP Xml utility library triggers DOMDocument warning
我正在使用CakePHP的Xml核心庫在視圖中生成XML:
$xml = Xml::build($data, array('return' => 'domdocument'));
echo $xml->saveXML();
視圖由帶有陣列的控制器提供:
$this->set(
array(
'data' => array(
'root' => array(
array(
'@id' => 'A & B: OK',
'name' => 'C & D: OK',
'sub1' => array(
'@id' => 'E & F: OK',
'name' => 'G & H: OK',
'sub2' => array(
array(
'@id' => 'I & J: OK',
'name' => 'K & L: OK',
'sub3' => array(
'@id' => 'M & N: OK',
'name' => 'O & P: OK',
'sub4' => array(
'@id' => 'Q & R: OK',
'@' => 'S & T: ERROR',
),
),
),
),
),
),
),
),
)
);
無論出於何種原因,CakePHP正在發出如下內部調用:
$dom = new DOMDocument;
$key = 'sub4';
$childValue = 'S & T: ERROR';
$dom->createElement($key, $childValue);
...觸發PHP警告:
Warning (2): DOMDocument::createElement(): unterminated entity reference T [CORE\Cake\Utility\Xml.php, line 292
...因為( 如文檔所述 ), DOMDocument::createElement
不會轉義值。 但是,正如測試案例所示,它只在某些節點中執行。
我做錯了什么或者我只是在CakePHP中遇到了一個錯誤?
這可能是PHP DOMDocument::createElement()
方法中的一個錯誤 。 你可以避免它。 單獨創建textnode並將其附加到元素節點。
$dom = new DOMDocument;
$dom
->appendChild($dom->createElement('element'))
->appendChild($dom->createTextNode('S & T: ERROR'));
var_dump($dom->saveXml());
輸出: https : //eval.in/134277
string(58) "<?xml version="1.0"?>
<element>S & T: ERROR</element>
"
這是將文本節點添加到DOM的預期方法。 您始終創建一個節點(element,text,cdata,...)並將其附加到其父節點。 您可以向一個父節點添加多個節點和不同類型的節點。 如下例所示:
$dom = new DOMDocument;
$p = $dom->appendChild($dom->createElement('p'));
$p->appendChild($dom->createTextNode('Hello '));
$b = $p->appendChild($dom->createElement('b'));
$b->appendChild($dom->createTextNode('World!'));
echo $dom->saveXml();
輸出:
<?xml version="1.0"?>
<p>Hello <b>World!</b></p>
這實際上是因為DOMDocument方法需要在html中輸出正確的字符; 也就是說, &
等字符會破壞內容並生成unterminated entity reference
錯誤
只是htmlentities()在使用它創建元素之前:
$dom = new DOMDocument;
$key = 'sub4';
$childValue = htmlentities('S & T: ERROR');
$dom->createElement($key ,$childValue);
這是因為這個角色: &
你需要用相關的HTML實體替換它。 &
要執行轉換,可以使用htmlspecialchars函數。 在寫入nodeValue屬性時,必須轉義該值。 作為從一個bug報告,2005年引用位於這里
在設置屬性textContent時正確編碼&符號。 不幸的是,當文本字符串作為DOMElement :: createElement的可選第二個參數傳遞時,它們不會被編碼您必須創建一個文本節點,設置textContent,然后將文本節點附加到新元素。
htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
這是翻譯表:
'&' (ampersand) becomes '&'
'"' (double quote) becomes '"' when ENT_NOQUOTES is not set.
"'" (single quote) becomes ''' (or ') only when ENT_QUOTES is set.
'<' (less than) becomes '<'
'>' (greater than) becomes '>'
該腳本將以遞歸方式執行翻譯:
<?php
function clean($type) {
if(is_array($type)) {
foreach($type as $key => $value){
$type[$key] = clean($value);
}
return $type;
} else {
$string = htmlspecialchars($type, ENT_QUOTES, 'UTF-8');
return $string;
}
}
$data = array(
'data' => array(
'root' => array(
array(
'@id' => 'A & B: OK',
'name' => 'C & D: OK',
'sub1' => array(
'@id' => 'E & F: OK',
'name' => 'G & H: OK',
'sub2' => array(
array(
'@id' => 'I & J: OK',
'name' => 'K & L: OK',
'sub3' => array(
'@id' => 'M & N: OK',
'name' => 'O & P: OK',
'sub4' => array(
'@id' => 'Q & R: OK',
'@' => 'S & T: ERROR',
) ,
) ,
) ,
) ,
) ,
) ,
) ,
) ,
);
$data = clean($data);
產量
Array
(
[data] => Array
(
[root] => Array
(
[0] => Array
(
[@id] => A & B: OK
[name] => C & D: OK
[sub1] => Array
(
[@id] => E & F: OK
[name] => G & H: OK
[sub2] => Array
(
[0] => Array
(
[@id] => I & J: OK
[name] => K & L: OK
[sub3] => Array
(
[@id] => M & N: OK
[name] => O & P: OK
[sub4] => Array
(
[@id] => Q & R: OK
[@] => S & T: ERROR
)
)
)
)
)
)
)
)
)
問題似乎是在具有屬性和值的節點中因此需要使用@
語法:
'@id' => 'A & B: OK', // <-- Handled as plain text
'name' => 'C & D: OK', // <-- Handled as plain text
'@' => 'S & T: ERROR', // <-- Handled as raw XML
我寫了一個小助手功能:
protected function escapeXmlValue($value){
return is_null($value) ? null : htmlspecialchars($value, ENT_XML1, 'UTF-8');
}
...並在創建數組時手動調用它:
'@id' => 'A & B: OK',
'name' => 'C & D: OK',
'@' => $this->escapeXmlValue('S & T: NOW WORKS FINE'),
由於文檔沒有提到它,很難說它是否是錯誤或功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.