/* Экспериментальный парсер XML в рефал и обратно. Рефал-результат - рефал-выражение, в котором <TAG...> ... </TAG> заменено на ((TAG...) ... ) Входные точки: Go - отладочные пуски, XML_REF - преобразование из XML в рефал, XML_REF1 - преобразование из XML в рефал с вводом файла, Arg 1 - name файла, канал 1, XML_REF2 - преобразование из XML в рефал с вводом файла, Arg 1 - name файла, канал 1, REF_XML - преобразование из рефала в XML. Исходный вариант, которого никто не видел, обладал недостатками: 1. Было несколько просмотров с неэффективным спариванием скобок, в результате чего текст в 20К обрабатывалсja 40 секунд, а в 200К не хватило 10 минут. 2. Оказалось, что конец строки тоже может быть разделителем. 3. В начале строк могут присутствовать не только пробелы, но и символы с кодом 09. 4. Кавычки и двойные кавычки не всегда правильно обрабатываются в этой реализации рефала-5. 5. В комментариях на русском языке я не могу использовать последнюю букву русского языка "я" - refc на ней просто останавливается. (Windows98 - кодировка windows). */ $EXTRN OPEN, GET, INPUT; $EXTRN ARG, PROUT; $EXTRN IMPLODE, EXPLODE; $EXTRN CHR; $EXTRN BR, DG; * Отладка: ввод, преобразование, печать. $ENTRY Go { = <Go1 (<Arg 3>) >; } Go1 { * Преобразование из XML в XML ('xml_xml') = <REF_XML <XML_REF1 >>; * Преобразование из XML в рефал ('xml_ref') = <Prout <XML_REF1 >>; } * Ввод XML-файла (Arg1). * Внимание ! При вводе ничего не игнорируем (пробелы и отступы)! * Строки разделяем макроцифрой 1. * Не понятно, как работать с отступами в начале строк, * по идеологии XML (компьютерная обработка) отступов и не должно * быть. Будут предложения - переделаем. $ENTRY XML_REF1 { = <Open 'r' 1 <Arg 1>> <XML_REF <XmlInput <Get 1>>>; } $ENTRY XML_REF2 { e.1 = <Open 'r' 1 e.1> <XML_REF <XmlInput <Get 1>>>; } XmlInput { e.1 0 = e.1; e.1 = e.1 1 <XmlInput <Get 1>>; } $ENTRY XML_REF { e.1 = <SparTag ( 5 ) e.1>; } * Предполагаем, что '<' , '>' все же в наличии парами. SparTag { ( 5 e.1) = e.1; * - незакрытый тэг в конце - закрываем ((e.1) e.2) = <SparTag (e.1 (e.2))>; * - уже спаренный тэг (e.1) ((e.2) e.a) e.3 = <SparTag (e.1 ((e.2) e.a) ) e.3>; * - закрывающий тэг ((e.1) (e.2) e.a) ('/' e.2) e.3 = <SparTag (e.1 ((e.2) e.a)) e.3>; ((e.1) (e.2 e.x) e.a) ('/' e.2) e.3 = <SparTag (e.1 ((e.2 e.x) e.a)) e.3>; * - незакрытый тэг - закрываем ((e.1) (e.7) e.a) ('/' e.2) e.3 = <SparTag (e.1 ((e.7) e.a)) ('/' e.2) e.3>; * - нет открывающего тэга ( 5 e.1) ('/' e.2) e.3 = <Prout ' !!! No open TAG !!! '> <SparTag ( 5 e.1 (' !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ') ('/' e.2)) e.3>; * - открывающий тэг (e.1) (e.2) e.3 = <SparTag ((e.1) (e.2)) e.3>; (e.1) e.2 '<' e.3 = <SparTag (e.1 <Zam e.2> ) <Tag '<' e.3>>; (e.1) e.2 = <SparTag (e.1 <Zam e.2> ) >; } * Замена <TAG ...> и </TAG> * на (TAG ...) и (/TAG) * Могут быть такие тэги: * <!-- ... --> - комментарии, * <! ....... > - элементы DTD, * <? ...... ?> - заголовки, которые всегда незакрытые. * Их делаем пока без обработки. * Уже спаренные открывающий и закрывающий тэги имеют вид ((e.1) e.2) Tag { '<!--' e.2 '-->' e.3 = (('!--' <Zam e.2> '--')) e.3; '<!' e.2 '>' e.3 = (('!' <Zam e.2>)) e.3; '<?' e.2 '?>' e.3 = (('?' <Zam e.2> '?')) e.3; '<' e.2 '>' e.3 = <Tag1 e.2> e.3; e.1 = e.1; } * Преобразование к стандартному виду * На примере /* XML-выражение: <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" lang="en"> .... </html> преобразуется в рефал-выражение: ((HTML (XSL VERSION IS '1.0') (XMLNS XSL IS 'http://www.w3.org/1999/XSL/Transform') (LANG IS 'en') ) .... ) */ Tag1 { * закрывающий тэг '/' e.1 = ('/' <Tag2 ( ) <Del e.1>> ); * закрытый тэг e.1 '/' = (( <Tag2 ( ) <Del e.1>> )); * открывающий тэг e.1 = ( <Tag2 ( ) <Del e.1>> ); } * убирание пробелов, табулиров., конца строки - справа и слева * - много лишних обращений к Del для надежности Del { e.1 = <Del1 <C > e.1>; } C { = ( ' ' <CHR 9> ); } Del1 { (e.a s.b e.c) s.b e.1 = <Del1 (e.a s.b e.c) e.1>; (e.a s.b e.c) e.1 s.b = <Del1 (e.a s.b e.c) e.1>; (e.a) 1 e.1 = <Del1 (e.a) e.1>; (e.a) e.1 1 = <Del1 (e.a) e.1>; (e.a) e.1 = e.1; } * выделение имени тэга Tag2 { (e.1) ' ' e.2 = <ImplodeTag1 e.1> <ImplodeTag2 <Del e.2>>; (e.1) 1 e.2 = <ImplodeTag1 e.1> <ImplodeTag2 <Del e.2>>; (e.1) s.a e.2 = <Tag2 (e.1 s.a) e.2>; (e.1) = <ImplodeTag1 e.1>; } * !!! xsl: ... - обрабатываем иначе * Долго думал, что делать с ":" в имени тэга, * решил представлять его двумя составными символами. * Не знаю, насколько удачно такое решение * - всегда можно легко переделать. ImplodeTag1 { 'xsl:' e.2 = <IMPLODE 'Xsl'> <IMPLODE e.2>; e.1 ':' e.2 = <IMPLODE e.1> <IMPLODE e.2>; e.1 = <IMPLODE e.1>; } ImplodeTag2 { e.1 '=' e.2 = <IT (e.1) <Del e.2>>; = ; e.1 = (e.1); } IT { * Is вставил по привычке - надо ли ? * Без Is менее наглядно, да и потом при программировании * будут более читабельные программы. (e.1) '' e.2 '' e.3 = (<ImplodeTag1 <Del e.1>> Is <Zam e.2>) <ImplodeTag2 <Del e.3>>; (e.1) "" e.2 "" e.3 = (<ImplodeTag1 <Del e.1>> Is <Zam e.2>) <ImplodeTag2 <Del e.3>>; } * Замены: * '<' -> '<' * '>' -> '>' * '&' -> '&' * '"' -> '"' * 1 - разделитель строк - убираем. Zam { 1 e.1 = <Zam e.1>; '<' e.1 = '<' <Zam e.1>; '>' e.1 = '>' <Zam e.1>; '&' e.1 = '&' <Zam e.1>; '"' e.1 = '"' <Zam e.1>; s.a e.1 = s.a <Zam e.1>; (e.1) e.2 = (<Zam e.1>) <Zam e.2>; = ; } * ------------------------------------------------------------------ * Преобразование из рефала в XML. * Исходное выражение - в поле зрения, * результат - печатаем. * Не понятно, когда может понадобиться что-то иное. * На всякий случай, ввожу функцию Out, в которой путем * убирания звездочки результирующее выражение останется * в поле зрения. Out { * e.1 = e.1; = ; e.1 = <Out1 <Prov <C > e.1>>; } * Здесь - попытка учесть имеющиеся пробелы и отступы Prov { (e.a s.b e.c) s.b e.1 = s.b <Prov (e.a s.b e.c) e.1>; (e.a) e.1 = (e.1); } Out1 { e.1 ( ) = <BR LineXML '=' <DG LineXML> e.1>; e.1 (e.2) = <Prout <DG LineXML> e.1 e.2>; } $ENTRY REF_XML { e.1 (e.2) e.3 = <Out <Zm e.1>> <Ref1 (e.2)> <REF_XML e.3>; e.1 = <Out <Zm e.1>>; } Ref1 { * закрытый тэг ((e.2)) = <Zakr e.2>; * Если нижний уровень скобочной структуры, то выводим в одну строку ((s.a s.b e.2) e.3), <Name s.a s.b>: e.n , <Param e.2>: e.p , e.3: { e.4 (e.5) e.6 = <Out '<' e.n e.p '>' > <REF_XML e.3> <Out '</' e.n '>' >; e.4 = <Out '<' e.n e.p '>' <Zm e.3> '</' e.n '>' >; }; ((s.a e.2) e.3), <Name s.a>: e.n , <Param e.2>: e.p , e.3: { e.4 (e.5) e.6 = <Out '<' e.n e.p '>' > <REF_XML e.3> <Out '</' e.n '>' >; e.4 = <Out '<' e.n e.p '>' <Zm e.3> '</' e.n '>' >; }; e.1 = <Zm e.1>; } Zakr { '!' e.1 = <Out '<!' <Zm e.1> '>' >; '?' e.1 = <Out '<?' <Zm e.1> '>' >; e.1 (e.2) e.3 = <Out '<' <Name e.1> <Param (e.2) e.3> '/>' >; e.1 = <Out '<' <Name e.1> '/>' >; } * Обработка имени тэга Name { s.a s.b = <EXPLODE s.a> ':' <EXPLODE s.b>; s.a = <EXPLODE s.a>; } * Обработка параметров тэга Param { (e.1) e.2 = ' ' <Param1 e.1> <Param e.2>; = ; } Param1 { e.1 Is e.2 = <Name e.1> '=' <Param2 e.2>; } Param2 { e.1 "" e.2 = '' e.1 "" e.2 '' ; e.1 = "" e.1 "" ; } * Замены: * '<' -> '<' * '>' -> '>' * '&' -> '&' * '"' -> '"' Zm { * e.1 = e.1; '<' e.1 = '<' <Zm e.1>; '>' e.1 = '>' <Zm e.1>; '&' e.1 = '&' <Zm e.1>; '"' e.1 = '"' <Zm e.1>; s.a e.1 = s.a <Zm e.1>; (e.1) e.2 = (<Zm e.1>) <Zm e.2>; = ; }