I'm generating XML in a view with CakePHP's Xml core library:
$xml = Xml::build($data, array('return' => 'domdocument'));
echo $xml->saveXML();
View is fed from the controller with an array:
$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',
),
),
),
),
),
),
),
),
)
);
For whatever the reason, CakePHP is issuing an internal call like this:
$dom = new DOMDocument;
$key = 'sub4';
$childValue = 'S & T: ERROR';
$dom->createElement($key, $childValue);
... which triggers a PHP warning:
Warning (2): DOMDocument::createElement(): unterminated entity reference T [CORE\Cake\Utility\Xml.php, line 292
... because (as documented), DOMDocument::createElement
does not escape values. However, it only does it in certain nodes, as the test case illustrates.
Am I doing something wrong or I just hit a bug in CakePHP?
The problem seems to be in nodes that have both attributes and values thus need to use the
@
syntax:I've written a little helper function:
... and take care of calling it manually when I create the array:
It's hard to say if it's bug or feature since the documentation doesn't mention it.
it is because of this character:
&
You need to replace that with the relevant HTML entity.&
To perform the translation, you can use the htmlspecialchars function. You have to escape the value when writing writing to the nodeValue property. As quoted from a bug report in 2005 located hereThis is the translation table:
This script will do the translations recursively:
Output
This might a bug in PHPs
DOMDocument::createElement()
method. You can avoid it. Create the textnode separately and append it to the element node.Output: https://eval.in/134277
This is the intended way to add text nodes to a DOM. You always create a node (element, text , cdata, ...) and append it to its parent node. You can add more then one node and different kind of nodes to one parent. Like in the following example:
Output:
This is in fact because the DOMDocument methods wants correct characters to be outputted in html; that is, characters such as
&
will break content and generate aunterminated entity reference
errorjust htmlentities() it before using it to create elements: