Use built-in DOMDocument methods
Xml::build()
returns an instance of either SimpleXMLElement
(default) or DOMDocument
. The latter has a built-in method for creating processing instruction nodes, DOMDocument::createProcessingInstruction()
.
$xml = Xml::build($value, array('return' => 'domdocument'));
$style = $xml->createProcessingInstruction(
'xml-stylesheet',
'type="text/xsl" href="/path/to/style.xsl"'
);
$xml->insertBefore($style, $xml->firstChild);
echo $xml->saveXML();
This would output something like:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/path/to/style.xsl"?>
<tags>
...
</tags>
See also
Manipulating XmlView output
When using XmlView
there is no way to hook into the XML generation process, as it's finally generated using a simple one-liner:
return Xml::fromArray($data, $options)->asXML();
So the only option here would be to take the generated output and process it again. For example extend the XmlView
, override the _serialize()
method, and then take that generated output, create a new DOMDocument
instance from it, and add the PI nodes if necessary.
Here's an (untested) example of such an exteneded view:
App::uses('XmlView', 'View');
class MyXmlView extends XmlView {
protected function _serialize($serialize) {
$xml = parent::_serialize($serialize);
if(isset($this->viewVars['_processingInstructions'])) {
$pi = array_reverse($this->viewVars['_processingInstructions']);
$doc = new DOMDocument();
$doc->loadXML($xml);
foreach($pi as $instruction) {
$node = $doc->createProcessingInstruction(
current(array_keys($instruction)),
current($instruction)
);
$doc->insertBefore($node, $doc->firstChild);
}
$xml = $doc->saveXML();
}
return $xml;
}
}
In the controller one could then set the _processingInstructions
view variable to define PI nodes:
$_processingInstructions = array(
array('xml-stylesheet' => 'type="text/xsl" href="/path/to/style.xsl"')
);
$this->set(compact('tags', '_processingInstructions'));
$this->set('_serialize', 'tags');