Visualizzazione dei risultati da 1 a 3 su 3

Discussione: Classi per Xml

  1. #1
    Utente di HTML.it L'avatar di lloyd27
    Registrato dal
    Mar 2006
    Messaggi
    256

    Classi per Xml

    Salve a tutti!
    Questo è un topic per coloro che come me odiano l'xml, ma sono costretti a lavorarci a stretto contatto lo stesso..

    Insoddisfatto da SimpleXml e dal suo trattamento approssimativo degli attributi, mi sono buttato nella creazione di due classi per la lettura / scrittura di questo formato..
    Non leggono e non scrivono direttamente i file, ma ricevono in input l'xml sotto forma di stringa. Questo per evitare di utilizzare per forza un file vero, e non magari uno "finto" (magari lavorando con le api di un web service?).

    Non ho preso spunto da nulla di esistente, quindi se trovate che vi sembra somigli a qualcos'altro, giuro che è una coincidenza!

    Ecco le due classi (forse l'inglese dei commenti phpDoc non è perfetto )

    esXmlParser
    Codice PHP:

    /**
     * esXmlParser class
     * This class parses a xml string into an object struct
     *
     * @author Davide Borsatto
     * @version 0.8
     * @package xml 
     */

    class esXmlParser
    {

      
    /**
       * Parses an xml string into an object
       *   
       * @access public
       * @param string $source The xml string
       * @return mixed The parsed xml string      
       */           
      
    public static function parse($source)
      {
        return 
    self::xmlToObject($source);
      }

      
    /**
       * Converts an xml string into an object struct
       * 
       * @access public
       * @param string $xmlData The xml string
       * @return esXmlNode The parsed xml
       */
      
    private static function xmlToObject($xmlData)
      {
        
    $xmlValues self::parseXmlIntoStruct($xmlData);
        
    $root = new esXmlNode();
        
    $root->setName('root');
        
    $actualLevel 1;
        
    $actualNode $root;
        
    $stack = array();
        
    $stack[1] = $root;
        foreach (
    $xmlValues as $element)
        {
          if (
    $element['type'] == 'close')
          {
            continue;
          }
          
    $node = new esXmlNode();
          
    $node->setName($element['tag']);
          if (
    array_key_exists('attributes'$element))
          {
            
    $node->setAttributes($element['attributes']);
          }
          if (
    array_key_exists('value'$element))
          {
            
    $node->setValue($element['value']);
          }
          
    $level $element['level'];
          if (
    $level $actualLevel)
          {
            
    $stack[$level] = $actualNode;
          }
          
    $stack[$level]->addSon($node);
          
    $actualNode $node;
          
    $actualLevel $element['level'];
        }
        
    $sons $root->getSons();
        return 
    $sons[0];
      }

      
    /**
       * Parses xml using native php functions
       *
       * @access public
       * @param string $xmlData The string to be parsed
       * @return array The parsed xml
       */
      
    private static function parseXmlIntoStruct($xmlData)
      {
        
    $parser xml_parser_create('');
        
    xml_parser_set_option($parserXML_OPTION_TARGET_ENCODING'UTF-8');
        
    xml_parser_set_option($parserXML_OPTION_CASE_FOLDING0);
        
    xml_parser_set_option($parserXML_OPTION_SKIP_WHITE1);
        
    xml_parse_into_struct($parser$xmlData$xmlValues);
        
    xml_parser_free($parser);
        return 
    $xmlValues;
      }



  2. #2
    Utente di HTML.it L'avatar di lloyd27
    Registrato dal
    Mar 2006
    Messaggi
    256
    esXmlNode
    Codice PHP:
    <?php

    /**
     * esXmlNode class
     * This class is a rappresentation of a xml node
     *
     * @author Davide Borsatto
     * @version 0.8
     * @package xml 
     */        

    class esXmlNode
    {

      
    /**
       * The name of the node
       * @access private
       * @var string
       */
      
    private $name '';

      
    /**
       * The attributes of the node, in a key => value form
       * @access private
       * @var array
       */
      
    private $attributes = array();

      
    /**
       * The nodes sons of this one
       * @access private
       * @var array
       */
      
    private $sons = array();

      
    /**
       * The value
       * @access private
       * @var string
       */
      
    private $value '';

      
    /**
       * If the node must print the cdata string while converted to xml
       * @access private
       * @var boolean
       */
      
    private $cdata false;

      
    /**
       * If the node must be printed in the short mode (<node />) instead of the default (<node></node>)
       * @access private
       * @var boolean
       */
      
    private $shortIfEmpty true;

      
    /**
       * The parent (if exists) of this node
       * @access private
       * @var object
       */
      
    private $parent null;

      
    /**
       * Contructor, it can set up {@link $name} and the {@link $parent}
       * @access public
       * @param string $name The name of the node
       * @param array $options An array with default options
       */
      
    public function __construct($name ''$options = array())
      {
        
    $this->setName($name);
        
    $defaultOptions = array
        (
          
    'parent'         => null,
          
    'short_if_empty' => true,
          
    'cdata'          => false,
          
    'value'          => ''
        
    );
        
    $options array_merge($defaultOptions$options);
        
    $this->setShortIfEmpty($options['short_if_empty']);
        
    $this->setCdata($options['cdata']);
        
    $this->setValue($options['value']);
        if (
    $options['parent'] instanceof esXmlNode)
        {
          
    $this->setParent($options['parent']);
        }
      }

      
    /**
       * Gets a string rappresentation of the node
       * @access public
       * @return string the xml rappresentation of the node      
       */     
      
    public function __toString()
      {
        return 
    $this->toXml();
      }

      
    /**
       * Sets the {@link $name} of the node
       * @param string $name The name of the node   
       */
      
    public function setName($name)
      {
        
    $this->name $name;
      }

      
    /**
       * Gets the {@link $name} of the node
       * @access public
       * @return string The name of the node
       */           
      
    public function getName()
      {
        return 
    $this->name;
      }

      
    /**
       * Sets the {@link $value} of the node
       * @access public
       * @param string $value The value of the node
       */           
      
    public function setValue($value)
      {
        
    $this->value $value;
      }

      
    /**
       * Gets the {@link $value} of the node
       * @access public
       * @return string The value of the node
       */           
      
    public function getValue()
      {
        return 
    $this->value;
      }

      
    /**
       * If the node must print the cdata string while converted to xml
       * @access public
       * @param boolean $cdata If the cdata string must be printed
       */           
      
    public function setCdata($cdata)
      {
        
    $this->cdata $cdata;
      }

      
    /**
       * Sets if the short tag mode must be used in conversion to xml
       * @access public
       * @param boolean $shortIfEmpty If the short tag mode must be used in conversion to xml
       */           
      
    public function setShortIfEmpty($shortIfEmpty)
      {
        
    $this->shortIfEmpty $shortIfEmpty;
      }

      
    /**
       * Returns true if the node has at least one son
       * @access public   
       * @return boolean If the node has sons or not
       */        
      
    public function hasSons()
      {
        return 
    count($this->sons) > 0;
      }

      
    /**
       * Returns true if the node is a leaf (it does not have any sons)
       * @access public
       * @return boolean If the node is a leaf or not
       */
      
    public function isLeaf()
      {
        return !
    $this->hasSons();
      }

      
    /**
       * Adds a son to the current node
       * @access public
       * @param XmlNode $node The son of the current node
       */           
      
    public function addSon(esXmlNode $node)
      {
        
    $node->setParent($this);
        
    $this->sons[] = $node;
      }

      
    /**
       * Adds an array of XmlNode nodes
       * @access public
       * @param array $nodes An XmlNode array
       */   
      
    public function addSons(array $nodes)
      {
        foreach (
    $nodes as $node)
        {
          if (
    $node instanceof esXmlNode)
          {
            
    $this->addSon($node);
          }
        }
      }

      
    /**
       * Returns the sons of the current node
       * @access public
       * @return array The sons of the current node
       */           
      
    public function getSons()
      {
        return 
    $this->sons;
      }

      
    /**
       * Sets an attribute of the current node
       * @access public
       * @param string $name The name of the attribute
       * @param string $value The value of the attribute
       */              
      
    public function setAttribute($name$value)
      {
        
    $this->attributes[$name] = $value;
      }

      
    /**
       * Returns if the node has an attribute or not
       * @access public
       * @param mixed $name The name of the attribute
       * @return boolean If the node has the requested attribute
      */
      
    public function hasAttribute($name)
      {
        return 
    Arrays::has($this->attributes$name);
      }


      
    // ...

  3. #3
    Utente di HTML.it L'avatar di lloyd27
    Registrato dal
    Mar 2006
    Messaggi
    256
    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 2false$cdata);
          }
          for (
    $i 0$i $spaces; ++$i)
          {
            
    $xml .= ' ';
          }
          
    $xml .= '</' $this->getName() . '>';
        }
        return 
    $xml "\n";
      }

    }
    Ho dovuto spezzare la classe perché era troppo lunga..

    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!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.