Codice PHP:
<?php
// ...
/**
* Sets an array of attributes
* @access public
* @param mixed $attributes The attributes to assing to the current node
*/
public function setAttributes($attributes, $merge = false)
{
if (is_array($attributes))
{
$this->attributes = $merge ? array_merge($this->attributes, $attributes) : $attributes;
}
}
/**
* Returns the request attribute of the node
* @access public
* @param string $name The name of the attribute
* @param string $default The default value to return, in case the attribute is not availlable
* @return mixed The value of the attribute
*/
public function getAttribute($name, $default = null)
{
return $this->hasAttribute($name) ? $this->attributes[$name] : $default;
}
/**
* Returns an array of the attributes
* @access public
* @return array The array of the attributes
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Returns the sons of the current node filtered by a set of defined field
*
* @access public
* @param array $filters An array in a key => value form
* @return array The array of filtered sons
*/
public function getFilteredSons(array $filters)
{
$sons = array();
foreach ($this->getSons() as $son)
{
$pass = true;
foreach ($filters as $name => $value)
{
if ($son->getAttribute($name) != $value)
{
$pass = false;
break;
}
}
if ($pass)
{
$sons[] = $son;
}
}
return $sons;
}
/**
* Returns the parent (if exists) of the current node
*
* @access public
* @return mixed The parent if exists, otherwise null
*/
public function getParent()
{
return $this->parent;
}
/**
* Sets the parent of the current node
*
* @access public
* @param exXmlNode $parent The parent of the current node
*/
public function setParent(esXmlNode $parent)
{
$this->parent = $parent;
}
/**
* Filter the sons by the tag name
*
* @access public
* @param string $name The name of the requested node
* @return array An array of esXmlNode
*/
public function getSonsByName($name)
{
$sons = array();
foreach ($this->getSons() as $son)
{
if ($son->getName() == $name)
{
$sons[] = $son;
}
}
return $sons;
}
/**
* Finds all the nodes (with the actual included) that pass the defined filters
*
* @access public
* @param string $name The name of the node we are looking for
* @param array $filters An array of defined filters
* @param array $moreFilters An array of special filters
* @return array An array containing all the nodes that pass the defined filters
*/
public function find($name, $filters = array(), $moreFilters = array())
{
$results = array();
$pass = true;
if ($name)
{
if ($this->getName() != $name)
{
$pass = false;
}
}
if ($pass and is_array($filters) and count($filters))
{
foreach ($filters as $filter)
{
$field = $filter[0];
$value = $filter[1];
$comparison = array_key_exists(2, $filter) ? $filter[2] : '==';
switch ($comparison)
{
case '>':
{
$isGood = (float) $this->attributes[$field] > $value;
break;
}
case '>=':
{
$isGood = (float) $this->attributes[$field] >= $value;
break;
}
case '<':
{
$isGood = (float) $this->attributes[$field] < $value;
break;
}
case '<=':
{
$isGood = (float) $this->attributes[$field] <= $value;
break;
}
case '==':
{
$isGood = $this->attributes[$field] == $value;
break;
}
case '!=':
{
$isGood = $this->attributes[$field] != $value;
break;
}
default:
{
$isGood = true;
break;
}
}
if (!$isGood)
{
$pass = false;
break;
}
}
}
if (is_array($moreFilters))
{
if ($pass and array_key_exists('is_leaf', $moreFilters) and (bool) $moreFilters['is_leaf'] != $this->isLeaf())
{
$pass = false;
}
if ($pass and array_key_exists('has_parent', $moreFilters) and (bool) $moreFilters['has_parent'] != ($this->parent !== null))
{
$pass = false;
}
if ($pass and array_key_exists('sons_more_than', $moreFilters) and (int) $moreFilters['sons_more_than'] <= count($this->sons))
{
$pass = false;
}
if ($pass and array_key_exists('sons_less_than', $moreFilters) and (int) $moreFilters['sons_less_than'] >= count($this->sons))
{
$pass = false;
}
if ($pass and array_key_exists('sons_more_equal_than', $moreFilters) and (int) $moreFilters['sons_more_equal_than'] < count($this->sons))
{
$pass = false;
}
if ($pass and array_key_exists('sons_less_equal_than', $moreFilters) and (int) $moreFilters['sons_less_equal_than'] > count($this->sons))
{
$pass = false;
}
}
if ($pass)
{
$results[] = $this;
}
foreach ($this->getSons() as $son)
{
foreach ($son->find($name, $filters, $moreFilters) as $occurency)
{
$results[] = $occurency;
}
}
return $results;
}
/**
* Returns the xml rappresentation of the node
* @access public
* @param integer $spaces The spaces in the beginning of the line
* @param boolean $xmlHeader If the method has to display the header of the xml
* @param boolean $cdata If the node must print the cdata string
* @return string The xml rappresentation of the node
*/
public function toXml($spaces = 0, $xmlHeader = true, $cdata = false)
{
$xml = '';
if ($xmlHeader)
{
$xml = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
}
for ($i = 0; $i < $spaces; ++$i)
{
$xml .= ' ';
}
$xml .= '<' . $this->getName();
foreach ($this->getAttributes() as $key => $value)
{
$xml .= ' ' . $key . '="' . $value . '"';
}
if ($this->isLeaf())
{
if ($this->getValue())
{
$xml .= '>';
if ($this->cdata)
{
$xml .= '<![CDATA[';
$xml .= $this->getValue();
$xml .= ']]>';
}
elseif ($cdata)
{
$xml .= '<![CDATA[';
$xml .= $this->getValue();
$xml .= ']]>';
}
else
{
$xml .= $this->getValue();
}
$xml .= '</' . $this->getName() . '>';
}
elseif ($this->shortIfEmpty)
{
$xml .= ' />';
}
else
{
$xml .= '>';
if ($this->cdata or $cdata)
{
$xml .= '<![CDATA[]]>';
}
$xml .= '</' . $this->getName() . '>';
}
}
else
{
$xml .= '>' . "\n";
foreach ($this->getSons() as $son)
{
$xml .= $son->toXml($spaces + 2, false, $cdata);
}
for ($i = 0; $i < $spaces; ++$i)
{
$xml .= ' ';
}
$xml .= '</' . $this->getName() . '>';
}
return $xml . "\n";
}
}
Ho dovuto spezzare la classe perché era troppo lunga.. ![Smile](images/smilies/smile.gif)
L'utilizzo è abbastanza semplice:
Codice PHP:
<?php
$nodes = esXmlParser::parse(file_get_contents('file.xml'));
E verra creato l'oggetto nodes, comprendente tutte le proprietà, i figli, filtrabili tramite i metodi getFilteredSons e find, e un metodo toXml per rappresentare tutta l'oggetto in una stringa xml corretta.
Ho postato qui sia per dare aiuto a chi magari serve una classe del genere, sia per chiedere consiglio su cos'altro implementare.. Già cosi mi sembra abbastanza completa, ma non si sa mai!
Un'ultima cosa.. La classe non è ottimizzata per le prestazioni, anche se se la cavicchia discretamente. Ho preferito seguire la strada della semantica e bellezza del codice piuttosto che quella della velocità ad ogni costo. In ogni modo, c'è sempre la possibilità di sistemare..
Ora aspetto.. Giudizi, critiche, domande.. Fate voi!