OmniMark — язык программирования четвертого поколения, используемый в основном в издательской отрасли. В настоящее время это фирменный программный продукт Stilo International. По состоянию на июль 2022 года последняя версия [1] OmniMark — 11.0.
OmniMark используется для обработки данных и преобразования их из одного формата в другой с использованием потоковой архитектуры [2] , которая позволяет ему последовательно обрабатывать большие объемы контента без необходимости хранить его весь в памяти. Он имеет встроенный анализатор XML и поддержку XQuery через интеграцию с собственной базой данных XML Sedna . Он также имеет функции для обработки правил поиска, которые реализуют аналогичную концепцию регулярных выражений , хотя синтаксис шаблонного выражения больше похож на английский, чем синтаксис регулярных выражений, используемый в Perl и других языках, таких как язык программирования Ruby , оба из которых используются более широко, чем OmniMark. OmniMark также может использоваться для задач преобразования схемы таким же образом, как XSLT , но поддерживает переключение между процедурным и функциональным кодом без необходимости каких-либо дополнительных конструкций для поддержки процедурных элементов.
OmniMark был изначально создан в 1980-х годах канадской компанией-разработчиком программного обеспечения Exoterica как программа обработки SGML под названием XTRAN. [3] Позднее XTRAN был переименован в OmniMark, а Exoterica стала OmniMark Technologies. Нынешние владельцы OmniMark, Stilo International, имеют свои главные офисы в Великобритании, но также имеют офис в Канаде. [4]
В 1999 году президент и генеральный директор OmniMark Джон Макфадден объявил, что OmniMark 5 будет доступен бесплатно, чтобы лучше конкурировать с Perl. [5] OmniMark больше не распространяется по такой модели.
OmniMark рассматривает входные данные как поток, который можно сканировать один раз, а не как статическую коллекцию данных, поддерживающую произвольный доступ. Большая часть программы OmniMark имеет форму условие=>правило действия , где условие распознает длину данных, над которыми нужно действовать, а действие указывает, что нужно сделать с данными. Существует два вида условий:
Правила поиска используются для применения шаблонов к неструктурированному вводу. Длина текста распознается шаблоном , который включает временные переменные шаблона для захвата любой части текста, которая понадобится в выводе. Действие использует эти переменные для создания требуемого вывода:
; Изменить цены с английского формата на французский формат find "$" digit + => dollars "." digit { 2 } => cents ; вывести цену в новом формате output dollars || "," || cents || "$"
Если два правила поиска могут распознать одну и ту же последовательность текста, первое правило «съест» последовательность, а второе правило никогда не увидит текст. Ввод, который не распознается ни одним правилом поиска, не «съедается» и проходит прямо на выход.
OmniMark рассматривает входные данные как поток; программа не хранит входные данные в памяти, если только часть данных не сохранена в переменных. По мере того, как входные данные поступают, OmniMark поддерживает стек элементов , содержащий информацию, которая может использоваться для управления преобразованием текста с помощью средства сопоставления с образцом OmniMark. Когда встречается каждый начальный тег, OmniMark помещает в стек другое описание элемента. Описание элемента включает имя элемента, имена атрибутов с типами и значениями атрибутов, а также другую информацию от синтаксического анализатора (например, является ли этот элемент элементом EMPTY). Когда встречается соответствующий конечный тег, описание элемента извлекается из вершины стека. С SGML некоторые теги могут быть опущены, но OmniMark действует так, как будто теги присутствуют и находятся в нужных местах.
содержание <h1> . </h1> < тело > | .| < / тело > < пример > || .|| < / пример > | | | . | | | | | | . | | | | | | . | | | ABC . DEF Х X: текущая позиция во входном документе Сканирование доступно Информация о местоположении Пример элемента от A до F Пример элементов B–E, тело Пример элементов C–D, тело, h1 C начало содержания D конец содержания
Программа OmniMark использует правила элементов для обработки документов XML или SGML. Правило элемента :
"%c"
. Содержимое обычно запрашивается для сканирования с сопоставлением с образцом, а не для хранения в переменной.Поскольку элементы могут быть вложенными, несколько правил элементов могут быть задействованы одновременно, каждое с соответствующим описанием элемента в стеке элементов. Правила элементов приостанавливаются, ожидая, пока анализатор закончит анализ их содержимого. Активным может быть только правило для элемента наверху стека. Когда достигается конец содержимого для элемента наверху стека, действие для соответствующего правила элемента снова получает управление. Когда это действие завершается, описание элемента извлекается, и управление возвращается действию для следующего нижнего элемента в стеке. Правило элемента может просто выводить проанализированное содержимое (в виде текста) и добавлять суффикс:
элемент "код" вывод "%c" ; разбор и вывод содержимого элемента do когда родительский элемент не является ( "h1" | "h2" | "h3" | "h4" | "h5" | "h6" ) вывод "%n" ; добавление новой строки, если не в заголовке done
Программе не нужно называть все элементы документа, если неименованным элементам можно присвоить какую-то общую обработку:
элемент #подразумевается do когда родительский элемент - "head" suppress ; отбросить дочерние элементы в противном случае вывести "%c" ; проанализировать и вывести содержимое элемента done
Проанализированное содержимое каждого элемента становится доступным в правиле элемента и может быть изменено с помощью блока повторного сканирования , который использует шаблоны для идентификации текста, подлежащего изменению:
элемент "p" ; Изменить цены с английского формата на французский формат повторить сканирование "%c" ; разобрать и сканировать содержимое элемента сопоставить "$" цифру + => доллары "." цифру { 2 } => центы ; вывести цену в новом формате вывести доллары || "," || центы || "$" сопоставить ( любое, кроме "$" ) + => текст ; вывести неценовые последовательности без изменения вывести текст сопоставить "$" => текст ; вывести изолированный символ валюты без изменения вывести текст выполнено
Первый шаблон, который соответствует начальной части текста, «съест» этот текст, и текст не будет доступен для следующих шаблонов, даже если одна из следующих частей может соответствовать более длинной начальной части текста. Любая начальная часть, которая не соответствует ни одному из шаблонов в блоке повторного сканирования ..., будет отброшена.
Правила перевода получают управление сразу после отделения тегов от текста, но до завершения разбора. Каждое правило перевода имеет шаблон, который определяет длину текста для обработки. Эта длина текста не будет включать никаких тегов, но может быть такой же, как полная длина текста между двумя тегами.
Одним из вариантов использования правил перевода является внесение определенных изменений во весь документ:
; Изменить символ разметки на сущность, которая представляла его во входных данных , перевести "&" , вывести "&"
Теги перед текущей точкой во входных данных уже прошли через парсер, поэтому в стеке элементов уже есть описание элемента (или вложенных элементов), которые содержат текст. Следовательно, информация в стеке элементов может использоваться для управления тем, что делается с текстом. Например, операция перевода может быть ограничена символьным содержимым одного или нескольких элементов:
; Изменить цены с английского формата на французский формат translate "$" digit + => dollars "." digit { 2 } => cents when element is ( "p" | "code" ) ; вывести цену в новом формате output dollars || "," || cents || "$"
В некоторых приложениях большая часть документа может быть обработана хорошо спроектированным общим действием, так что только часть документа нуждается в специальной обработке. Это может значительно уменьшить размер и сложность программы и, в случае XML-документов, может сделать программу очень терпимой к изменениям в структуре входного документа.
Это базовая программа «Hello, World!» :
процесс вывод "Привет, мир!"
Эта программа выводит все слова, начинающиеся с заглавной буквы, по одному слову в строке, и отбрасывает весь остальной текст:
обработать отправить файл "myfile.txt" ; или отправить "ЛЮБОЙ текст, отбросить строчные слова" ; вывести заглавное слово, добавить новую строку find ( uc letter * ) => temp output temp || "%n" ; отбросить все остальные символы найти любые ; ничего не выводить
OmniMark может принимать правильно сформированный XML, действительный XML или SGML в качестве структурированного ввода. Эта программа выводит список заголовков первого и второго уровня из файла xhtml, делая отступы для заголовков второго уровня:
; xhtml-headings.xom ; Список заголовков первого и второго уровня из файла xhtml или xhtml5 ; Заголовки второго уровня имеют отступобработка ; преобразование входного документа ; выполнение xml-анализа документа ; анализ корректного XML do xml - анализ ; анализ правильно сформированного XML- файла сканирования "example.html" вывод "%c" ; анализ и вывод содержимого документа выполнено элемент "head" подавить ; отбросить дочерние элементыэлемент "h1" вывод "%c" ; разбор и вывод содержимого элемента вывод "%n" ; добавление конца строкиэлемент "h2" вывести " " ; отступ 2 пробела вывести "%c" ; проанализировать и вывести содержимое элемента вывести "%n" ; добавить конец строки; обработать любой элемент, не указанный в явных правилах выше элемента #implied do when parent is "body" ; отбросить все дочерние элементы, кроме указанных выше suppress ; отбросить дочерние элементы else ; сохранить содержимое любого другого элемента output "%c" ; проанализировать и вывести содержимое элемента done; отбросить символьное содержимое из элемента "body", если этот элемент ; имеет смешанное содержимое , преобразовать любой + => X , если элемент - body ; нет вывода (ничего не делать с переменной "X")
Правило element #implied
выбирает любой элемент, который не распознается ни одним из других правил элементов.
Эта программа заменяет пропущенные теги в простом документе SGML и выводит что-то похожее на правильно сформированный XML. Программа не переводит правильно пустые теги SGML в пустые теги XML и не обрабатывает многие функции SGML, которые могут использоваться в документах SGML.
; Вставить пропущенные теги в документ SGML ; ; Эта программа упрощена и предназначена только для демонстрации. ; Программа не обрабатывает многие функции SGML ; Для создания правильно сформированного XML из большинства документов SGML потребовалась бы более сложная программа .процесс сделать sgml - разбор документа отсканированный файл "example.sgml" вывод "%c" ; разбор и вывод содержимого документа выполненэлемент #подразумеваемый вывод "<%q" ; начало начального тега ; запись атрибутов как пары имя="значение" повторить для указанных атрибутов как attr вывести " " || ключ атрибута attr || "=%" % v ( attr ) % " " снова вывод ">" ; завершить начальный тег ; запись содержимого элемента вывода "%c" ; написать конечный тег, если элемент допускает вывод содержимого "</%q>", если только содержимое не ( пустое | conref ); перевести символы разметки (в тексте) обратно в сущности , ; которые представляли их в исходном вводеперевести "&" вывести "&"перевести "<" вывод "<"перевести ">" вывод ">"
<!-- Простой документ SGML для ввода в демонстрации OmniMark --> <!DOCTYPE example [ <!ELEMENT example O - (head, body)> <!ELEMENT head OO (title?)> <!ELEMENT title - - (#PCDATA)> <!ELEMENT body - O ((empty|p)*)> <!ELEMENT empty - O EMPTY> <!ELEMENT p - O (#PCDATA)> <!ATTLIST P id ID #IMPLIED> <!ENTITY amp "&"> <!ENTITY lt "<"> <!ENTITY gt "> "> ]><example> <title> Заголовок </title> <body> <p> Текст <empty> <p id= "P-2" > <&> </example>
<EXAMPLE><HEAD><TITLE> Заголовок </TITLE></HEAD><BODY><P> Текст </P><EMPTY><P ID= "P-2" > <&> </P></BODY></EXAMPLE>