[ Index ]
 

Code source de SPIP 1.9.2c

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/ecrire/xml/ -> analyser_dtd.php (source)

   1  <?php
   2  
   3  /***************************************************************************\
   4   *  SPIP, Systeme de publication pour l'internet                           *
   5   *                                                                         *
   6   *  Copyright (c) 2001-2007                                                *
   7   *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
   8   *                                                                         *
   9   *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  10   *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
  11  \***************************************************************************/
  12  
  13  if (!defined("_ECRIRE_INC_VERSION")) return;
  14  
  15  include_spip('xml/interfaces');
  16  
  17  function charger_dtd($grammaire, $avail)
  18  {
  19      spip_timer('dtd');
  20      $dtc = new DTC;
  21      // L'analyseur retourne un booleen de reussite et modifie $dtc.
  22      // Retourner vide en cas d'echec
  23      if (!analyser_dtd($grammaire, $avail, $dtc)) return array();
  24  
  25      // tri final pour presenter les suggestions de corrections
  26      foreach ($dtc->peres as $k => $v) {
  27          asort($v);
  28          $dtc->peres[$k] = $v;
  29        } 
  30        
  31      spip_log("Analyser DTD $avail $grammaire (" . spip_timer('dtd') . ") " . count($dtc->macros)  . ' macros, ' . count($dtc->elements)  . ' elements, ' . count($dtc->attributs) . " listes d'attributs, " . count($dtc->entites) . " entites");
  32  #    $r = $dtc->regles; ksort($r);foreach($r as $l => $v) echo "<b>$l</b> '$v' ", join (', ',array_keys($dtc->attributs[$l])), "<br />\n";exit;
  33      return $dtc;
  34  }
  35  
  36  // Compiler une regle de production en une Regexp qu'on appliquera sur la
  37  // suite des noms de balises separes par des espaces. Du coup:
  38  // supprimer #PCDATA etc, ca ne sert pas pour le controle des balises;
  39  // supprimer les virgules (les sequences sont implicites dans une Regexp)
  40  // conserver | + * ? ( ) qui ont la meme signification en DTD et en Regexp;
  41  // faire suivre chaque nom d'un espace (et supprimer les autres) ...
  42  // et parentheser le tout pour que  | + * ? s'applique dessus.
  43  
  44  // http://doc.spip.org/@compilerRegle
  45  function compilerRegle($val)
  46  {
  47      $x = str_replace('\s*()\s*','',
  48          preg_replace('/\s*,\s*/','',
  49          preg_replace('/(\w+)\s*/','(\1 )',
  50          preg_replace('/\s*([(+*|])\s*/','\1',
  51          preg_replace('/\s*#\w+\s*[,|]?\s*/','', $val)))));
  52      return $x;
  53  }
  54  
  55  
  56  // http://doc.spip.org/@analyser_dtd
  57  function analyser_dtd($loc, $avail, &$dtc)
  58  {
  59      if ($avail == 'SYSTEM')
  60        $file = $loc;
  61      else {
  62        $file = sous_repertoire(_DIR_CACHE_XML);
  63        $file .= preg_replace('/[^\w.]/','_', $loc);
  64      }
  65  
  66      $dtd = '';
  67      if (@is_readable($file)) {
  68          lire_fichier($file, $dtd);
  69      } else {
  70          if ($avail == 'PUBLIC') {
  71              include_spip('inc/distant');
  72              if ($dtd = trim(recuperer_page($loc)))
  73                  ecrire_fichier($file, $dtd, true); 
  74          }
  75      }
  76  
  77      if (!$dtd) {
  78          spip_log("DTD '$loc' inaccessible");
  79          return false;
  80      } else     spip_log("analyse de la DTD $loc ");
  81  
  82      while ($dtd) {
  83          if ($dtd[0] != '<')
  84              $r = analyser_dtd_lexeme($dtd, $dtc, $loc);
  85          elseif ($dtd[1] != '!')
  86              $r = analyser_dtd_pi($dtd, $dtc, $loc);
  87          elseif ($dtd[2] == '[')
  88              $r = analyser_dtd_data($dtd, $dtc, $loc);
  89          else switch ($dtd[3]) {
  90        case '%' : $r = analyser_dtd_data($dtd, $dtc, $loc); break;
  91        case 'T' : $r = analyser_dtd_attlist($dtd, $dtc, $loc);break;
  92        case 'L' : $r = analyser_dtd_element($dtd, $dtc, $loc);break;
  93        case 'N' : $r = analyser_dtd_entity($dtd, $dtc, $loc);break;
  94        case 'O' : $r = analyser_dtd_notation($dtd, $dtc, $loc);break;
  95        case '-' : $r = analyser_dtd_comment($dtd, $dtc, $loc); break;
  96        default: $r = -1;
  97            }
  98          if (!is_string($r)) {
  99              spip_log("erreur $r dans la DTD  " . substr($dtd,0,80) . ".....");
 100              return false;
 101          }
 102          $dtd = $r;
 103       }
 104      return true;
 105  }
 106  
 107  // http://doc.spip.org/@analyser_dtd_comment
 108  function analyser_dtd_comment($dtd, &$dtc, $grammaire){
 109      // ejecter les commentaires, surtout quand ils contiennent du code.
 110      // Option /s car sur plusieurs lignes parfois
 111  
 112      if (!preg_match('/^<!--.*?-->\s*(.*)$/s',$dtd, $m))
 113          return -6;
 114      return $m[1];
 115  }
 116  
 117  // http://doc.spip.org/@analyser_dtd_pi
 118  function analyser_dtd_pi($dtd, &$dtc, $grammaire){
 119      if (!preg_match('/^<\?.*?>\s*(.*)$/s', $dtd, $m))
 120          return -10;
 121      return $m[1];
 122  }
 123  
 124  // http://doc.spip.org/@analyser_dtd_lexeme
 125  function analyser_dtd_lexeme($dtd, &$dtc, $grammaire){
 126      if (!preg_match(_REGEXP_ENTITY_DEF,$dtd, $m))
 127          return -9;
 128  
 129      list(,$s) = $m;
 130      $n = $dtc->macros[$s];
 131      if (is_array($n)) {
 132          // en cas d'inclusion, l'espace de nom est le meme
 133          analyser_dtd($n[1], $n[0], $dtc);
 134      }
 135      
 136      return ltrim(substr($dtd,strlen($m[0])));
 137  }
 138  
 139  // il faudrait prevoir plusieurs niveaux d'inclusion.
 140  // (Ruby en utilise mais l'erreur est transparente. Scandaleux coup de pot)
 141  
 142  // http://doc.spip.org/@analyser_dtd_data
 143  function analyser_dtd_data($dtd, &$dtc, $grammaire){
 144      if (!preg_match('/^<!\[\s*%\s*([^;]*);\s*\[\s*(.*?)\]\]>\s*(.*)$/s',$dtd, $m))
 145          return -11;
 146      if ($dtc->macros[$m[1]] == 'INCLUDE')
 147          $retour = $m[2] . $m[3];
 148      else $retour = $m[3]; 
 149      return $retour;
 150  }
 151  
 152  // http://doc.spip.org/@analyser_dtd_notation
 153  function analyser_dtd_notation($dtd, &$dtc, $grammaire){
 154      if (!preg_match('/^<!NOTATION.*?>\s*(.*)$/s',$dtd, $m))
 155          return -8;
 156      spip_log("analyser_dtd_notation a ecrire");
 157      return $m[1];
 158  }
 159  
 160  // http://doc.spip.org/@analyser_dtd_entity
 161  function analyser_dtd_entity($dtd, &$dtc, $grammaire)
 162  {
 163      if (!preg_match(_REGEXP_ENTITY_DECL, $dtd, $m))
 164          return -2;
 165  
 166      list($t, $term, $nom, $type, $val, $q, $c, $alt, $dtd) = $m;
 167  
 168      if (isset($dtc->macros[$nom]) AND $dtc->macros[$nom])
 169          return $dtd;
 170      if (isset($dtc->entites[$nom]))
 171          spip_log("redefinition de l'entite $nom");
 172      if  (!$term)
 173          $dtc->entites[$nom] = expanserEntite($val, $dtc->macros);
 174      elseif (!$type)
 175          $dtc->macros[$nom] = expanserEntite($val, $dtc->macros);
 176      elseif (!$alt)
 177          $dtc->macros[$nom] = expanserEntite($val, $dtc->macros);
 178      else {
 179          if (strpos($alt, '/') === false)
 180              $alt = preg_replace(',/[^/]+$,', '/', $grammaire)
 181              . $alt ;
 182          $dtc->macros[$nom] = array($type, $alt);
 183      } 
 184      return $dtd;
 185  }
 186  
 187  // Dresser le tableau des filles potentielles de l'element
 188  // pour traquer tres vite les illegitimes.
 189  // Si la regle a au moins une sequence (i.e. une virgule)
 190  // ou n'est pas une itération (i.e. se termine par * ou +)
 191  // en faire une RegExp qu'on appliquera aux balises rencontrees.
 192  // Sinon, conserver seulement le type de l'iteration car la traque
 193  // aura fait l'essentiel du controle sans memorisation des balises.
 194  // Fin du controle en finElement
 195  
 196  // http://doc.spip.org/@analyser_dtd_element
 197  function analyser_dtd_element($dtd, &$dtc, $grammaire)
 198  {
 199      if (!preg_match('/^<!ELEMENT\s+(\S+)\s+([^>]*)>\s*(.*)$/s', $dtd, $m))
 200          return -3;
 201  
 202      list(,$nom, $val, $dtd) = $m;
 203      $nom = expanserEntite($nom, $dtc->macros);
 204      $val = compilerRegle(expanserEntite($val, $dtc->macros));
 205      if (isset($dtc->elements[$nom])) {
 206          spip_log("redefinition de l'element $nom dans la DTD");
 207          return -4;
 208      }
 209      $filles = array();
 210      if ($val == '(EMPTY )')
 211          $dtc->regles[$nom] = 'EMPTY';
 212      elseif  ($val == '(ANY )') 
 213          $dtc->regles[$nom] = 'ANY';
 214      else {
 215          $last = substr($val,-1);
 216          if (preg_match('/ \w/', $val)
 217          OR strpos('*+', $last) === false)
 218              $dtc->regles[$nom] = "/^$val$/";
 219          else
 220              $dtc->regles[$nom] = $last;
 221              $filles = array_values(preg_split('/\W+/', $val,-1, PREG_SPLIT_NO_EMPTY));
 222  
 223              foreach ($filles as $k) {
 224                  if (!isset($dtc->peres[$k]))
 225                    $dtc->peres[$k] = array();
 226                  if (!in_array($nom, $dtc->peres[$k]))
 227                      $dtc->peres[$k][]= $nom;
 228              }
 229      }
 230      $dtc->elements[$nom]= $filles;
 231      return $dtd;
 232  }
 233  
 234  
 235  // http://doc.spip.org/@analyser_dtd_attlist
 236  function analyser_dtd_attlist($dtd, &$dtc, $grammaire)
 237  {
 238      if (!preg_match('/^<!ATTLIST\s+(\S+)\s+([^>]*)>\s*(.*)/s', $dtd, $m))
 239          return -5;
 240  
 241      list(,$nom, $val, $dtd) = $m;
 242      $nom = expanserEntite($nom, $dtc->macros);
 243      $val = expanserEntite($val, $dtc->macros);
 244      if (!isset($dtc->attributs[$nom]))
 245          $dtc->attributs[$nom] = array();
 246  
 247      if (preg_match_all("/\s*(\S+)\s+(([(][^)]*[)])|(\S+))\s+([^\s']*)(\s*'[^']*')?/", $val, $r2, PREG_SET_ORDER)) {
 248          foreach($r2 as $m2) {
 249              $v = preg_match('/^\w+$/', $m2[2]) ? $m2[2]
 250                : ('/^' . preg_replace('/\s+/', '', $m2[2]) . '$/');
 251              $m21 = expanserEntite($m2[1], $dtc->macros);
 252              $m25 = expanserEntite($m2[5], $dtc->macros);
 253              $dtc->attributs[$nom][$m21] = array($v, $m25);
 254          }
 255      }
 256  
 257      return $dtd;
 258  }
 259  
 260  
 261  // http://doc.spip.org/@expanserEntite
 262  function expanserEntite($val, $macros)
 263  {
 264      if (preg_match_all(_REGEXP_ENTITY_USE, $val, $r, PREG_SET_ORDER)){
 265        foreach($r as $m) {
 266            $ent = $m[1];
 267            // il peut valoir ""
 268              if (isset($macros[$ent]))
 269                  $val = str_replace($m[0], $macros[$ent], $val);
 270        }
 271      }
 272      return trim(preg_replace('/\s+/', ' ', $val));
 273  }
 274  
 275  
 276  
 277  ?>


Généré le : Wed Nov 21 10:20:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics