/*
Экспериментальный парсер 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>;
= ;
}