X-Git-Url: http://git.cyclocoop.org/?p=velocampus%2Fweb%2Fwww.git;a=blobdiff_plain;f=www%2Fecrire%2Fxml%2Fsax.php;fp=www%2Fecrire%2Fxml%2Fsax.php;h=a7cb70d652d3d92f70b66aa11ad2c0486d7a9587;hp=0000000000000000000000000000000000000000;hb=80b4d3e85f78d402ed2e73f8f5d1bf4c19962eed;hpb=aaf970bf4cdaf76689ecc10609048e18d073820c diff --git a/www/ecrire/xml/sax.php b/www/ecrire/xml/sax.php new file mode 100644 index 0000000..a7cb70d --- /dev/null +++ b/www/ecrire/xml/sax.php @@ -0,0 +1,279 @@ +depth; + + $t = isset($phraseur->ouvrant[$depth]) ? $phraseur->ouvrant[$depth] : ' '; + // espace initial signifie: deja integree au resultat + if ($t[0] != ' ') + { + $phraseur->res .= '<' . $t . '>'; + $phraseur->ouvrant[$depth] = ' ' . $t; + } + $t = $phraseur->contenu[$depth]; + // n'indenter que s'il y a un separateur avant + $phraseur->res .= preg_replace("/[\n\t ]+$/", "\n$depth", $t); + $phraseur->contenu[$depth] = ""; + $att = ''; + $sep = ' '; + foreach ($attrs as $k => $v) { + $delim = strpos($v, "'") === false ? "'" : '"'; + $val = htmlspecialchars($v,ENT_QUOTES); + $att .= $sep . $k . "=" . $delim + . ($delim !== '"' ? str_replace('"', '"', $val) : $val) + . $delim; + $sep = "\n $depth"; + } + $phraseur->depth .= ' '; + $phraseur->contenu[$phraseur->depth] = ""; + $phraseur->ouvrant[$phraseur->depth] = $name . $att; + $phraseur->reperes[$phraseur->depth] = xml_get_current_line_number($phraseur->sax); +} + +// http://doc.spip.org/@xml_finElement +function xml_finElement($phraseur, $name, $fusion_bal=false) +{ + $ouv = $phraseur->ouvrant[$phraseur->depth]; + + if ($ouv[0] != ' ') + $phraseur->ouvrant[$phraseur->depth] = ' ' . $ouv; + else $ouv= ""; + $t = $phraseur->contenu[$phraseur->depth]; + $phraseur->depth = substr($phraseur->depth, 2); + $t = preg_replace("/[\n\t ]+$/", "\n" . $phraseur->depth, $t); + + // fusion en . + // ATTENTION, certains clients http croient que fusion ==> pas d'atttributs + // en particulier pour les balises Script et A. + // en presence d'attributs ne le faire que si la DTD est dispo et d'accord + // (param fusion_bal) + + if ($t || (($ouv != $name) AND !$fusion_bal)) + $phraseur->res .= ($ouv ? ('<' . $ouv . '>') : '') . $t . ""; + else + $phraseur->res .= ($ouv ? ('<' . $ouv . ' />') : ("")); +} + +// http://doc.spip.org/@xml_textElement +function xml_textElement($phraseur, $data) +{ + $depth = $phraseur->depth; + $phraseur->contenu[$depth] .= preg_match('/^script/',$phraseur->ouvrant[$depth]) + ? $data + : htmlspecialchars($data,ENT_QUOTES); +} + +function xml_piElement($phraseur, $target, $data) +{ + $depth = $phraseur->depth; + + if (strtolower($target) != "php") + $phraseur->contenu[$depth] .= $data; + else { + ob_start(); + eval($data); + $data = ob_get_contents(); + ob_end_clean(); + $phraseur->contenu[$depth] .= $data; + } +} + + +// http://doc.spip.org/@xml_defautElement +function xml_defaultElement($phraseur, $data) +{ + $depth = $phraseur->depth; + + if (!isset($phraseur->contenu[$depth])) $phraseur->contenu[$depth]=''; + $phraseur->contenu[$depth] .= $data; +} + +// http://doc.spip.org/@xml_parsestring +function xml_parsestring($phraseur, $data) +{ + $phraseur->contenu[$phraseur->depth] =''; + + if (!xml_parse($phraseur->sax, $data, true)) { + coordonnees_erreur($phraseur, + xml_error_string(xml_get_error_code($phraseur->sax)) + . "
\n" . + (!$phraseur->depth ? '' : + ('(' . + _T('erreur_balise_non_fermee') . + " " . + $phraseur->ouvrant[$phraseur->depth] . + " " . + _T('ligne') . + " " . + $phraseur->reperes[$phraseur->depth] . + ")
\n" ))); + } +} + +// http://doc.spip.org/@coordonnees_erreur +function coordonnees_erreur($phraseur, $msg) +{ + $entete_length = substr_count($phraseur->entete,"\n"); + $phraseur->err[] = array($msg, + xml_get_current_line_number($phraseur->sax) + $entete_length, + xml_get_current_column_number($phraseur->sax)); +} + +// http://doc.spip.org/@xml_sax_dist +function xml_sax_dist($page, $apply=false, $phraseur=NULL) +{ + // init par defaut si pas fait (compatibilite Tidy espace public) + if (!$phraseur) { + $indenter_xml = charger_fonction('indenter', 'xml'); + return $indenter_xml($page, $apply); + } + + $xml_parser = xml_parser_create($GLOBALS['meta']['charset']); + + xml_set_element_handler($xml_parser, + array($phraseur, "debutElement"), + array($phraseur, "finElement")); + + xml_set_character_data_handler($xml_parser, + array($phraseur, "textElement")); + + xml_set_processing_instruction_handler($xml_parser, + array($phraseur, 'piElement')); + + xml_set_default_handler($xml_parser, + array($phraseur, "defaultElement")); + + xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); + + if ($apply) { + ob_start(); + if (is_array($apply)) + $r = call_user_func_array($page, $apply); + else $r = $page(); + $page = ob_get_contents(); + ob_end_clean(); + // fonction sans aucun "echo", ca doit etre le resultat + if (!$page) $page = $r; + } + + // charger la DTD et transcoder les entites, + // et escamoter le doctype que sax mange en php5 mais pas en php4 + list($entete,$page, $dtc) = sax_bug($page); + + $phraseur->sax = $xml_parser; + $phraseur->entete = $entete; + $phraseur->page = $page; + $phraseur->dtc = $dtc; + $phraseur->phraserTout($xml_parser, $page); + xml_parser_free($xml_parser); +} + +// SAX ne dit pas si une Entite est dans un attribut ou non. +// Les eliminer toutes sinon celles des attributs apparaissent en zone texte! +// Celles fondamentales pour la lecture (lt gt quot amp) sont conservees +// (d'ailleurs SAX ne les considere pas comme des entites dans un attribut) +// Si la DTD est dispo, on va chercher les entites dedans +// sinon on se rabat sur ce qu'en connait SPIP en standard. + +// http://doc.spip.org/@sax_bug +function sax_bug($data) +{ + $r = analyser_doctype($data); + + if (!$r) { + $data = _MESSAGE_DOCTYPE . _DOCTYPE_ECRIRE + . preg_replace(_REGEXP_DOCTYPE, '', $data); + $r = analyser_doctype($data); + } + + list($doctype, $topelement, $avail, $grammaire, $rotlvl, $len) = $r; + + include_spip('xml/analyser_dtd'); + $dtc = charger_dtd($grammaire, $avail, $rotlvl); + + // l'entete contient eventuellement < ? xml... ? >, le Doctype, + // et des commentaires autour d'eux + $entete = ltrim(substr($data,0,$len)); + + if ($dtc) { + $trans = array(); + + foreach($dtc->entites as $k => $v) { + if (!strpos(" amp lt gt quot ", $k)) + $trans["&$k;"] = $v; + } + $data = strtr(substr($data,$len), $trans); + } else { + $data = html2unicode(substr($data,$len), true); + } + return array($entete,unicode2charset($data), $dtc); +} + +// Reperer le Doctype et le decomposer selon: +// http://www.freebsd.org/doc/fr_FR.ISO8859-1/books/fdp-primer/sgml-primer-doctype-declaration.html +// Si pas de Doctype et premiere balise = RSS prendre la doctype RSS 0.91: +// les autres formats RSS n'ont pas de DTD, +// mais un XML Schema que SPIP ne fait pas encore lire. +// http://doc.spip.org/@analyser_doctype +function analyser_doctype($data) +{ + if (!preg_match(_REGEXP_DOCTYPE, $data, $page)) { + if (preg_match(_REGEXP_XML, $data, $page)) { + list(,$pico, $topelement) = $page; + $pico = strlen($pico); + if ($topelement == 'rss') + return array('', + 'rss', + 'PUBLIC', + _DOCTYPE_RSS, + 'rss-0.91.dtd', + $pico); + else { + $dtd = $topelement . '.dtd'; + $f = find_in_path($dtd); + if (file_exists($f)) + return array('', $topelement, 'SYSTEM', $f, $dtd, $pico); + } + } + spip_log("Dtd pas vu pour " . substr($data, 0, 100)); + return array(); + } + list($doctype,$pico, $topelement, $avail,$suite) = $page; + + if (!preg_match('/^"([^"]*)"\s*(.*)$/', $suite, $r)) + if (!preg_match("/^'([^']*)'\s*(.*)$/", $suite, $r)) + return array(); + list(,$rotlvl, $suite) = $r; + + if (!$suite) { + if ($avail != 'SYSTEM') return array(); + $grammaire = $rotlvl; + $rotlvl = ''; + } else { + if (!preg_match('/^"([^"]*)"\s*$/', $suite, $r)) + if (!preg_match("/^'([^']*)'\s*$/", $suite, $r)) + return array(); + + $grammaire = $r[1]; + } + + return array(substr($doctype,strlen($pico)), $topelement, $avail, $grammaire, $rotlvl, strlen($doctype)); +} +?>