View source
<?php
class FrxReportEditor {
public $dom;
public $document_root;
public $simplexml;
public $title;
public $doc_prefix = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY nbsp " ">
]>';
public $xmlns = 'urn:FrxReports';
private $xpq;
public function __construct($xml_string = '') {
$this->dom = new DOMDocument('1.0', 'UTF-8');
$dom = $this->dom;
if ($xml_string) {
$xml_string = str_ireplace('<?xml version="1.0"?>', '', $xml_string);
if (strpos($xml_string, '<?xml') === FALSE) {
$xml_string = $this->doc_prefix . "\n" . $xml_string;
}
}
else {
$xml_string = $this->doc_prefix . '<html xmlns:frx="urn:FrxReports"><head/><body/></html>';
}
libxml_use_internal_errors();
try {
$dom
->loadXML($xml_string);
} catch (Exception $e) {
forena_error('Invalid or malformed report document', '<pre>' . $e
->getMessage() . $e
->getTraceAsString() . '</pre>');
}
$this
->verifyHeaderElements();
$tnodes = $dom
->getElementsByTagName('title');
if ($tnodes->length) {
$this->title = $tnodes
->item(0)->textContent;
}
$this->document_root = $dom->documentElement;
$this->simplexml = simplexml_import_dom($dom);
$dom->formatOutput = TRUE;
$this->xpq = new DOMXPath($dom);
$this->xpq
->registerNamespace('frx', $this->xmlns);
}
public function asXML() {
$dom = $this->dom;
$dom->formatOutput = TRUE;
return $dom
->saveXML();
}
public function setValue($xpath, $value) {
$xml = $this->simplexml;
$i = strrpos($xpath, '/');
$path = substr($xpath, 0, $i);
$key = substr($xpath, $i + 1);
$nodes = $xml
->xpath($path);
if ($nodes) {
if (strpos($key, '@') === 0) {
$key = trim($key, '@');
if (is_null($value)) {
unset($nodes[0][$key]);
}
else {
$nodes[0][$key] = $value;
}
}
else {
if (is_null($value)) {
unset($nodes[0]->{$key});
}
else {
$nodes[0]->{$key} = $value;
}
}
return TRUE;
}
else {
return FALSE;
}
}
public function setBody($body) {
$dom = $this->dom;
$nodes = $dom
->getElementsByTagName('body');
$cur_body = $nodes
->item(0);
if (strpos($body, '<body') === FALSE) {
$body = '<body>' . $body . '</body>';
}
$body_doc = new DOMDocument('1.0', 'UTF-8');
$body_xml = $this->doc_prefix . '<html xmlns:frx="' . $this->xmlns . '">' . $body . '</html>';
try {
$body_doc
->loadXML($body_xml);
$new_body = $dom
->importNode($body_doc
->getElementsByTagName('body')
->item(0), TRUE);
$parent = $cur_body->parentNode;
$parent
->replaceChild($new_body, $cur_body);
} catch (Exception $e) {
forena_error('Malformed report body', '<pre>' . $e
->getMessage() . $e
->getTraceAsString() . '</pre>');
}
}
public function verifyHeaderElements($required_elements = array()) {
if (!$required_elements) {
$required_elements = array(
'category',
'options',
'fields',
'parameters',
'docgen',
);
}
$dom = $this->dom;
$head = $dom
->getElementsByTagName('head')
->item(0);
if ($dom
->getElementsByTagName('title')->length == 0) {
$n = $dom
->createElement('title');
$head
->appendChild($n);
}
foreach ($required_elements as $tag) {
if ($dom
->getElementsByTagNameNS($this->xmlns, $tag)->length == 0) {
$n = $dom
->createElementNS($this->xmlns, $tag);
$head
->appendChild($n);
}
}
}
public function setFrxHeader($parent, $element, $element_array, $attributes, $element_field = '', $id_field = 'id') {
$dom = $this->dom;
$xpq = $this->xpq;
$this
->verifyHeaderElements(array(
$parent,
));
$pnode = $dom
->getElementsByTagNameNS($this->xmlns, $parent)
->item(0);
$tnode = $dom
->createTextNode("\n");
$pnode
->appendChild($tnode);
foreach ($element_array as $element_data) {
$id = $element_data[$id_field];
$path = '//frx:' . $parent . '/frx:' . $element . '[@' . $id_field . '="' . $id . '"]';
$nodes = $xpq
->query($path);
$value = null;
if ($element && isset($element_data[$element_field])) {
$value = $element_data[$element_field];
}
$node = $dom
->createElementNS($this->xmlns, $element, trim($value, "|"));
if ($nodes->length == 0) {
$tnode = $dom
->createTextNode(" ");
$pnode
->appendChild($tnode);
$pnode
->appendChild($node);
$tnode = $dom
->createTextNode("\n");
$pnode
->appendChild($tnode);
}
else {
$src_node = $nodes
->item(0);
$pnode
->replaceChild($node, $src_node);
}
foreach ($attributes as $attribute) {
if (!empty($element_data[$attribute])) {
$node
->setAttribute($attribute, $element_data[$attribute]);
}
else {
if ($node
->hasAttribute($attribute)) {
$node
->removeAttribute($attribute);
}
}
}
}
}
public function setFields($fieldElements) {
$dom = $this->dom;
$newFields = $dom
->createElementNS($this->xmlns, 'fields');
$this
->verifyHeaderElements(array(
'fields',
));
$fnode = $dom
->getElementsByTagNameNS($this->xmlns, 'fields')
->item(0);
$p = $fnode->parentNode;
$p
->replaceChild($newFields, $fnode);
$this
->setFrxHeader('fields', 'field', $fieldElements, array(
'id',
'link',
'format',
'format-string',
'target',
), 'default');
}
public function setDocgen($docgenElements) {
$dom = $this->dom;
$newDocs = $dom
->createElementNS($this->xmlns, 'docgen');
$this
->verifyHeaderElements(array(
'docgen',
));
$dnode = $dom
->getElementsByTagNameNS($this->xmlns, 'docgen')
->item(0);
$p = $dnode->parentNode;
$p
->replaceChild($newDocs, $dnode);
$this
->setFrxHeader('docgen', 'doc', $docgenElements, array(
'type',
), null, 'type');
}
public function setParameters($parmElements) {
$dom = $this->dom;
$newParms = $dom
->createElementNS($this->xmlns, 'parameters');
$this
->verifyHeaderElements(array(
'parameters',
));
$fnode = $dom
->getElementsByTagNameNS($this->xmlns, 'parameters')
->item(0);
$p = $fnode->parentNode;
$p
->replaceChild($newParms, $fnode);
$this
->setFrxHeader('parameters', 'parm', $parmElements, array(
'id',
'label',
'require',
'desc',
'data_source',
'data_field',
'type',
), 'value');
}
public function setTitle($title) {
$dom = $this->dom;
$head = $dom
->getElementsByTagName('head')
->item(0);
$tnode = $dom
->getElementsByTagName('title')
->item(0);
$node = $dom
->createElement('title', $title);
$head
->replaceChild($node, $tnode);
}
public function setCategory($category) {
$ret = array();
$dom = $this->dom;
$this
->verifyHeaderElements(array(
'category',
));
$head = $dom
->getElementsByTagName('head')
->item(0);
$cnode = $dom
->getElementsByTagNameNS($this->xmlns, 'category')
->item(0);
$node = $dom
->createElementNS($this->xmlns, 'category', $category);
$head
->replaceChild($node, $cnode);
}
public function getCategory() {
$dom = $this->dom;
$this
->verifyHeaderElements(array(
'category',
));
$cnode = $dom
->getElementsByTagNameNS($this->xmlns, 'category')
->item(0);
return $cnode->textContent;
}
public function getOptions() {
$dom = $this->dom;
$this
->verifyHeaderElements(array(
'options',
));
$opts = $dom
->getElementsByTagNameNS($this->xmlns, 'options')
->item(0);
$ret = array();
$options = simplexml_import_dom($opts);
foreach ($options
->attributes() as $key => $value) {
$ret[(string) $key] = (string) $value;
}
return $ret;
}
public function setOptions($option_data) {
$dom = $this->dom;
$this
->verifyHeaderElements(array(
'options',
));
$options = $dom
->getElementsByTagNameNS($this->xmlns, 'options')
->item(0);
foreach ($option_data as $key => $value) {
if ($value) {
$options
->setAttribute($key, $value);
}
else {
if ($options
->hasAttribute($key)) {
$options
->removeAttribute($key);
}
}
}
}
public function removeParm($id) {
$dom = $this->dom;
$xpq = $this->xpq;
$pnode = $dom
->getElementsByTagNameNS($this->xmlns, 'parameters')
->item(0);
$path = '//frx:parameters/frx:parm[@id="' . $id . '"]';
$nodes = $xpq
->query($path);
if ($nodes->length) {
foreach ($nodes as $node) {
$pnode
->removeChild($node);
}
}
}
private function parse_ids() {
$i = 0;
if ($this->simplexml) {
$this->simplexml
->registerXPathNamespace('frx', FRX_NS);
$frx_attributes = array();
$frx_nodes = $this->simplexml
->xpath('body//*[@frx:*]');
if ($frx_nodes) {
foreach ($frx_nodes as $node) {
$attr_nodes = $node
->attributes(FRX_NS);
if ($attr_nodes) {
$i++;
$id = 'forena-' . $i;
if (!(string) $node['id']) {
$node
->addAttribute('id', $id);
}
else {
if (strpos((string) $node['id'], 'forena-') === 0) {
$node['id'] = $id;
}
else {
$id = (string) $node['id'];
}
}
$attr_nodes = $node
->attributes(FRX_NS);
$attrs = array();
if ($attr_nodes) {
foreach ($attr_nodes as $key => $value) {
$attrs[$key] = (string) $value;
}
}
$frx_attributes[$id] = $attrs;
}
}
}
$this->frx_attributes = $frx_attributes;
}
}
public function get_attributes_by_id() {
$this
->parse_ids();
return $this->frx_attributes;
}
public function save_attributes_by_id($attributes) {
$rpt_xml = $this->simplexml;
if ($attributes) {
foreach ($attributes as $id => $att_list) {
$id_search_path = '//*[@id="' . $id . '"]';
$fnd = $rpt_xml
->xpath($id_search_path);
if ($fnd) {
$node = $fnd[0];
$frx_attributes = $node
->Attributes(FRX_NS);
foreach ($att_list as $key => $value) {
if (!$frx_attributes[$key]) {
$node['frx:' . $key] = $value;
}
else {
unset($frx_attributes[$key]);
$node['frx:' . $key] = $value;
}
}
}
}
}
}
}