home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / XML / DTD.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  12.2 KB  |  375 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | XML_DTD package                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2003 Tomas Von Veschler Cox                            |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors:     Tomas V.V.Cox <cox@idecnet.com>                         |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: DTD.php,v 1.6 2004/05/17 19:51:07 schst Exp $
  21. //
  22.  
  23. /*
  24. TODO:
  25.     - Entities: PUBLIC | SYSTEM | NDATA
  26.     - Tokenized types for ATTLIST
  27.     - others ...
  28. */
  29.  
  30. /**
  31.  * XML_DTD_Parser
  32.  * 
  33.  * Usage:
  34.  * 
  35.  * <code>
  36.  * // Create a new XML_DTD parser object
  37.  * $dtd_parser = new XML_DTD_Parser;
  38.  * // Do the parse and return a XML_DTD_Tree object
  39.  * // containing the DTD tree representatio.
  40.  * $dtd_tree = $dtd_parser->parse($dtd_file);
  41.  * </code>
  42.  * 
  43.  * @package XML_DTD
  44.  * @category XML
  45.  * @author Tomas V.V.Cox <cox@idecnet.com> 
  46.  * @copyright Copyright (c) 2003
  47.  * @version $Id: DTD.php,v 1.6 2004/05/17 19:51:07 schst Exp $
  48.  * @access public 
  49. */
  50. class XML_DTD_Parser
  51. {
  52.     var $dtd = array();
  53.  
  54.     /**
  55.      * XML_DTD_Parser::_parseENTITIES()
  56.      * 
  57.      * Do entities preprocessing
  58.      * 
  59.      * @param string $str 
  60.      * @return string 
  61.      * @access private 
  62.      */
  63.     function _parseENTITIES($str)
  64.     {
  65.         // Find all ENTITY tags
  66.         if (preg_match_all('|<!ENTITY\s+([^>]+)\s*>|s', $str, $m)) {
  67.             $ids = array();
  68.             $repls = array();
  69.             foreach ($m[1] as $entity) {
  70.                 // Internal entities
  71.                 if (preg_match('/^%?\s+([a-zA-Z0-9.\-]+)\s+(["\'])(.*)\2\s*$/s', $entity, $n)) {
  72.                     // entity name
  73.                     $id = '/%' . $n[1] . ';/';
  74.                     // replacement text
  75.                     $repl = $n[3];
  76.                     $ids[] = $id;
  77.                     $repls[] = $repl;
  78.                 // XXX PUBLIC | SYSTEM | NDATA
  79.                 } else {
  80.                     trigger_error("Entity <!ENTITY $entity> not supported");
  81.                 }
  82.             }
  83.             // replace replacements in entities
  84.             $defined_ids = $defined_repls = array();
  85.             for ($i = 0; $i < count($ids); $i++) {
  86.                 if ($i <> 0) {
  87.                     $repls[$i] = preg_replace($defined_ids, $defined_repls, $repls[$i]);
  88.                     // XXX Search for not previously defined entities
  89.                 }
  90.                 $defined_ids[] = $ids[$i];
  91.                 $defined_repls[] = $repls[$i];
  92.             }
  93.             // replace replacements in the whole DTD
  94.             array_flip($ids);
  95.             array_flip($repls);
  96.             $str = preg_replace($ids, $repls, $str);
  97.             // Check if there are still unparsed entities
  98.             if (preg_match_all('/(%[^#][a-zA-Z0-9.]+;)/', $str, $o)) {
  99.                 foreach ($o[1] as $notparsed) {
  100.                     trigger_error("Entity ID: '$notparsed' not recognized, skipping");
  101.                     $str = preg_replace("/$notparsed/", '', $str);
  102.                 }
  103.             }
  104.         }
  105.         return $str;
  106.     }
  107.  
  108.     /**
  109.      * XML_DTD_Parser::parse()
  110.      * 
  111.      * @param string $cont      it could be either a filename or a string
  112.      * @param boolean $is_file  if the first param is supposed to be a string
  113.      *                          or a filename
  114.      * @return object           a XML_DTD_Tree object
  115.      */
  116.     function parse($cont, $is_file = true)
  117.     {
  118.         if ($is_file) {
  119.             $cont = file_get_contents($cont);
  120.         }
  121.         // Remove DTD comments
  122.         $cont = preg_replace('|<!--.*-->|Us', '', $cont);
  123.         $cont = $this->_parseENTITIES($cont);
  124.         if (preg_match_all('|<!([^>]+)>|s', $cont, $m)) {
  125.             foreach ($m[1] as $tag) {
  126.                 $fields = array();
  127.                 $in = 0;
  128.                 $buff = '';
  129.                 $tag = preg_replace('|\s+|s', ' ', $tag);
  130.                 // Manual split the parts of the elements
  131.                 // take care of netsted lists (a|(c|d)|b)
  132.                 for ($i = 0; $i < strlen($tag); $i++) {
  133.                     if ($tag{$i} == ' ' && !$in && $buff) {
  134.                         $fields[] = $buff;
  135.                         $buff = '';
  136.                         continue;
  137.                     }
  138.                     if ($tag{$i} == '(') {
  139.                         $in++;
  140.                     } elseif ($tag{$i} == ')') {
  141.                         $in--;
  142.                     }
  143.                     $buff .= $tag{$i};
  144.                 }
  145.                 if ($buff) {
  146.                     $fields[] = $buff;
  147.                 }
  148.                 // Call the element handler
  149.                 $elem = $fields[0];
  150.                 array_shift($fields);
  151.                 switch ($elem) {
  152.                     case 'ELEMENT':
  153.                         $this->_ELEMENT($fields);
  154.                         break;
  155.                     case 'ATTLIST':
  156.                         $this->_ATTLIST($fields);
  157.                         break;
  158.                     case 'ENTITY':
  159.                         break;
  160.                     default:
  161.                         trigger_error("$elem not implemented yet", E_USER_WARNING);
  162.                         break;
  163.                 }
  164.             }
  165.         }
  166.         return new XML_DTD_Tree($this->dtd);
  167.     }
  168.  
  169.     /**
  170.      * XML_DTD_Parser::_ELEMENT()
  171.      * 
  172.      * Handles the ELEMENT parsing
  173.      * 
  174.      * @param array $data $data[0] the element, $data[1] the string with allowed childs
  175.      * @return null
  176.      * @access private
  177.      */
  178.     function _ELEMENT($data)
  179.     {
  180.         // $data[0] the element
  181.         // $data[1] the string with allowed childs
  182.         $elem_name  = $data[0];
  183.         $ch = str_replace(' ', '', $data[1]);
  184.         // Content
  185.         if ($ch{0} != '(') {
  186.             $content = $ch;
  187.             $children = array();
  188.         // Enumerated list of childs
  189.         } else {
  190.             $content = null;
  191.             do {
  192.                 $children = preg_split('/([^#a-zA-Z0-9_.-]+)/', $ch, -1, PREG_SPLIT_NO_EMPTY);
  193.                 if (in_array('#PCDATA', $children)) {
  194.                     $content = '#PCDATA';
  195.                     if (count($children) == 1) {
  196.                         $children = array();
  197.                         break;
  198.                     }
  199.                 }
  200.                 $this->dtd['elements'][$elem_name]['child_validation_dtd_regex'] = $ch;
  201.                 // Convert the DTD regex language into PCRE regex format
  202.                 $reg = str_replace(',', ',?', $ch);
  203.                 $reg = preg_replace('/([#a-zA-Z0-9_.-]+)/', '(,?\\0)', $reg);
  204.                 $this->dtd['elements'][$elem_name]['child_validation_pcre_regex'] = $reg;
  205.             } while (false);
  206.         }
  207.         // Tree of rules childs
  208.         $this->dtd['elements'][$elem_name]['children'] = $children;
  209.         // Either null, #PCDATA, EMPTY or ANY
  210.         $this->dtd['elements'][$elem_name]['content']  = $content;
  211.     }
  212.  
  213.     /**
  214.      * XML_DTD_Parser::_ATTLIST()
  215.      * 
  216.      * Handles the ATTLIST parsing
  217.      * 
  218.      * @param array $data $data[0] the element name, $data[1] string with the attributes
  219.      * @return null
  220.      * @access private 
  221.      */
  222.     function _ATTLIST($data)
  223.     {
  224.         $elem = $data[0];
  225.         array_shift($data);
  226.         for ($i=0; $i < count($data) ; $i = $i + 3) {
  227.             $a = array();
  228.             $att = $data[$i];
  229.             $opts = $data[$i+1];
  230.             if ($opts{0} == '(' && $opts{strlen($opts)-1} == ')') {
  231.                 $a['opts'] = preg_split('/\||,/',
  232.                                         preg_replace('|\s+|',
  233.                                                      '',
  234.                                                      substr($opts, 1, -1)
  235.                                                     )
  236.                                        );
  237.             } else {
  238.                 $a['opts'] = $opts; // XXX ID is missing yet
  239.             }
  240.             $def = $data[$i+2];
  241.             if ($def{0} == '"' && $def{strlen($def)-1} == '"') {
  242.                 $def = substr($def, 1, -1);
  243.             } elseif ($def == '#FIXED') {
  244.                 $a['fixed_value'] = substr($data[$i+3], 1, -1); //strip "s
  245.                 $i++;
  246.             }
  247.             $a['defaults'] = $def;
  248.             $this->dtd['elements'][$elem]['attributes'][$att] = $a;
  249.         }
  250.     }
  251. }
  252.  
  253. /**
  254.  * XML_DTD_Tree
  255.  * 
  256.  * DTD tree format:
  257.  * 
  258.  * <code>
  259.  * [elements] => array(
  260.  *      <tag name> => array(
  261.  *          [children] => array(
  262.  *              0 => <child name>                    //allowed children array
  263.  *          ),
  264.  *          [child_validation_pcre_regex] => string, // The regex for validating
  265.  *                                                   // the list of childs
  266.  *          [child_validation_dtd_regex] => string,  // The DTD element declaration
  267.  *          [content] => string                      // null, #PCDATA, EMPTY or ANY
  268.  *          [attributes] => array(
  269.  *              <att name> => array(
  270.  *                  [opts] => (array|string),        // enumerated or CDATA
  271.  *                  [defaults] => (#IMPLIED|#REQUIRED|#FIXED|value),
  272.  *                  [fixed_value] => string          // only when defaults is #FIXED
  273.  *              )
  274.  *          )
  275.  *      )
  276.  * )
  277.  * </code>
  278.  * 
  279.  * @package XML_DTD
  280.  * @category XML
  281.  * @author Tomas V.V.Cox <cox@idecnet.com> 
  282.  * @copyright Copyright (c) 2003
  283.  * @version $Id: DTD.php,v 1.6 2004/05/17 19:51:07 schst Exp $
  284.  * @access public 
  285.  */
  286. class XML_DTD_Tree
  287. {
  288.     /**
  289.      * XML_DTD_Tree::XML_DTD_Tree()
  290.      *
  291.      * The DTD tree array comming from XML_DTD_Parse->parse()
  292.      *  
  293.      * @param array $tree
  294.      **/
  295.     function XML_DTD_Tree($tree)
  296.     {
  297.         $this->dtd = $tree;
  298.     }
  299.  
  300.     /**
  301.      * XML_DTD_Tree::getChildren()
  302.      * 
  303.      * @param string $elem
  304.      * @return array
  305.      **/
  306.     function getChildren($elem)
  307.     {
  308.         return $this->dtd['elements'][$elem]['children'];
  309.     }
  310.  
  311.     /**
  312.      * XML_DTD_Tree::getContent()
  313.      * 
  314.      * @param string $elem
  315.      * @return string
  316.      **/
  317.     function getContent($elem)
  318.     {
  319.         return $this->dtd['elements'][$elem]['content'];
  320.     }
  321.  
  322.     /**
  323.      * XML_DTD_Tree::getPcreRegex()
  324.      * 
  325.      * Return the perl regular expresion used for validating
  326.      * the children of a node
  327.      * 
  328.      * @param string $elem
  329.      * @return string
  330.      **/
  331.     function getPcreRegex($elem)
  332.     {
  333.         return $this->dtd['elements'][$elem]['child_validation_pcre_regex'];
  334.     }
  335.  
  336.     /**
  337.      * XML_DTD_Tree::getDTDRegex()
  338.      * 
  339.      * Return the DTD element definition for $elem
  340.      * 
  341.      * @param string $elem
  342.      * @return string
  343.      **/
  344.     function getDTDRegex($elem)
  345.     {
  346.         return $this->dtd['elements'][$elem]['child_validation_dtd_regex'];
  347.     }
  348.  
  349.     /**
  350.      * XML_DTD_Tree::getAttributes()
  351.      * 
  352.      * @param $elem
  353.      * @return array
  354.      **/
  355.     function getAttributes($elem)
  356.     {
  357.         if (!isset($this->dtd['elements'][$elem]['attributes'])) {
  358.             return array();
  359.         }
  360.         return $this->dtd['elements'][$elem]['attributes'];
  361.     }
  362.  
  363.     /**
  364.      * XML_DTD_Tree::elementIsDeclared()
  365.      * 
  366.      * @param string $elem
  367.      * @return bool
  368.      **/
  369.     function elementIsDeclared($elem)
  370.     {
  371.         return isset($this->dtd['elements'][$elem]);
  372.     }
  373. }
  374. ?>
  375.