English version

Содержание


0. Что это такое?
1. Мотивация
2. Принцип и синтаксис
  • 2.1. Кодировка
  • 2.2. Синтаксис (SINX уровень 0)
  • 2.3. Базовые метасинтаксические рекомендации (SINX уровень 1)
  • 2.4. И это всё?
  • 3. Почему SINX, а не XML?
    4. Библиотека
    5. Соглашение об использовании
    6. Пример софта
    7. Дополнительные материалы (обновления от 2011 и далее)

    0. Что это такое?


    SINX (SINX Is Not XML) – язык разметки полуструктурированных данных, альтернативный XML, HTML и огромному множеству менее известных альтернатив. Да, ещё один. В чём смысл, спросите вы? Зачем нам ещё один язык разметки?
    Не знаю, как вам, но расскажу, зачем он понадобился мне и почему его пришлось придумать.

    1. Мотивация


    Не секрет, что одна из наиболее частых потребностей в практике программирования – представление, хранение и распознавание данных в неких текстовых форматах. Типичные случаи:
  • конфигурационные и управляющие файлы,
  • таблицы ресурсов, различные манифесты,
  • сериализация и десериализация внутренних данных,
  • логи и отчёты, предназначенные для автоматизированной обработки,
  • ...
  • Почему форматы для подобных задач желательны именно текстовые? Во-первых, для чтения и редактирования любого текстового формата достаточно блокнота (бывают, конечно, форматы, для которых блокнота мало, но зато его именно достаточно), а для бинарного формата требуются специальные редакторы, как правило – специализированные под каждый конкретный формат. В ряде случаев это неудобно и непрактично. На самопальные же форматы для приземлённых гаражных нужд не напасёшься никаких редакторов. Во-вторых, бинарные форматы по самой своей природе обладают относительно жёсткой структурой. Если программа эволюционирует, и в данных, представляемых ими, что-то появляется, исчезает или меняет место, научить программу понимать формат предыдущей версии (или хотя бы написать конвертор в следующую) становится накладнее, чем в текстовом случае.
    Бывает так, что подобный формат требуется не один. Мне, например, в один прекрасный момент потребовалось сразу целых три – для конфигурационного, для локализационного и для сериализационного файлов. А какая самая неприятная особенность текстового (хотя, почему только текстового...) формата? Правильно, написание парсера (в более общем случае – ещё и генератора).
    Поэтому программист рано или поздно приходит к мысли, что вместо зоопарка форматов хорошо бы иметь один универсальный, на базе которого строились бы все остальные. Если формат хороший, то парсер и генератор для него пишутся только один раз, а работа с более сложными структурами более или менее тривиальным образом ведётся в терминах базового парсера/генератора, без доведения последнего под конкретные случаи с помощью лобзиков и напильников.
    Итак, мне понадобился формат со следующими характеристиками:
  • текстовый,
  • позволяющий представить как структурированные данные, в которых главную роль играет древовидная структура, так и текст с незначительной разметкой, где главную роль играет сам текст.
  • Какая мысль у вас возникает первой при виде таких требований? Конечно же, XML. Он заточен именно под такие задачи, он – распространённый индустриальный стандарт, на нём основано множество технологий, для него существует уйма готовых библиотек на всех языках мира, и прочая, и прочая...
    Казалось бы, бери да пользуйся. Ан нет. XML меня абсолютно не устроил, и вот чем.
    1. Он избыточен. Он просто запредельно избыточен. Чтобы понять, насколько всё ужасно, посмотрите хотя бы на примеры XML-RPC и попробуйте осознать, что в этих примерах речь идёт всего лишь о передаче пары параметров. XML-документы считаются человекочитаемыми исключительно формально. На практике разглядеть данные среди многочисленных открывающе-закрывающих тегов крайне затруднительно, не говоря уже о том, чтобы такой документ набрать ручками.
    2. Он навороченный. Он невообразимо навороченный. Он изобилует ненужными и дублирующими друг друга излишествами. Чего стоит одна только альтернатива <tag><value>data</value></tag> vs. <tag value="data"/> для представления одного и того же по существу куска данных!
    Как следствие, все так называемые готовые библиотеки для работы с оным форматом – жирные непотребства, которые по размеру и количеству файлов занимают места едва ли не на порядок больше, чем иные программы (а нам всего-то надо было несчастную конфижку для hello, world...), нередко требуют нетривиального билда (за которым волочатся ГНУсные тулчейны и всякие $тудии), а интерфейс, который они дают – итерации разной степени рукопашности по мешанине из атрибутов и поддеревьев. Глядя на код, который при этом получается, хочется рыдать кровавыми слезами. Если вам пока ещё не хочется, найдите в анналах истории, например, справку по функции GetPrivateProfileString и группе ей подобных (там же заодно посмотрите описание формата INI-файла), просветитесь, а после сравните, как делается доступ к XML-документам (заметьте, к уже загруженным и распарсенным) в считающейся одной из наиболее простых XML-библиотек.
    При всём при этом, не всякая чудо-библиотека может похвастаться умением понимать XML во всей его полноте (пример, раздел с недвусмысленным названием 'What it doesn't do?').
    Многие люди считают XML чем-то хорошим исключительно потому, что пользуются производными форматами через соответствующие программы (офисы, инкскейпы, экспрешенбленды и т. д.) и не видят происходящего под капотом. Но у нас, простых программистов с простыми приземлёнными нуждами, писателей, а не читателей, критерии несколько иные. Поэтому не знаю, как для вас, а для меня было очевидно, что XML – наихудшее из возможных решений (к тому же, в моём конкретном случае – откровенный overkill).
    Я вас умоляю, только не надо стыдить меня неприятием международного стандарта, склонностью к велосипедостроительству, и всё такое. Вот сидит простой советский программист, перед ним простой компилятор с программной строки и девственно чистый блокнот, и стоит задача – написать небольшую консольную программу, немного конфигурируемую. Как все эти замечательные международные стандарты помогут ему против необходимости тащить в дом и приучать к лотку многотонного монстра, на фоне которого его собственный код затеряется жалким придатком? Вот именно. А если монстр уже притащен и приучен, причина этому может быть только одна – программисту было явно больше нечем заняться.
    Итак, XML не нужен. Какие более простые и лишённые указанных недостатков альтернативы предлагает нам коллективный разум?
    YAML, JSON, XF, тыщи их?
    Они, безусловно, лучше, но слишком узкоспециализированны. Конкретно говоря, все эти форматы заточены сугубо под данные, а представление в них текста с незначительной разметкой – занятие неблагодарное. Кроме того, их синтаксис в чём-то функционально избыточен, в чём-то слишком негибок. К примеру, JSON предусматривает ровно 5 базовых типов данных (строка, число, бул, словарь, последовательность). Чтобы быть в состоянии распарсить данный формат, программа должна понимать все пять, даже если какие-то из них ей не нужны. С другой стороны, если программе требуется какой-то другой тип данных (скажем, комплексное число или текст с разметкой), формат резко перестаёт быть компактным, и начинаются косяки. Примерно так же дело обстоит и с остальными.
    Адаптированные S-expressions (как в презренном лиспе).
    Очень неплохо. Примерно что-то такое мне и было нужно – компактность и гибкость структуры в одном флаконе. Но и тут не всё идеально. Во-первых, этот формат тоже ориентирован на данные, и представление текста с разметкой (напомню, таково одно из требований!) в нём по-прежнему несколько неуклюже. А во-вторых, синтаксис всё ещё сложноват. Не знаю, какими представлениями о простоте руководствовался автор, но направления для упрощения и устранения излишеств просматриваются с первых же строчек спецификации.
    Через все эти мытарства и родилась идея формата SINX.
    Не сказать, чтобы формат получился самобытным и революционным. Задачи нарисовать новый язык разметки, ни на что не похожий, не ставилось (зачем?) – заимствования из предшественников заметны невооружённым глазом. (Да и затравка формата, в общем-то, не придумана с нуля, а позаимствована из одного древнего редактора для первого старкрафта – мне запомнилось, как оригинально автор решил проблему ввода непечатных символов). Приоритеты были следующие:
  • формат, не уступающий XML и HTML по равнопригодности как для текста, так и для структурированных данных, но избавленный от их тяжеловесности,
  • максимальная простота и минимальная избыточность. Если у нас текст, он должен не теряться среди элементов синтаксиса и как можно меньше искажаться ему в угоду. Если у нас структурированные данные, средств синтаксиса должно хватать на описание структуры, и ни на грамм больше. Классифицировать данные по типам, разложить их на информацию и метаинформацию юзер сможет и сам, если понадобится (а если не понадобится, то в формате это тем более ни к чему). Наша же задача – дать ему вытащить эти данные без лишней бюрократии и мутных условностей.
  • Насколько получилось реализовать задуманное – судите сами.

    2. Принцип и синтаксис


    Идея формата следующая. Есть SINX-строка – последовательность символов (конечная), в том числе и пустая. Символы могут быть двух видов:
  • терминальный (буква, цифра и т. д.),
  • специальный, характеризующийся именем и данными. Данные специального символа также являются SINX-строкой, к которой рекурсивно применимо всё вышесказанное.
  • От этого принципа и танцуют дальнейшие построения.

    2.1. Кодировка


    Для формата SINX годится любая кодировка, в которой представимы символы '<', '>', '%' и есть символы, считающиеся пробельными (whitespaces). Желательно, но менее обязательно наличие символов '.', ':', '=', и ещё менее обязательно – '-', '#', символов для всех шестнадцатеричных цифр и букв 'x' (латинский икс), 'l' и 'g'. Рекомендуется UTF-8 или какая-нибудь 8-битная кодировка на основе ASCII. Но, если желаете извращений, это может быть UTF-32 или какой-нибудь EBCDIC.
    Важное замечание: все символы в SINX берутся, как есть, к ним ни при каких обстоятельствах не применяется никаких трансляций и трансформаций. То есть, последовательности пробелов не склеиваются и не выбрасываются, табуляция и переводы строк не транслируются в пробелы, регистр букв учитывается, и т. д. Возможна трансляция CR/LF в одиночный перевод строки и прочие платформоспецифичные выкрутасы, но предполагается, что это происходит на уровне физического чтения потока перед скармливанием данных в SINX-парсер, и формат этих тонкостей не касается. На уровне формата все символы, поступившие на вход, учитываются без изменений. Если речь идёт о некой последовательности без уточнений, подразумевается, что она бинарно-дословно соответствует её представлению во входном потоке.

    2.2. Синтаксис (SINX уровень 0)


    SINX-строка состоит из последовательности элементов. Элементы могут быть следующие:

    1) Простой терминальный символ – любой символ, кроме '<' и '>'.
    Пример: aba125 буквы входят в пример 15#tbs.
    Простой терминальный символ обозначает просто соответствующий терминальный символ.

    2) Терминальная последовательность:
    '<' ограничитель '%' последовательность-символов '%' ограничитель '>'
    где:
    ограничитель – последовательность любых символов, кроме '%', '<', '>', '=' и пробельных (может быть и пустой), причём второй ограничитель должен быть точно той же (бинарно идентичной) последовательностью, что и первый,
    последовательность-символов – последовательность любых возможных символов в данной кодировке, не включающая подпоследовательности '%' ограничитель '>'.
    Примеры:
    <abc%пример%abc>
    <%пример последовательности с пустым ограничителем%>
    <ab%пример последовательности < со служебными >< символами > % внутри%%ab> (последний знак процента перед %ab – часть последовательности)
    <$#!@%пример последовательности с небуквенноцифровыми символами в ограничителе %$#!@>
    <abcdx%это %abcdx тоже %abcdx > правильный %abcd> пример%abcdx> (в последовательность входят все символы между <abcdx% и %abcdx> – завершающим маркером последовательности является не сам ограничитель, а именно последовательность из процента, ограничителя и закрывающей угловой скобки)
    Терминальная последовательность интерпретируется, как последовательность составляющих её терминальных символов, не включая начальный и конечный маркеры.
    Пример: abc<%def%>ghi интерпретируется аналогично abcdefghi
    Однако начальный и конечный маркеры считаются частью содержащей их SINX-строки и включаются в неё, если речь идёт о ней в целом.
    Символы внутри последовательности не интерпретируются никаким специальным образом и считаются частью последовательности, независимо от их вида.
    <abc% можно <def% даже %def> и так %abc> (<def% и %def> в данном случае – просто наборы символов, включаемые в последовательность наравне с остальными)
    Назначение последовательности – выражение куска данных, в котором могут встречаться служебные символы.
    <%Например, арифметических или языковых выражений, типа x = i>11? 100 : 500;%>

    3) Специальный символ:
    '<' имя разграничитель SINX-строка '>'
    где:
    имя – последовательность любых символов, кроме '%', '<', '>', '=' и пробельных (может быть и пустой),
    разграничитель – либо последовательность пробельных символов (если за ней следует '<' или '>', она может быть и пустой), либо одиночный символ '='.
    SINX-строка является данными специального символа и может, в свою очередь, состоять из всех перечисленных ранее видов элементов (включая спецсимволы). Она может быть пустой.
    Примеры:
    <a пример>
    <$!#@ пример с нетривиальным именем спецсимвола>
    <a пример с составными данными: <xxx%последовательность%xxx>, <b вложенный спецсимвол>>
    <a=пример с ограничителем '='>
    <a
    пример с ограничителем из перевода строки (в предположении, что в используемой кодировке он считается пробельным символом)>
    < пример спецсимвола с пустым именем>
    <=ещё один>
    <xxx> (пример спецсимвола с пустыми данными)
    <xxx=> (пример спецсимвола с пустыми данными и разграничителем '=')
    <xxx<%yyy%>> (пример спецсимвола с пробельным разграничителем нулевой длины, что возможно, поскольку его данные которого начинаются с '<')
    <> (пример спецсимвола с пустым именем и данными)
    <=> (ещё один)
    < > (ещё один)
    <a =тут символ '=' является частью данных, т. к. разграничитель – пробел>
    <a= тут разграничителем является '=', а пробел, стоящий после него, является частью данных>
    Символы разграничителя и открывающие-закрывающие '<' и '>' не включаются ни в имя, ни в данные спецсимвола. Однако они считаются частями содержащей его SINX-строки и включаются в неё, если речь идёт о ней в целом.
    Специальный символ интерпретируется, как спецсимвол с соответствующим именем и данными. Относительно имени есть следующие нюансы:
  • если имя начинается с '.' и/или заканчивается на ':', эти символы не включаются в само имя, но парсер *должен* запомнить тот факт, что они были, в виде отдельных флагов для данного спецсимвола. '.' в начале имени называется признаком атрибута, ':' в конце – признаком составного символа.
  • Например, все эти символы имеют одно и то же имя:
    <a пример символа с именем 'a'>
    <.a пример символа с именем 'a' и признаком атрибута>
    <a: пример символа с именем 'a' и признаком составного символа>
    <.a: пример символа с именем 'a' и признаками атрибута и составного символа>
  • кроме того, парсер *должен* запомнить в виде отдельного флага для данного спецсимвола, какой именно разграничитель в нём был использован – последовательность пробелов или '='. Разграничитель '=' называется признаком терминальности.
  • Признаки сами по себе не несут синтаксической нагрузки (кроме того, что их нужно исключать из имени и учитывать отдельно). Их смысл – метасинтаксический. Пользователь конечного формата вправе наделять их любым значением на своё усмотрение или игнорировать. SINX уровень 1 (см. ниже) содержит рекомендации насчёт применения признаков, но они не являются требованиями, и на уровне формата к их соблюдению пользователя ничто не принуждает.
    Если символы '.', ':' или '=' в выбранной кодировке не предусмотрены, все правила, в которых упоминаются соответствующие признаки, допускается исключить.

    Как следует понимать фразу "считаются частью содержащей их SINX-строки и включаются в неё, если речь идёт о ней в целом" в пп. 2) и 3)? Очень просто. Если речь идёт о посимвольном чтении из SINX-строки, то символы не учитываются, а если речь идёт о SINX-строке, как едином целом (например, о данных спецсимвола), то подразумеваются все составляющие её символы, включая служебные.
    Пример: 1235<xx%abcdef%xx>678<a <%x%>> есть последовательность символов: '1', '2', '3', '5', 'a', 'b', 'c', 'd', 'e', 'f', '6', '7', '8', 'спецсимвол с именем a и данными <%x%>'. Но в то же время она в целом является SINX-строкой 1235<xx%abcdef%xx>678<a <%x%>>. Аналогично, данные спецсимвола с именем a из этой последовательности – SINX-строка <%x%>, но с точки зрения посимвольного чтения они представляют собой последовательность из одного символа 'x'.

    Вот и весь синтаксис SINX. Если желаете грамматики, она такова:

    любой-терминальный-символ ::= любой терминальный символ, представимый в используемой кодировке
    терминальный-символ-не-угловая-скобка ::= любой терминальный символ, представимый в используемой кодировке, кроме '<' и '>'
    терминальный-символ-имени ::= любой терминальный символ, представимый в используемой кодировке, кроме '<', '>', '%', '=' и пробельных символов
    пробельный-терминальный-символ ::= любой символ, считающийся в используемой кодировке пробельным
    имя ::= терминальный-символ-имени*
    разграничитель ::= '=' | пробельный-терминальный-символ*
    (если '=' в выбранной кодировке не существует, то разграничитель ::= пробельный-терминальный-символ*)
    SINX-строка ::= SINX-символ*
    SINX-символ ::= терминальный-символ-не-угловая-скобка | терминальная-последовательность | спецсимвол
    терминальная-последовательность ::= '<' имя '%' любой-терминальный-символ* '%' имя '>' (2-е имя должно бинарно идентичным первому)
    спецсимвол ::= '<' имя разграничитель SINX-строка '>'

    Но, как вы сами видите, написать парсер можно и без всякой грамматики – логика очень простая.
    Синтаксис организован так, чтобы, по возможности, валидной SINX-строкой являлась любая последовательность символов. Действительно произвольная последовательность может быть ошибочной. Но синтаксическая ошибка – не повод, чтобы отказаться от возвращения результата. В случае обнаружения перечисленных ниже ошибок парсер *должен* реагировать одним из предложенных для соответствующей ошибки вариантов, на усмотрение реализации:

    1) Символ '>', не имеющий соответствующего открывающего '<'. Пример: abc>de
    Варианты:
  • считать его концом потока, не включая в сам поток (abc),
  • игнорировать (рассматривать поток так, как если бы этого символа не было) (abcde).
  • 2) Незакрытый спецсимвол. Пример: abc<de <f><g h
    Варианты:
  • считать, что все незакрытые явным образом спецсимволы автоматически закрываются с концом потока в соответствующем порядке (abc<de <f><g h>>),
  • игнорировать открывающие фрагменты незакрытых спецсимволов, включая разграничители (abc<f>h).
  • 3) Незакрытая терминальная последовательность. Пример: <abc%def
    Её всегда следует считать автоматически закрывающейся с концом потока (<abc%def%abc>).
    4) Последовательность '<' имя (конец потока) следует считать открывающим фрагментом спецсимвола с пробельным разграничителем нулевой длины и, соответственно, частным случаем ошибки 2).

    Парсер *может* сообщать об обнаруженных синтаксических ошибках дополнительно, но всегда *должен* проводить распарсивание до конца в соответствии с выбранными вариантами реакции.

    Описание синтаксиса и вариантов действия при синтаксических ошибках назовём "нулевым уровнем формата SINX". Для практического применения, в принципе, уровня 0 уже достаточно. Но перед языками разметки часто встречаются некоторые задачи, которые вам, скорее всего, всё равно придётся так или иначе решить в рамках своего формата. Для наиболее распространённых из них предусмотрен SINX уровень 1, описанный в следующей главе.

    2.3. Базовые метасинтаксические рекомендации (SINX уровень 1)


    SINX уровень 0 задаёт синтаксис формата, а SINX уровень 1 предлагает некоторые обязательные соглашения о том, как интерпретировать в рамках этого синтаксиса определённые специальные символы.

    1) Терминальные символы, заданные через код.
    Спецсимволы с именами вида '#' последовательность-десятичных-цифр или '#' '0' x|X последовательность-шестнадцатеричных-цифр следует интерпретировать, как символ с соответствующим численным кодом в принятой кодировке. Примеры:
    <#33> (символ '!' (по ASCII))
    <#0x33> (символ '3' (по ASCII))
    <#0XDeAdBeEf> (символ с 16-чным кодом DEADBEEF)
    Данные спецсимвола при этом не учитываются. Т. е., например, mail<#0x40 gg>to интерпретируется аналогично mail<#0x40>to и mail@to.
    Если имя спецсимвола начинается с '#', но не представляет собой правильного десятичного или 16-чного числа, этот спецсимвол не транслируется в терминальный и рассматривается, как обычный спецсимвол с данным именем.
    Предусмотрено два особых спецсимвола, которые интепретируются как '<' и '>':
    <lt> – '<',
    <gt> – '>'.
    Буквы l, g и t могут быть в любом регистре, если это допускается кодировкой.
    Пример: <example вот спецсимволы, выраженные прописью: <lt><gt> <lT>spec1 содержимое1<Gt> <Lt>spec2 содержимое2<gT>> – интерпретируется аналогично <example <%вот спецсимволы, выраженные прописью: <> <spec1 содержимое1> <spec2 содержимое2>%>>
    Это правило допускается исключить, если в выбранной кодировке не предусмотрено достаточного количества символов для выражения 16-чных цифр, символов '#' и букв 'l', 'g' и 'x'.

    2) Комментарии.
    Спецсимволы с именем '--' следует считать комментариями и игнорировать.
    Пример: a<-- b>cd – аналогично acd

    2 вышеперечисленных соглашения обязательны для соответствия уровню 1. Кроме них, SINX уровень 1 предлагает и необязательных к соблюдению рекомендаций относительно использования признаков.

    3) Признак терминальности (разграничитель '=' в спецсимволе) *следует* использовать в случае, если все данные спецсимвола считаются в рамках конечного формата терминальными – т. е., либо конечным неделимым куском данных, либо формат этого куска является пользовательским и распарсивается отдельно, вне рамок SINX-формата. Заметьте, однако, что эта конвенция не освобождает данные от необходимости быть синтаксически правильной SINX-строкой.
    Спецсимволы в терминальных данных *следует*, на усмотрение конечного формата в каждом конкретном случае, либо интерпретировать, как терминальные символы (в соотв. с соглашением 1 данной главы, если они подходят по формату), либо игнорировать, либо включать в данные в виде бинарно-дословной последовательности составляющих их символов. Терминальные последовательности в терминальных данных, также на усмотрение конечного формата, *следует* либо интерпретировать, как соответствующую последовательность, либо включать в данные в виде бинарно-дословной последовательности составляющих её символов.
    Примеры:
    <url=http://mikle33.narod.ru>
    <url=http:<#47><#47>mikle33.<-- комментарий –->narod.<%ru%>> (данные, на усмотрение конечного формата, могут быть проинтерпретированы, как: http://mikle33.narod.ru, http:<#47><#47>mikle33.narod.ru, http://mikle33.narod.<%ru%>, http:<#47><#47>mikle33.narod.<%ru%>, http:<#47><#47>mikle33.<-- комментарий –->narod.<%ru%>, и т. п.)
    Если данные спецсимвола пустые, то разграничитель '=' *можно* не использовать.

    4) Признак атрибута *следует* использовать для спецсимволов, которые в рамках конечного формата считаются атрибутами объемлющего спецсимвола (или, если таковых нет, то всего потока), и предполагается, что спецсимволов с таким именем в объемлющем спецсимволе/потоке может быть в количестве не более одного. (Т. е., спецсимволы с признаком атрибута рекомендуется использовать в качестве аналогов атрибутам в XML/HTML.) Если спецсимволов с таким именем встречается более одного, то, на усмотрение конечного формата, действительным можно считать либо самый первый, либо самый последний.
    Пример:
    <error <.locations <line=11><line=22><line=100500>at these lines>An error has been encountered>

    5) Признак составного символа *следует* использовать для спецсимволов, которые в рамках конечного формата используются для хранения структурированных данных, и предполагается, что значащими в их данных являются только спецсимволы (на данные вложенных спецсимволов эта конвенция не распространяется, если только они тоже не являются составными спецсимволами). Все прочие символы (включая спецсимволы-комментарии и спецификаторы терминальных символов по соглашениям 1 и 2) *следует* считать комментариями/элементами форматирования и игнорировать.
    Пример:
    <url: <scheme=http> <domain=mikle33> <domain=narod> <domain=ru>>
    <url:
    (url, разложенный на компоненты и представленный через составной символ SINX)
    <scheme=http>
    <domain=mikle33>
    <domain=narod>
    <domain=ru>>
    оба варианта следует интерпретировать аналогично <url: <scheme=http><domain=mikle33><domain=narod><domain=ru>>

    Признаки могут комбинироваться, если это соответствует их роли в рамках конечного формата. Пример:
    <table: <.width=100%><.height=50%>
    <tr:
    <td <b>Cell11</b>> <td <i>Cell12</i>>
    >
    <tr:
    <td <u>Cell21</u>> <td Cell22>
    >
    <tr:
    <td <.colspan=2>Обратите внимание: <b>, </b>, <i>, </i>, <u> и </u> с точки зрения SINX – это не открывающие и закрывающие теги, а независимые спецсимволы.>
    >>
    Признаки терминальности и составного символа, очевидно, являются логически несовместимыми, но в рамках синтаксиса они могут присутствовать одновременно. SINX уровень 1 принципиально не даёт никаких рекомендаций насчёт такой комбинации и оставляет её использование и смысл на усмотрение конечного формата.

    Если выбранная кодировка не предусматривает символа для какого-либо признака, и соответствующее правило исключено на уровне синтаксиса, то исключается и соответствующая рекомендация из пунктов 3-5.

    2.4. И это всё?


    Да, это всё. Заметьте, не "всё, что вам надо знать для начала, но позже вы откроете для себя...", а именно всё. Данная глава является исчерпывающим описанием SINX уровней 0 и 1, как формата.

    3. Почему SINX, а не XML?


    Для начала есть смысл задать обратный вопрос – почему XML, а не SINX?
    Если вы не свободны в выборе формата в силу условий задачи, участвуете в проекте, где не всё зависит от вас, и знакомство с используемыми технологиями важно для срабатываемости участников, или вы используете сложные инструменты, форматы которых являются для вас непреодолимой данностью, или имеете ещё какие-нибудь аналогичные внешние обстоятельства – что ж, тогда, конечно, ничего не попишешь; используйте XML и примите мои соболезнования.
    Но, если вы пишете что-то лично для себя и свободны в выборе инструментов и технологий, большинство ваших аргументов в пользу XML, скорее всего, проистекают из укоренившихся стереотипов и стадного инстинкта. Это плохие вещи, нужно тренироваться ломать их в пользу здравого смысла. Вот вам несколько соображений, почему для кустарных нужд SINX лучше XML.

    +1. SINX проще. Об этом можно было бы и не упоминать лишний раз, но он действительно намного проще. Он прост почти настолько, насколько это вообще возможно (мог бы быть ещё чуть проще, но были учтены соображения эстетики и кое-какие вспомогательные моменты). Парсер нулевого уровня вы напишете с нуля примерно за час, надстройку над ним для первого уровня – максимум ещё за час. При всём при этом, SINX даёт вам точно те же возможности для выражения данных и разметки, что и XML. Вы, вероятно, обратили внимание на псевдо-HTML-пример в предыдущей главе. Он как раз иллюстрирует принцип конверсии из XML/HTML в SINX (и, при необходимости, обратно). Принцип настолько примитивен и очевиден (и не менее очевидным образом автоматизируем), что я, с вашего позволения, не буду его разжёвывать.
    Более того, предоставляя те же возможности, SINX делает это более простым и однозначным образом. Пример: в XML, чтобы преобразовать атрибут во вложенный тег или наоборот, нужно сами понимаете, сколько всего сделать (и в XML-документе, и в читающем его коде). В SINX же нет разделения на теги и атрибуты, и проблема сводится к чисто эстетическому решению, поставить или убрать признак атрибута (1 точку) перед именем спецсимвола (или вообще забить на этот вопрос).

    +2. SINX компактнее. Дело даже не в том, что служебные издержки в SINX-строке в ~2 раза меньше, чем в идентичном по структуре XML-документе. Формат в меньшей степени затрагивает сам текст. Задумывались ли вы над такой возможностью, как вывод сообщения для пользователя в stdout прямо в XML-формате? Вряд ли – здравый смысл показывает, что текст затеряется в обрамлении служебных элементов и излишеств. В случае с SINX же вполне можно сделать так, что человекочитаемость по сравнению с простым текстом пострадает ненамного. Сравните:

    <?xml version='1.0' encoding='UTF-8' ?>
    <message file="file.txt" line="14">
    Это сообщение, относящееся к строке &lt;14&gt; файла &quot;file.txt&quot;.
    </message>

    и:

    <message <.file=file.txt> <.line=14>
    <% Это сообщение, относящееся к строке <14> файла "file.txt". %>>

    +3. SINX гибче. Рассмотрим, к примеру, XML-кусок <tag attr="some-value"/> и аналогичную SINX-строку <tag <.attr some-value>>. Что можно сказать про some-value? Это, видимо, должен быть какой-то текст. А почему, собственно, только текст? Почему бы ему не быть вложенным узлом со своей собственной структурой? В SINX такая возможность заложена по дизайну: <tag <.attr <.attr-of-attr=100%><component1=xxx><component2=yyy>>> – причём данные спецсимвола, являясь полноценной SINX-строкой, всегда могут быть выделены и рассмотрены независимо, как самостоятельный документ. В XML же, даже если мы, поднатужившись, сконструируем аналог из вложенных тегов:
    <tag><attr>
    <attr-of-attr>100%</attr-of-attr>
    <component1>xxx</component1>
    <component2>yyy</component2>
    </attr></tag>
    то внутреннее содержимое <tag>, в общем случае, даже не будет валидным XML-документом, который можно рассмотреть вне контекста объемлющего документа.
    Это гораздо более внушительное преимущество, чем может показаться. Почему? Вот вам пара наглядных примеров из пары современных форматов:

    SVG:
    ...
    <path fill="none" stroke="black" d="M 227 239 L 328 90 L 346 250 L 201 124 L 410 150 L 228 238" />
    ...

    CSS:
    ...
    <style type="text/css">
    body { color: red; }
    h1 { color: white; background-color: orange !important; }
    h2 { color: white; background-color: green !important; }
    </style>
    ...

    Это хорошие иллюстрации анекдотичного положения дел в так называемых форматах, основанных на XML. По идее, основанность на XML означает, что берём первый попавшийся XML-парсер, натравливаем его на документ, и наши проблемы решены. Однако нередки случаи, когда роль собственно XML в неком формате ограничивается отметкой какого-то общего куска с данными, а сами данные следуют в совершенно ином формате, парсящемся отдельно и совсем по другим правилам. А что такого в этих данных? У них экзотическая структура, не позволяющая представить их поддеревом главного документа и распарсить на общих принципах? Случается и такое (скажем, жабаскриптовые вставки), но явно не здесь. Здесь у нас такая же кучка узлов со свойствами, как и в остальном документе. И что мешает представить тот же CSS как-нибудь вот так:
    ...
    <style ...>
    <body color="red"/>
    <h1 color="red" orange="!important/>
    <h2 color="white" green="!important/>
    </style>
    ...
    ?
    Да, так бы заняло чуть больше места, но регулярность формата дала бы преимущества при... ох, постойте, а ведь элементы CSS бывают вложенными? А ведь у них бывают поля со сложным составным форматом?? А ведь стиль должно быть можно задавать не только в спецсекции документа, но и через атрибут тега, к которому он применяется??? Ох, мама. Да, пожалуй, лучше придумать отдельный формат.
    Что называется, скупой платит дважды.

    А если бы вместо X/HTML был SINX, такой проблемы бы не стояло.

    <style ...>
    body {
    background-color: #111111;
    background-image: url("caulk_sucker.jpg");
    }
    p {
    }
    h1 {
    color: #222222;
    background-color: #333333;
    }
    </style>
    ...
    <h1 style="color: #FFFFFF; background-color: #000000;">желаете напрямую?</h1>

    ===>

    <style:
    <body:
    <.background-color=#111111>
    <.background-image: <.url=caulk_sucker.jpg>>
    >
    <h1:
    <.color=#222222>
    <.background-color=#333333>
    >
    >
    <h1 <.style: <.color=#FFFFFF> <.background-color=#000000>>можно и напрямую!>
    (Обратите внимание – результат практически тот же, но мы не вышли за рамки SINX.)

    К сожалению, XML/HTML+CSS получили распространение в той форме, в которой они есть, и лечить их генетические дефекты уже поздно. А вот вашим самопальным форматам может повезти больше – ещё есть возможность основать их на SINX и через это значительно уменьшить вероятность, что придётся придумывать языки в языке.

    +4. SINX можно употреблять даже для бинарных данных. Правило о бинарно-дословном соответствии последовательностей их представлению во входном потоке сурово и недвусмысленно, а элемент терминальной последовательности более универсален, чем XML-овское CDATA, и позволяет бинарно-дословным образом вместить абсолютно любую последовательность.
    Кроме того, SINX уровня 0 идеально подходит для inplace-распарсивания.

    Непронумерованный бонусный плюс. SINX – крайне щадящий формат в плане миграции с XML. Как отмечено выше, задача конвертации из XML в SINX и наоборот решается просто и прозрачно, можно элементарно написать универсальный конвертатор. При этом SINX использует привычные и знакомые угловые скобочки. :)
    Шутка юмором, но любопытный факт: XML/HTML без жабаскриптов, CDATA и заковыристых комментариев, как правило, является валидной SINX-строкой, в которой спецсимволы совпадают с открывающими и закрывающими тегами.

    С преимуществами всё понятно, а недостатки? Объективности ради, попробуем рассмотреть некоторые типовые возражения.

    –1. "Для XML разработано множество технологий – XSLT, XPath, и прочее, у него есть dtd/dsd/schema, а у вашего формата ничего этого нет. А если всё это придумывать, не получится ничего качественно лучшего. Так в чём же смысл?"

    Ну и часто ли вы пользуетесь схемами не то что в повседневной жизни, а даже в производстве? Зачем она вам? Проверить валидность документа? Можно подумать, ваша программа, имея распарсенный в дерево конфигурационный файл и разбирая его простым поиском по нужным ключам + проверкой значений на валидность, и так не поймёт, её ли это конфигурационный файл или нечто левое.
    Для каких-то экзотических применений схема, может, и нужна. Но у вас – не экзотический случай. Я в этом уверен на 99%. Именно такой (как минимум) процент применений XML обходятся без всякой схемы. Среднестатистическая библиотека для работы с XML даже не обучена такой премудрости. Так о чём разговор?
    За остальные множество технологий скажу ещё короче: добрая половина из них – узкоспециализированные костыли, придуманные для борьбы с корявостями XML в различных специфических применениях. Большинство этих "технологий", скорее всего, известно вам только по названию и с вашими повседневными нуждами имеет мало общего.
    А то, что вам от базового текстового формата действительно нужно, SINX даёт, и даёт качественнее, чем XML (см. список преимуществ).

    –2. "Для XML есть множество готовых библиотек, а про ваш формат знают полтора человека, и для него ничего толкового нет."

    Ну берите "готовые библиотеки" и радуйтесь рукописными итерациями по DOM-дереву через красивые, удобные интерфейсы. И созданию-редактированию вашего формата, особенно когда он будет подвергаться расширениям, тоже радуйтесь. Когда нарадуетесь, перечитайте ещё раз главу 2. SINX настолько прост, что написание для него собственного парсера займёт у вас меньше, чем освоение иных XML-библиотек. И даже этот труд окупится временем, которое вы впоследствии сэкономите на разных мелочах за счёт более простой и логичной структуры формата.
    За отправную идею о том, как может выглядит библиотека для работы с SINX, предлагается взять пример из гл. 4.

    –3. "Если уж изобретать вместо стандартного формата велосипед, лучше я изобрету свой собственный, с блэкджеком и шлюхами – он-то точно идеально подойдёт под мои требования."

    Попробуйте. Попытки думать самостоятельно, а не оглядываться на авторитеты – занятие полезное, и нередко даёт ценные плоды.
    Один форумный товарищ, сочтя SINX слишком сложным и вообще идеологически неправильным, прямо на месте изобрёл свой собственный велосипед. Изобретение долженствовало показать несовершенство смелого замысла и его неконкурентоспособность на велосипедном рынке.
    И получился у него полный аналог SINX уровня 0, отличающийся только способом записи открывающих и закрывающих фрагментов спецсимвола (в сторону большей многословности).
    Таким образом, скептически настроенный товарищ своими руками доказал если и не идеальную минималистичность нашего формата, то, как минимум, его крайнюю к этому близость.
    Поэтому, конечно, можете и попридумывать что-нибудь своё, но стоит ли, если высока вероятность получить то же самое? :)

    4. Библиотека


    По правилам хорошего тона, к описанию формата прилагается пример библиотеки (на C++) для чтения и записи с примером использования: sinx.zip (27 кб). Библиотека не отличается особой компактностью и сферичностью, поскольку при её создании не ставилось задач сделать нечто компактное и сферическое. Кроме вещей, относящихся непосредственно к формату, она содержит кое-какие удобства и излишества, а также использует некоторые вещи из STL (конкретно говоря, std::map, std::deque и std::string). С одной стороны, она предполагалась референсной имплементацией SINX-парсера и генератора, а с другой – для реального применения автором в своих прожектах и с робким прицелом на портируемость. (Тем не менее, даже при всей своей некомпактности, несферичности и излишествах, она меньше RapidXml (примерно аналогичной по функциям библиотеки для XML, самой минималистичной из существующих) на можете сами посмотреть, сколько килобукв, и при этом реализует SINX уровня 1 полностью, безо всяких ограничений. О чём это говорит?)
    Подробной документации не прилагается, ибо: а) лень :), б) всё, чего достаточно для счастья конечному пользователю, проиллюстрировано в примере и довольно очевидно в своей простоте, в) всё остальное снабжено doxygen-комментариями (правда, не по-русски, чему есть производственные причины), так что поклассовую справку при желании можно сварганить и доксигеном. Здесь же будет дано общее описание содержимого посылки, общей идеи и краткие наставления по применению.

    Посылка содержит ряд файлов, которые надлежит распаковать в одну папку:
    sinx_pltfm.h – платформо-зависимые концепты для парсера и кое-какие общие определения,
    sinx_read_l0.h, sinx_read_l1.h – реализации парсера 0-го и 1-го уровней соответственно,
    sinx_write.h – реализация генератора (использует вышеперечисленное),
    sinx.h, sinx.cpp – обёртки для вышеперечисленного в товарный вид,
    test.cpp – главная программа примера,
    test.sinx, testpr.sinx, example_gen.sinx – примеры файлов в формате SINX. Из них последний генерируется примером (в рамках демонстрации генератора), а предпоследний – прямолинейная конверсия из XML-файла (проект-заглушка от C++ Builder), главным образом для иллюстрации непронумерованного бонусного плюса из гл. 3.

    Никаких файлов проектов, makefile-ов и прочего мусора в посылку не положено. Предполагается, что программа тривиально собирается из командной строки. В C++ Builder версии 5 и выше (есть подозрение, что и ниже) это делается вот такой командой:
    bcc32 test.cpp sinx.cpp (собирается test.exe)
    В M$ Vi$ual $tudio 2005 и позднее (предполагается, что вы уже сконфигурировали $тудию для работы с командной строки) –
    cl /EHsc test.cpp sinx.cpp
    Пример компилируется и на gcc от WxDev++ (gcc test.cpp sinx.cpp), но с командной строки оно не пожелало видеть стандартной библиотеки на этапе линковки, как с этим бороться – разбираться было лень и незачем. Поэтому, если у вас gcc или какой-нибудь маргинальный компилятор (или другая операционная система, не отрицаю и такой возможности), попробуйте разобраться сами, благо принцип должен быть понятен из приведённых выше примеров.

    Принцип применения самой библиотеки здесь описывать не будем – приёмы, достаточные для типового практического случая, можно почерпнуть из текста примера (test.cpp), где всё довольно очевидно. Но кое-какие дополнительные пояснения насчёт внутреннего устройства и логики некоторых вещей дать всё же стоит.

    Итак, неcколько развёрнутых слов про каждый файл, в порядке их логической взаимосвязи.

    sinx_pltfm.h. Изначальный замысел был в том, чтобы весь парсер отвязать от какой бы то ни было платформы и параметризовать неким классом-концептом, в котором пользователь и определит требуемые платформо-специфические вещи. Один из таких классов, SINX0_Platform, определяется (подразумевалось, что в качестве примера) в sinx_pltfm.h. Основные вещи, которые в нём определены – тип SINX0_Platform::TChar (символ используемой кодировки), коды синтаксически значимых символов, функции динамической аллокации/деаллокации памяти и класс SINX0_Platform::Buffer, определяющий буфер с исходной SINX-строкой для разбора. В данной реализации он сделан через буфер в памяти, содержащий строку целиком, но ничто не мешает переписать его внутренности для работы над частично буферизируемыми данными из внешнего источника.

    sinx_l0.h (опирается на sinx_pltfm.h). К сожалению, достичь задуманного в полной мере не удалось – этот скользкий путь привёл на территорию навороченных шаблонов, на которой мнения различных компиляторов разошлись до несовместимости. Но для парсера SINX уровня 0, которому посвящён файл sinx_l0.h, цель всё-таки была достигнута. В данном файле содержатся следующие классы:
    SINX0_String<Platform> – фрагмент SINX-строки в дословно-двоичном представлении. Проще говоря, кусок буфера (Platform::Buffer), рассматриваемый как строка. Её можно сравнивать с другими строками (в том числе и с C-style строками) и брать от неё подстроку.
    SINX0_SuxxElement<Platform>, SINX0_SuxxParser<Platform> – обеспечивают последовательное извлечение из SINX-строки (представленной SINX0_String<Platform>) элементов в стиле SAX-парсера. (Название классов намекает на моё отношение к SAX-парсерам, как методологии, но их метод, при всей своей практической ущербности, удобен в качестве базиса.) Кто из них реализует парсер, а кто представляет извлекаемый элемент – полагаю, уточнять не надо. Элементы могут быть следующими:
  • последовательность данных,
  • открывающий фрагмент спецсимвола (с именем и признаками),
  • закрывающий фрагмент спецсимвола,
  • маркер конца строки.
  • SINX0_Symbol<Platform>, SINX0_SymbolIterator<Platform> – обеспечивают более прямо соответствующее уровню 0 обращение к SINX-строке – в терминах отдельных символов, терминальных и специальных. Первый SINX0_Symbol<Platform> можно получить присвоением из SINX0_String<Platform> (это будет "виртуальный" спецсимвол с пустым именем и данными, совпадающими с присваиваемой строкой) и далее извлекать из него компоненты с помощью SINX0_SymbolIterator<Platform>. В части обработки ошибок формата (см. конец гл. 2.2) парсер придерживается следующей стратегии:
  • символ '>', не имеющий соответствующего открывающего '<', игнорируется,
  • открывающие фрагменты спецсимволов, не имеющие соответствующих '>', игнорируются.
  • Все перечисленные классы суть шаблоны, параметризуемые классом, соответствующим концепту платформы. Иными словами, реализующими тот же интерфейс, что и SINX0_Platform из вышеупомянутого sinx_pltfm.h (на практике, это только он и будет). Кроме того, все они сделаны так, что не используют динамических аллокаций (кроме ситуации с присвоением SINX0_Symbol из SINX0_String – одна дополнительная аллокация) и для работы с данными полагаются на объект буфера, от которого всё и танцует. То есть, предполагается, что буфер должен оставаться в живых не менее, чем любой из SINX0_...–классов, его использующих (для этой цели в его интерфейсе предусмотрен подсчёт ссылок). Учитывайте это, если задумаете сделать свою собственную реализацию буфера.
    При желании, sinx_l0.h и содержащиеся в нём богатства можно использовать самостоятельно, их достаточно для работы с SINX уровня 0. Но интерфейс и применение у всего этого дела не самые удобные (примерно на уровне библиотек для XML), поэтому общаться с SINX0_... напрямую вы, скорее всего, не будете.

    sinx_l1.h (опирается на sinx_l0.h). Парсер SINX уровня 1. По отмеченным выше причинам получился, к сожалению, непараметризуемым (использует строго SINX0_Platform и SINX0_...–классы, параметризованные именно им), но зато у него более пристойный интерфейс. Помимо вещей, связанных с собственно SINX уровня 1, включает несколько вспомогательных излишеств – для удобства и даже для демонстрации кое-каких возможностей по использованию формата.
    Классы, которые здесь представляют основной интерес, следующие:
    SINX1_Symbol – олицетворяет SINX-спецсимвол. Позволяет извлекать из него данные в форме строки или целого числа (если они не содержат спецсимволов, не сводимых к терминальным по правилам SINX уровня 1), получать составляющие спецсимволы (индивидуально по имени или полным комплектом), получать все данные в виде неинтерпретированной SINX-строки, и т. п. Для возврата данных SINX1_Symbol использует std::string и std::deque (и, на внутреннем уровне, std::map), но сделано так, что никаких связанных с динамическими аллокациями операций не проводится до тех пор, пока вы явно не вызовете функцию запроса данных. Поэтому копировать SINX1_Symbol и возвращать из функций можете, не опасаясь исключений.
    Обработка ошибок формата следует той же стратегии, что описана выше для SINX0_Symbol.
    Поучительная возможность, которую следует упомянуть особо – извлечение спецсимвола из нижележащего поддерева по описанию пути (функция OpenPathL). Что это такое? Проще всего показать на примере. В SINX-строке:
    <a:
    <b blah>
    <c:
    <e blah-blah>
    <d <.x=1>>
    <d <.x=2>>
    <d <.x=3>>
    >>
    <x>
  • спецсимвол 'b' имеет путь <a <b>> (или, что то же самое, <a <b><.index=0> (индекс может указываться только целым числом)),
  • спецсимвол 'c' имеет путь <a <c>>,
  • первый спецсимвол 'd' имеет путь <a <c <d>>> (или, что то же самое, <a <c <d><.index=0>>>)
  • второй спецсимвол 'd' имеет путь <a <c <d><.index=1>>>,
  • третий спецсимвол 'd' имеет путь <a <c <d><.index=2>>>,
  • спецсимвол <.x=2> имеет путь <a <c <d <x>><.index=1>>>,
  • ...
    В общем, вы поняли принцип.
    SINX-строкой для поиска выступают данные SINX1_Symbol, а путь вы даёте его функции OpenPathL (в виде обычной строки), в ответ вам возвращается искомый спецсимвол. Если спецсимвол с такими "координатами" не найден, то возвращается результат, соответствующий пустому спецсимволу и имеющий специальный флажок IsEof (). Эта возможность полезна, если у вас есть некий сложный SINX-файл, а конфигурация, интересующая вашу программу, является поддеревом, затерянным где-то в общей структуре, и местоположение его корневого узла проще всего указать в качестве входных данных (например, с командной строки).
    Поучительно здесь то, что, как видите, путь до искомого символа также описывается в SINX-формате (и, как нетрудно догадаться, распарсивается этим же самым парсером). Вот такой импровизированный велосипедик, не отходя от кассы, средствами самой кассы. Сравните простоту и минимум затрат, к которой он нам достался, с XPath – аналогичной по назначению технологией для XML. Да, я знаю, что в XPath несоизмеримо больше возможностей, и синтаксис у него более удобный, и т. д., и т. п... Но – у него другой синтаксис, несовместимый с XML, и он требует отдельного парсера. Вдумайтесь в этот факт. Даже если бы "технология" имела ровно такие же примитивные возможности, как у нас, у неё всё равно был бы другой синтаксис, несовместимый с XML и требующий отдельного парсера. В нашем импровизированном "SINXPath" не потребовалось изобретать ничего нового. Мы бы могли, но зачем, если можно легко и сравнительно красиво обойтись подручными средствами?
    Что мешало пойти похожим путём и сочинителям XPath? Чисто теоретически, ничто не мешало. Чисто практически... Думаю, всё понятно.

    sinx_write.h (опирается на sinx_l1.h). Реализует запись данных в формате SINX уровня 1 (включая запись комментариев, экранирование символов через спецсимволы <#...> при выводе обычных строк, посильное соблюдение конвенций о признаках и форматирование внутри спецсимволов, которые юзер предпишет считать составными).
    Принцип использования:
  • Юзер должен определить свой класс выходного потока – наследника чисто виртуального класса SINX_WriteDocumentBase, в котором нужно доопределить пару виртуальных функций для записи байт в поток. Далее предполагается, что экземпляр этого класса воплощает открытый поток, и с помощью функций, предоставляемых этим объектом (а точнее, его ещё более ранним предком SINX_WriteNode), можно записывать в него данные.
  • Для записи простых данных (строк и спецсимволов с простым строковым содержимым) достаточно функций из класса SINX_WriteNode. Если требуется записать спецсимвол со сложной структурой, нужно: а) открыть новый спецсимвол, создав объект класса SINX_WriteSpecialOpen (при этом можно указать желаемые признаки открываемого спецсимвола и указания по его форматированию), б) записать составляющие его данные (это делается таким же образом, т. к. SINX_WriteSpecialOpen тоже является наследником SINX_WriteNode), в) закрыть спецсимвол (это происходит автоматически при уничтожении SINX_WriteSpecialOpen).

  • sinx.h, sinx.cpp (опирается на sinx_l1.h и sinx_write.h) – обёртка классов и констант из sinx_l1.h и sinx_write.h в объединённый неймспейс SINX, определение кое-каких вспомогательных функций и реализация классов-обёрток для наиболее естественного случая – чтения и записи в/из файла (классы SINX_ReadFileOpen/SINX::ReadFileOpen и SINX_WriteFileOpen/SINX::WriteFileOpen).
    Принцип использования вспомогательных функций достаточно очевиден по их именам и параметрам. Не самая очевидная идея только у функций SINX::ReadSpecialEnumL<Enum> и SINX::WriteSpecialEnumL<Enum>, предназначенных для чтения/записи спецсимвола, хранящего значение типа enum (или иного типа с небольшим заранее известным набором допустимых значений). Это шаблоны, параметром которых является, собственно, тот enum-тип, который вы хотите прочитать/записать. Этим функциям нужно предоставить специальный объект класса SINX::EnumHelper<Enum> (тоже шаблон, параметром которого должен быть тот же enum-тип), описывающий соответствие допустимых значений требуемого типа и их строковых представлений. Как конструируется такой объект, можете посмотреть в примере.

    test.cpp – собственно пример. Представляет собой программу, работающую с командной строки. Если запустить её без параметров, она генерирует файл example_gen.sinx (он также включён в посылку, но можно со спокойной совестью его стереть, всё равно будет создан заново), а потом читает из него некоторые данные. Файл сравнительно большой и сложный по структуре (пример из простого и примитивного файла был бы менее интересен, не правда ли?), поэтому пусть вас не смущает объём кода, отвечающего за пример записи – он потому и большой, что много пишет.
    Ещё можно запустить программу с одним параметром – именем SINX-файла (см. другие файлы с расширением .sinx из посылки), в этом случае она выведет поэлементный дамп указанного файла.

    Вот, в сущности, и всё. Разбирайтесь и пользуйтесь.

    5. Соглашение об использовании


    В наше суровое копирастическое время об этом тоже нужно сказать пару слов. Пара слов:

    ===
    Соглашение об использовании.

    Код из представленного выше архива sinx.zip разрешается свободно и безвозмездно использовать и модифицировать любым способом и в любых целях, за исключением следующего ограничения: запрещено добавлять в него любые отметки о копирайте и лицензии. Код предоставляется, как есть, без каких-либо гарантий.

    Описанием формата SINX является глава 2 данного документа, за исключением подраздела 2.4. Описание разрешается свободно и безвозмездно использовать любым образом, при условии сохранности его текста в неизменном виде.

    SINX, как формат, допускается свободно и безвозмездно использовать в любых целях, при соблюдении следующих требований:
    1. Сам по себе формат SINX является общественным достоянием и принципиально не патентуется.
    2. Патентование новой технологии или формата данных, в которых в каком-либо качестве используется формат SINX, разрешается только в том случае, если патент касается только именно этой технологии или формата, и под его действие не попадает ни один объект, кроме перечисленных явным и конкретным образом в тексте патента,
    3. Допускается введение формата SINX в уже существующую и запатентованную технологию или формат (например, в качестве альтернативного базового формата), но только в качестве элемента, не покрытого соответствующим патентом. Если введение его в таком качестве невозможно без изменения текста патента, разрешается оформить на модифицированный формат или технологию новый патент, к которому применяются ограничения п. 2.

    Используя формат SINX и прочие материалы с данной страницы, вы тем самым соглашаетесь на требования данного соглашения об использовании.
    ===

    Пара слов не претендует на юридическую строгость, но обрисовывает основные направления. Данный раздел в будущем может уточняться и совершенствоваться, если того потребует ситуация.

    Может возникнуть вопрос – а зачем на странице самопального и малоизвестного формата этот раздел, отдающий в свете самопальности и малоизвестности чем-то цирковым?
    Как самопальный и малоизвестный формат, SINX имеет ещё одно неочевидное преимущество – лицензионную чистоту. Можно употреблять его для любых целей, не опасаясь ситуаций типа таких. Необходимость в данном разделе, конечно, сомнительна – здравый смысл подсказывает, что вряд ли в ближайшее время SINX обретёт широкую известность, повсеместно вытеснит б-гомерзкий XML, и кому-то до него вообще будет дело. Но, как человек параноидальный, я не могу не рассмотреть все варианты. И лучше написать несколько смешных буковок сейчас, чем потом внезапно обнаружить, что уже поздно.

    6. Пример софта


    В доказательство того, что я действительно использовал формат SINX для собственных нужд, вот пример программы – игра Operation I.T.C.H. (5 мб, .zip) (работает на вантузе, теоретически – от 2000, достоверно – на XP, 7 и, по свидетельствам очевидцев, в Wine). Поиск мест, где он там используется, предоставляю вашему любопытству.

    7. Дополнительные материалы (обновления от 2011 и далее)


    В процессе использования формата SINX в моей деятельности к нему появились (и продолжают появляться) разные полезные разности. Я буду выкладывать их сюда.
  • sinxxml.zip (187 кб) – небольшой консольный конвертор SINX<->XML. Сурцы прилагаются, инструкция печатается при запуске. Для борьбы с XML использован RapidXML, поэтому есть несколько дефектов. При конверсии из XML обычно теряется форматирование из табов и отступов, а обратное даёт не совсем корректный XML: нужно дописать вручную <?xml version="1.0" encoding="utf-8"?> (а я говорил вам, что библиотеки для работы с XML неполноценны!), и будет нехорошо, если исходный SINX состоит из нескольких элементов на корневом уровне – правильный XML позволяет иметь там только один элемент (я же говорил, что XML – неполноценный формат!:).
  • sinx_cs.zip (7 кб) – минималистическая библиотека для SINX в C# 3.0+, можно использовать на Window$ Phone (7) SDK (собственно, для этого и создавалась). Используются документационные комментарии C# (не по-русски), так что разберётесь. Класс Test в конце файла – как бы пример, удалите его перед тем, как использовать для своих нужд. Если у вас C# 4+, можно найти фрагмент "public SinxSpecial this[string pName,int i]" и заменить в нём на "int i=0", тогда вместо xxx["special_name",0] можно будет писать xxx["special_name"].
  • sinx_php.zip (4 kb) – библиотека для использования SINX в PHP 4/5. Примеров нет, но всё документировано (имеется даже краткое описание формата) (правда, опять-таки не по-русски) – не потеряетесь.


  • (C) 2011 Mikle[Subterranean Devil]
    Использование текста с данной страницы допускается только со ссылкой на источник
    Hosted by uCoz