Спецификация rtf на русском


Спецификация формата RTF

Спецификация формата RTF

Данный формат был определен фирмой Microsoft как стандартный формат для обмена текстовыми документами. Следовательно, по назначению этот формат подобен SYLK-формату для электронных таблиц. RTF поддерживается многими продуктами фирмы Microsoft. Так, например, начиная с версии 2.0, он введен в Windows в качестве Clipboard-формата, благодаря чему возможен обмен данными между различными прикладными программами Windows. Кроме того, RT-формат поддерживается программами WORD для Macintosh, начиная с версии 3.X, и WORD для PC, начиная с версии 4.X. В RTF для обмена документами используются только представимые символами коды из ASCII-, MAC- и PC-символьного набора. Кроме текста, файл в RT-формате в читаемой форме содержит команды управления.Документ состоит преимущественно из команд управления настройки программы чтения файлов в RTF-формате. Эти команды можно разделить на управляющие слова (control words)и управляющие символы(control symbols). Управляющее слово представляет собой последовательность символов с разделителем(delimiter)в конце:

lettersequence

Перед управляющим словом вводится обратная косая черта "" (backslash). В качестве разделяющих могут использоваться следующие символы:

  • Пробел (space), причем этот символ относится к управляющему слову;

  • Цифра или знак "-". После этих символов должен следовать параметр с разделителем. В качестве разделителя может быть использован пробел или другие символы, кроме цифр и букв;

  • Все символы, отличные от цифр и букв. Эти символы не относятся к управляющему слову.

В RT-формате для задания управляющей последовательности используются буквы от "А" до "Z" и от "а" до "z", а также цифры от "0" до "9". Национальные символы к управляющей информации не относятся. В качестве, управляющих символов используются отдельные буквы. Перед каждым управляющим символом вводится обратная косая черта "":

control symbol

В настоящее время определены только некоторые из этих символов. Поэтому при чтении неизвестные символы могут быть пропущены. В RT-формате существует возможность объединять отдельные последовательности в группы при помощи скобок:

{ начало группы} конец группы

Такие группы создаются, например, при описании сносок, колонтитулов и т.п. Если необходимо разместить символы "", "{" или "}" внутри обычного текста, то перед ними надлежит поставить обратную косую черту:

{}

Это позволяет программе, читающей RTF-последовательность, распознать, что символ не следует интерпретировать как управляющий. В RT-формате используются также некоторые символьные коды для управления печатью

Код

Значение

09Н

Табулятор

0АН

Символ CR

0СН

Символ LF

Символы CR и LF, расположенные внутри текста, будут пропущены. Microsoft использует эти символы для большей наглядности при представлении RTF-файла. Внутри управляющих слов символы CR и LF могут иметь особое значение, подробнее об этом будет сказано при описании команд.

Специальные управляющие слова (special control words)В RTF имеются управляющие слова специального назначения. Рассмотрим кратко эти слова и их назначение.

chpgnУправляющее слово change page number выводит текущий номер страницы.

chftnУправляющее слово change footnote активизирует автоматическую нумерацию сносок.

chdateС помощью change date можно вывести текущую дату.

chtimeС помощью change time можно вывести текущее время.

chatnСсылка на примечание (текст следует в группе).

chftnsepСвидетельствует об изменении линии, отделяющей сноски от текста.

/С помощью данной последовательности вводится текст формулы.

:Обозначает подпункт индекса.

*Текст может быть пропущен при чтении RTF-формата.

~Задает жесткий (неразрываемый) пробел между двумя словами, т.е. в этой позиции предложение не может быть разделено при переносе на следующую строку.

-Символ обозначает мягкий перенос (nonrequired hyphen).

_Символ обозначает неразрываемый перенос (nonbreaking hyphen), на месте которого слово не может быть разделено.

''hhПоследовательность позволяет прямой ввод в тексте шестнадцатеричных чисел. Они задаются вместо символов hh.

pageДанная последовательность задает переход на новую страницу.

lineЭта последовательность вызывает переход на новую строку в тексте.

раrС помощью данной последовательности в тексте отмечается конец абзаца. Последовательность раr может заменяться последовательностью10или13. При этом 10 соответствует ASCII-символу с кодом 10 (carriage return). Непосредственно ввести ASCII-код 10 (CR) нельзя, т.к. он игнорируется программой чтения.

sectЭта последовательность обозначает конец текстового фрагмента или текстового абзаца.

tabДанная последовательность заменяет табулятор. Можно также непосредственно задавать ASCII-код 09Н.

сеllКонец таблицы (столбец).

rowКонец таблицы (строка).

Операторы настройки (destination control words)С помощью описанных ниже управляющих слов можно произвести основную настройку программы чтения RTF. Они могут встречаться только в начале документа или в начале группы. Все операторы вместе с параметрами должны быть заключены в скобки, например:

{rtf0pc.......}

Ниже описан формат некоторых операторов.

rtf <параметр>Задает метку начала файла. В качестве параметра программа, при помощи которой создается файл, может указывать номер версии. Например:

{rtf0.......}

Метка должна стоять в начале файла. После этого оператора могут следовать другие операторы или закрывающая скобка. Установка вида кодировки для сохраняемого текста осуществляется с помощью следующих операторов:

ansi:

текст хранится в стандартном ASCII-формате. Этот формат используется, например, в Windows.

mac:

текст хранится в кодировке Macintosh.

рс:

для вывода текста используется кодировка символов IBM-PC.

рса:

IBM-PC Code Page 850 (модель PS2).

Для передачи текстов между различными системами должна использоваться кодировка ansi.

colortblWindows и другие программы пользуются палитрами для определения используемых цветов. Чаще всего палитра состоит из 16 различных цветов, получаемых путем комбинации основных цветов - красного, зеленого и синего. Команда colortbl позволяет изменить отдельные определения в палитре. Для каждого цвета в таблице указывается величина красной, зеленой и синей составляющей. Каждый цвет описывается тремя параметрами:

red000 green000 blue000

Вместо 000указывается величина доли цвета в диапазоне от 0 до 255. Пример: в таблице, состоящей из 16 цветов, должны быть заново определены цвета 0-й и 2-й. Для переопределения цветов может быть задана следующая последовательность:

{ colortbl redl28green64bluel28;;red0green64bluel2 8; }

Определение цвета завершается точкой с запятой. Поскольку 1-й цвет остается без изменений, в последовательности два символа ";" следуют один за другим. Последовательность завершается закрывающей скобкой. Операторcfnопределяет цвет фона (при стандартной настройке n=0), а операторcbn- цвет символа (при стандартной настройке n=0).

fonttblДанный оператор используется для построения таблицы шрифтов и соотносит имя шрифта (группы шрифтов) с номером шрифта. При определении шрифта можно использовать следующие операторы:

fnil:

имя группы шрифтов неизвестно. При выводе должен использоваться стандартный шрифт.

froman:

должны использоваться шрифты группы Roman (например, Times Roman).

fswiss:

этот оператор предписывает использование шрифтов из группы Swiss (Helvetica, Swiss и т.д.)

fmodern:

могут использоваться шрифты Pica, Elite и Courier.

fscript:

используются курсивные шрифты группы Script.

fdecor:

при указании этого оператора шрифты должны выбираться из группы Decor (Old English и т.д.).

ftech:

выбор группы шрифтов с техническими и математическими символами (SYMBOL и т.д.).

Команда для создания группы шрифтов может состоять из таких операторов:

{fonttblf0fnil default;} {flfroman roman h;} {f2fswiss helvetica;}

После ключевого слова fonttblследует первый номер шрифтаf0. Далее идет определение группы шрифтов. Здесь после номера 0 указаноfnil, т.е. имя группы неизвестно. Следующий параметр обозначает имя выбираемого шрифта (например,roman h). Указаниеdefaultговорит считывающей программе о том, что следует использовать стандартный шрифт. После имени шрифта стоит точка с запятой. В приведенном примере определены только шрифты с номерами 1 и 2. Вся последовательность может быть объединена фигурными скобками в группу. Таблица шрифтов должна быть заполнена значениями до того, как встретится операторstylesheetили текст. Стандартный шрифт вводится операторомdeffn.

stylesheetЭтот оператор определяет шрифт абзаца, т.е. размер, начертание и имя гарнитуры, а также способ выравнивания текста абзаца. При этом используются два ключевых параметра:

sbasedon000вместо символов 000 указывается номер вида шрифта, который используется в качестве текущего.

snext000назначает номер следующего вида шрифта (style), который - станет текущим. Оператор может иметь, например, следующий вид:

{stylesheets0f3fs20qj Normal;} {slf3fs30bqc Heading Level 3;}

Шрифты нумеруются числами от 0 до n (s0...). В первой строке стилю абзаца 0 (s0) предписывается имя Normal. Вывод текста выполняется шрифтом 3 (f3), размером 10 пунктов (fs20). Параметр qj говорит о том, что надпись должна выравниваться по формату. Вторая строка определяет стиль шрифта 1, который получает имя Heading Level 3. Шрифт имеет размер 15 пунктов, жирное начертание (b = bold) и при выводе надпись центрируется (qc).

pictЭтот оператор используется при описании рисунка в формате битовой карты (bitmap). Следующие параметры содержат описание рисунка в виде шестнадцатеричных значений. Параметры могут быть выборочно использованы для определения геометрии рисунка или его формата:

pich000:

оператор указывает высоту рисунка в пикселях. Вместо трех нулей подставляется числовое значение. Если оператор отсутствует, высота рисунка определяется из текущих графических данных. С помощью параметра можно задать для рисунка определенную высоту.

piw000:

оператор задает ширину рисунка в пикселях. Справедливо все, сказанное о предыдущем операторе.

picscaled:

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

wmetafilen:

параметр указывает, что данные хранятся в формате Windows-метафайла. Параметр n определяет тип метафайла (1 = ММ-текст).

macpict:

параметр указывает, что данные хранятся в Macintosh-формате Quick-Draw.

bin000:

параметр определяет количество байтов. Вместо трех нулей записывается шестнадцатеричное число.

wbitmapn:

параметр определяет формат bitmap-рисунка. Параметр n задает тип (0 соответствует логической битовой карте).

brdrs:

определяет простую рамку для рисунка

brdrdb:

определяет двойную рамку для рисунка.

brdrth:

определяет жирную линию для рамки рисунка.

brdrsh:

определяет затененную рамку для рисунка

brdrdot:

определяет для рисунка пунктирную линию.

brdrhair:

определяет тонкую линию для рамки рисунка.

picwGoaln:

задает желаемую ширину рисунка в twips

pichGoaln:

задает желаемую высоту рисунка в twips.

picscalexn:

задает горизонтальное масштабирование (n может принимать значения от 1 до 100, по умолчанию - 10).

picscaleyn:

задает вертикальное масштабирование (n может принимать значения от 1 до 100, по умолчанию - 10).

piccroptn:

описывает верхнее поле рисунка в twips. При положительных значениях параметра n верхняя часть рисунка обрезается. Отрицательные значения n дают возможность построить вокруг рисунка рамку. Стандартное значение n равно 0.

рiccrорbn:

описывает нижнее поле рисунка в twips. При положительных значениях параметра n нижняя часть рисунка обрезается. Отрицательные значения n дают возможность построить вокруг рисунка рамку. Стандартное значение n равно 0.

рiссrорrn:

описывает правое поле рисунка в twips. При положительных значениях параметра n рисунок обрезается справа. Отрицательные значения n дают возможность построить вокруг рисунка рамку. Стандартное значение n равно 0.

piccropln:

описывает левое поле рисунка в twips. При положительных значениях параметра n рисунок обрезается слева. Отрицательные значения n дают возможность построить вокруг рисунка рамку. Стандартное значение n равно 0.

wbmbitspixeln:

определяет количество битов, приходящихся на пиксел, для bitmap-рисунка (стандартное значение равно 1).

wbmplanesn:

определяет количество битовых плоскостей (стандартное значение равно 1).

wbmwidtbbytesn:

определяет длину битовой карты в байтах.

footnoteОператор должен следовать непосредственно после отметки сноски и относиться к тексту.

headerОператор определяет верхний колонтитул текущего фрагмента текста и поэтому должен указываться в начале текста.

headerlОператор определяет верхний колонтитул четной страницы (left hand header), на которой колонтитул выводится с выравниванием влево.

headerrОператор устанавливает верхний колонтитул нечетной страницы, на которой колонтитул выводится с выравниванием вправо (right hand header).

headerfОператор устанавливает верхний колонтитул первой страницы (first page header).

footerОператор устанавливает нижний колонтитул текущего фрагмента и должен указываться перед началом текста.

footerlОператор устанавливает нижний колонтитул четной страницы (left hand footer), на которой колонтитул выводится с выравниванием влево.

footerrОператор устанавливает нижний колонтитул нечетной страницы, на которой он выводится с левосторонним выравниванием (right hand footer).

footerfОператор устанавливает нижний колонтитул первой страницы (first page footer).

ftnsepОператор определяет символ-разделитель для сносок.

ftnsepcОператор определяет разделитель для сноски, которая продолжается на следующей странице (continued footnote).

ftncnЭтот оператор применяется для обозначения продолжения текста сноски.

infoС помощью данного ключевого слова в начале документа открывается информационный блок. Он может содержать информацию о заголовке документа, дате его составления и т.д. Внутри информационного блока, который начинается оператором info, могут встречаться следующие операторы:

title subject operator author keywords doccomm version nextfileПеречисленные команды позволяют передавать вспомогательную информацию о документе, например, имя автора, версию текста, заголовок и т.д. Программа чтения RTF-данных не обязана обрабатывать команды информационного блока.

vern000Вместо 000 в операторе записывается номер версии программы, в которой составлен документ.

creatimС помощью данного ключевого слова определяется дата и время создания документа. Эти данные кодируются с помощью таких операторов:

уr000год создания документа

то000месяц создания документа

dy000день создания документа

hr000время создания документа в часах

min000время создания документа в минутах

sec000время создания документа в секундах

revtimОпределяет время и дату последней корректировки документа. Оба параметра задаются так, как указано в описании оператора creatim.

printtimОпределяет время и дату последней распечатки документа. Оба параметра задаются так, как указано в описании оператора creatim.

buptimОпределяет время и дату последнего сохранения документа (backup). Оба параметра задаются так, как указано в описании оператора creatim.

edmins000Хранит длительность (в минутах) последнего сеанса редактирования.

nofpages000 nofwords000 nofchars000 id000Вышеуказанные операторы содержат уточняющую информацию о документе (количество страниц, количество слов и количество символов), а также внутренний идентификационный номер.

commentВ заголовке может встретиться текст, помеченный ключевым словом comment. В этом случае речь идет о комментарии в тексте, который пропускается программой чтения данных в RTF-формате.

fieldИмеется группа операторов, при помощи которых описываются поля, вставляемые в WORD. Группа начинается ключевым словом field, за которым могут следовать такие операторы:

flddirtyполе было изменено во время последней актуализации

fldeditтекст был отредактирован во время последней актуализации

fldlockполе закрыто для доступа и не может быть актуализировано

fldprivрезультат не сообщается (например, рисунок)

xeЭта группа операторов начинается последовательностью символов xe и может содержать следующие ключевые слова:

bхедля номеров страниц задается жирное начертание (bold).

ixeдля номеров страниц задается курсивное начертание (italic).

txe textвместо номера страницы используется текст.

rхе bookmarkгенерация номеров страниц для области, содержащей закладку (bookmark).

tcГруппа содержит элементы данных для таблиц и может состоять из следующих ключевых слов:

tcfnпередается тип таблицы (n может иметь значения от А до Z, значение по умолчанию - С).

tclnномер уровня (стандартное значение n = 1). В группу операторов, определяющих закладки, входят только два оператора:

*bkmkstartначало области

*bkmkendконец области

Операторы форматирования (document formatting)В следующую группу входят команды для форматирования текста. Эти команды могут быть разделены на подгруппы:

  • команды, действие которых распространяется на весь текст,

  • команды, изменяющие формат только текущего абзаца,

  • команды, которые относятся к текущему выводу текста.

В этом разделе описываются операторы форматирования всего документа.

paperw000Команда задает ширину листа в twips (1 twip равен 1/20 пункта или 1/1440 дюйма). Значение ширины указывается вместо 000. Если команда отсутствует, то ширина листа устанавливается равной 12240 twips.

рареrh000Команда задает высоту листа в twips. Значение высоты указывается вместо 000. Если команда отсутствует, то высота листа устанавливается разной 15840 twips.

margl000С помощью этой команды можно установить ширину левого поля при печати в twips. Стандартная ширина поля равна 1800 twips.

margr000С помощью этой команды можно установить ширину правого поля при печати в twips. Стандартная ширина поля равна 1800 twips.

margt000С помощью этой команды можно установить ширину верхнего поля (margin top) при печати в twips. Стандартная ширина поля равна 1440 twips.

margb000С помощью этой команды можно установить ширину нижнего поля (margin bottom) при печати в twips. Стандартная ширина поля равна 1440 twips.

facingpОператор facing page определяет внешний вид страницы. Он устанавливает например, печатается колонтитул на четных или на нечетных страницах. Если за оператором следует параметр 0, то вывод подавляется.

gutter000С помощью этого оператора можно установить ширину поля подшивки (gutter внутри facing page).

deftab000Команда определяет величину табулятора. Стандартное значение составляет 72 twips.

widowctrlОператор включает wido-контроль. Если за оператором следует параметр 0, то контроль снова отключается.

endnotesЕсли в документе указан этот параметр, то тексты сносок размещаются в конце фрагмента.

ftobjПо умолчанию тексты сносок выводятся в конце страницы (footnotes bottom justified). Данный оператор позволяет переключиться с установки, заданной оператором endnotes, на стандартную установку.

ftntjТексты сносок выводятся в тексте (footnotes top justified).

ftnstart000Вместо 000 команда содержит начальный номер первой сноски. Стандартное значение номера равно 1.

ftnrestartПри указании этого оператора нумерация сносок на каждой странице начинается с 1. Параметр 0 отключает эту установку.

pgnstart000Вместо 000 команда содержит номер начальной страницы. Стандартное значение номера равно 1.

linestart000Значение, указанное вместо 000, задает номер начальной строки. Стандартное значение номера равно 1.

landscapeКоманда позволяет задать альбомную ориентацию (landscape). При указании параметра 0 восстанавливается книжная ориентация.

byphhotzОпределяет область, которая обозначается как - Hyphenation hot zone.

ftnsepОпределяет разделитель, который отделяет сноски от текста.

ftnsepcОпределяет разделитель, который отделяет сноски, продолжающиеся на следующую страницу, от текста.

ftncnОтметка для следующей сноски.

enddocСноска в конце документа.

*nextfileПередает (в скобках {}) имя файла вывода или индексного файла.

*templateПосле оператора в скобках {} указано имя файла шаблона (template), если оно отличается от принятого по умолчанию.

makebackАвтоматическое создание Backup-файла, если документ защищен.

defformatСообщает программе чтения RTF-данных о том, что документ должен быть защищен.

revisonВключает отметку об изменениях.

margmirrorУказывает на необходимость зеркально отобразить описания для левого и правого полей.

rеvрrорnЗначение параметра n задает начертание и способ выделения символов при создании редакторских примечаний. Значение n, равное 0, соответствует нормальному начертанию, 1 - жирному, 2 - курсиву, 3 - подчеркиванию (стандартная настройка), 4 - двойному подчеркиванию.

rеvbаrnВ зависимости от значения параметра n, задается способ выделения вертикальными линиями текста редакторских примечаний: 0 - не отмечается, 1 - отмечается левый край текста, 2 - отмечается правый край текста, 3 - отметка располагается за пределами текста (стандартная настройка) по краю страницы.

Форматирование секции (section formatting)Вторая группа операторов управляет форматом секции (section) и состоит из следующих команд.

sectdОператор устанавливает стандартную настройку параметров секции.

sbknoneОператор подавляет переход на новую страницу перед началом секции (section break continuous).

sbkcolПри указании этой команды в начале секции осуществляется переход на новую колонку (section break new column).

sbkpageПри указании этой команды (section break new page) в начале секции происходит переход к новой странице.

sbkevenПри указании этой команды в начале секции выполняется переход к новой странице, если номер страницы четный (section break even).

sbkoddПри указании этой команды в начале секции выполняется переход к новой странице, если номер страницы нечетный (section break odd).

pgostartsnНумерация страниц начинается с номера n.

pgnrestartКоманда устанавливает временную нумерацию страниц, начиная со значения 1. Параметр 0 восстанавливает прежний порядок нумерации.

pgndecНомера страниц выводятся в десятичном формате.

pgnucrmНомера страниц выводятся большими римскими цифрами (upper case roman).

pgnlcrmНомера страниц выводятся маленькими римскими цифрами (lower case roman).

pgncontСквозная нумерация страниц (стандартная настройка).

pgnucltrНомера страниц выводятся прописными символами (upper case letter).

pgnlcltrНомера страниц выводятся строчными символами (lower case letter).

pgnx000С помощью этой команды задается X-координата номера страницы при автоматической нумерации. Значение указывается относительно верхнего левого угла страницы и по умолчанию устанавливается равным 720 twips.

pgny000С помощью этой команды задается Y-координата номера страницы при автоматической нумерации. Значение указывается относительно верхнего левого угла страницы и по умолчанию устанавливается равным 720 twips.

linemod000Оператор устанавливает величину интервала при нумерации строк.

linex000Оператор устанавливает расстояние между строками. По умолчанию оно равно 360 twips.

linestartnНумерация строк начинается со значения n.

linerestartВозвращает номер строки к значению 1. Команда устанавливает, что нумерация строк начинается с 1.

linepageНа каждой странице нумерация строк начинается со значения 1.

linecontНумерация строк продолжается с предыдущей секции (предыдущей главы).

headery000Команда задает Y-координату верхнего колонтитула. Значение указывается относительно верхнего края страницы и по умолчанию принимается равным 720 twips.

footery000Команда задает Y-координату нижнего колонтитула. Значение указывается относительно нижнего края страницы и по умолчанию принимается равным 720 twips.

vertaltТекст по вертикали выравнивается к верхнему краю страницы. Текст располагается в верхней части страницы (vertically align at top of page).

vertalcТекст размещается посредине страницы. Вертикальное выравнивание текста выполняется по центру страницы (vertical align centered).

vertaljТекст по вертикали размещается так, чтобы заполнить всю страницу (vertical align justified).

vertalbВертикальное выравнивание текста выполняется по нижнему краю страницы (vertical align bottom).

cols000С помощью этой команды можно задать количество столбцов в строке. Стандартное значение равно 1.

colsx000С помощью этой команды устанавливается расстояние между двумя столбцами в twips. Стандартное значение равно 720 twips.

endnhereПри указании этого оператора послетекстовые сноски выводятся в конце секции. Такой вывод можно подавить путем задания параметра 0.

titlepgОператор задает вывод титульной страницы. Параметр 0 подавляет вывод титульной страницы.

Форматирование абзаца (paragraph formatting)Следующие команды управляют форматированием абзаца (paragraph).

pardОператор устанавливает стандартную настройку для абзаца.

s000Команда определяет шрифт для данного абзаца. С помощью подставляемого вместо 000 значения осуществляется выбор в таблице шрифтов.

qlПри задании команды quad left текст выравнивается по левому краю страницы.

qrПри задании команды quad right текст выравнивается по правому краю страницы.

qcПри задании команды quad centered текст размещается по центру страницы.

qjПри задании команды quad justified текст выравнивается по формату страницы.

fi000Оператор определяет величину отступа первой строки абзаца (first line indent). Стандартное значение равно 0.

li000Оператор определяет величину втяжки абзаца слева (left indent). Стандартное значение равно 0.

ri000Оператор определяет величину втяжки абзаца справа (right indent). Стандартное значение равно 0.

sb000Оператор задает количество пустых строк, вставляемых перед абзацем (spaces before). Стандартное значение равно 0.

sa000Оператор задает количество пустых строк, вставляемых после абзаца (spaces after). Стандартное значение равно 0.

sl000Команда устанавливает расстояние между строками в пунктах. Стандартное значение равно одной строке (12 пунктам). Команда sl000 включает auto line mode.

intblАбзац является частью некоторой таблицы.

keepПри указании этой команды фиксируется принадлежность текста к текущему абзацу. Команда отключается указанием параметра 0.

kеерnПри указании этой команды текст ставится в соответствие следующему (next) абзацу. Команда отключается указанием параметра 0.

studfiles.net

Полезности для вебмастеров и не только — xBB.uz

31.01.2015: Пессимизация. Что это такое и как избежать?

28.01.2015: 5 инструментов продвижения, которые больше не работают

26.01.2015: Простой способ прогнозировать посещаемость сайта

23.01.2015: Что такое верстка сайта и ее виды

21.01.2015: Объем контента сайта и его влияние на позиции в поисковой выдаче

Для вебмастеров

Пессимизация. Что это такое и как избежать? 31.01.2015 Одним из популярных способов продвижения является оптимизация текстового контента под поисковые системы. Это объясняется достаточно высокой эффективностью и относительной простотой. Но часто случается, что веб-мастера чрезмерно увлекаются оптимизацией текстов. Как результат, можно наблюдать переспам ключевых слов или другие злоупотребления. За такие проступки поисковые системы предусматривают наказание, именно оно имеет название пессимизация. 5 инструментов продвижения, которые больше не работают 28.01.2015 Поисковая оптимизация динамично развивается и при ее проведении нужно быть очень аккуратным. Те инструменты, которые недавно работали и давали результаты, могут оказаться бесполезными и вредными. Бывает и наоборот, когда методы, за которые можно было получить наказание от поисковых систем, начинают эффективно работать. Соответственно, оптимизатор должен всегда находиться в курсе тенденций и понимать, какие способы продвижения можно использовать. Простой способ прогнозировать посещаемость сайта 26.01.2015 Узнать будущую посещаемость сайта легко. Но зачем это делать? Если вы собираетесь использовать сайт как рекламную площадку, то еще до того, как приступать к его созданию, вам необходимо понять, сколько людей будут заходить на сайт в будущем. Вы оцениваете видимость сайта и потенциальный трафик по каждому из интересующих вас запросов, и на основании полученной информации создаете семантическое ядро. Это научный подход, который приносит результаты.

Для программистов

Программируем на R: как перестать бояться и начать считать 28.11.2014 Возможно, вас заинтересовала проблема глобального потепления, и нужно сравнить погодные показатели с архивными данными времен вашего детства. Калькулятором тут не обойтись. Да и такие программы для обработки электронных таблиц, как Microsoft Excel или Open Calc, пригодны только для простых вычислений. Придется изучать специализированный статистический софт. В этой статье мы расскажем об одном из популярнейших решений — языке программирования R. Smart Install Maker. Создаем установщик 23.11.2014 Появляется все больше инди-разработчиков, которые создают собственное программное обеспечение для компьютеров. Однако, чтобы продукт выглядел качественным, необходимо продумать все до мелочей, в том числе и систему установки программы. Тратить время на написание собственных инсталляторов никто не хочет, поэтому на рынке появляется все больше специализированных утилит, которые все сделают за вас. Они дают целевому пользователю то, что ему необходимо. Функции в языке программирования C++ 18.11.2014 Функцией называют обособленный модуль программы, внутри которого производятся некоторые вычисления и преобразования. Помимо непосредственных вычислений внутри данного модуля могут создаваться и удаляться переменные. Теперь расскажем о том, из каких основных частей состоит функция в C++. Самая первая часть — это тип возвращаемого значения. Он показывает, что будет передавать функция в основную программу после своих внутренних преобразований...

Для других IT-специалистов

Роль дизайна в разработке пользовательских интерфейсов 23.11.2014 Разработка программного обеспечения — сложный, трудоемкий процесс, требующий привлечения экспертов разного профиля. Команда опытных программистов способна создать систему, удовлетворяющую любым техническим заданиям заказчика. Однако зачастую вне зоны внимания остается существенный вопрос: а насколько привлекательна разработанная система для пользователя? К сожалению, на сегодняшний день разработчики не всегда готовы дать внятный ответ на этот вопрос. Аренда программного обеспечения 13.11.2014 В последнее время на рынке IT-услуг все большую популярность набирает услуга аренды серверных мощностей с размещенным на них программным обеспечением. Суть услуги состоит в том, что заказчику предоставляется доступ к необходимому программному обеспечению по модели «бизнес-приложения» в аренду. Базы пользователей располагаются на серверах в специально оборудованном дата-центре. Пользователи работают в программе через удаленный рабочий стол. Машина трехмерного поиска 09.11.2014 Поисковые машины, без которых немыслим современный интернет, еще довольно ограничены. Можно искать слова, изображения, а в последние годы и мелодии (по фрагменту, проигранному перед микрофоном). Но как найти, например, аромат яблока? Технологии цифровой обработки запахов пока не очень развиты. Однако есть прогресс в другом направлении — стал возможен поиск 3D-объектов. И судя по растущему количеству 3D-принтеров, это будет востребованный сервис.

Для других пользователей ПК и Интернет

YouTube и раритетные видеозаписи. Часть 2 19.01.2015 У скачанного файла *.MP4 напрочь отсутствует звук. Это просто кусок видеопотока, совершенно не проиндексированный, с некорректным заголовком. В Ubuntu воспроизвести его может лишь Gnome MPlayer, да и то без перемотки, без задействования пауз, строго подряд и непрерывно. Из всех бесплатных редакторов, доступных для Ubuntu Linux, переварить такое видео согласился лишь OpenShot. Импортировал и разместил на TimeLine (в области монтажа) без проблем. YouTube и раритетные видеозаписи 17.01.2015 В давние времена много чего записывалось на древние видеокассеты (VHS), большие плоские коробки с рулоном плёнки внутри. Затем контент оцифровывался и попадал на сервис YouTube, ставший для меломанов одним из основных источников добычи старых видеоклипов и концертов. Но пришла беда. Теперь почти все средства скачивания предлагают для загрузки лишь «360p». Этого разрешения хватит для просмотра разве что на маленьком экране телефона в четыре дюйма. Биржи контента. Ситуация к началу 2015 г. Обзор и тенденции. Часть 2 14.01.2015 Требования к качеству статей неуклонно растут. Хозяева бирж приспосабливаются к этому по-разному. Кто-то хитрит и придирается к чему может. Кто-то снижает уникальность из-за одного единственного технического термина в статье. А кто-то, не в силах придумать благовидные способы, просто блокирует и грабит пользователей. Во-вторых, биржи контента всё больше ориентируются на выполнение заданий, а продажа готовых статей становится второстепенной.

Для мобильных пользователей

Обзор смартфона Lenovo S580 26.11.2014 В этой статье подробно рассмотрен очередной смартфон Lenovo. Одним из направлений компании является выпуск смартфонов в доступном ценовом сегменте и с достойными характеристиками. Такой моделью и является S580. Качественный дисплей, хорошая камера, нестандартные 8 Гб памяти и производительный процессор обрекают этот смартфон на успех. В ближайшие месяцы он станет хитом продаж. Рассмотрим его внешний вид, функционал, характеристики, время работы. Firefox OS глазами пользователя. Часть 2 22.11.2014 К данному моменту Firefox OS вполне стабильна (по-настоящему) и вполне пригодна для использования теми, кому от смартфона нужны лишь базовые умения. Звонить умеет, Wi-Fi работает, смотреть видео и фотографии можно. Однако о покупке телефона с Firefox OS лучше не думать до тех пор, пока в местных магазинах не начнёт рябить в глазах от таких аппаратов. Ведь тогда и хороший выбор приложений появится, и дизайнеров Mozilla отыщет и на работу примет. Firefox OS глазами пользователя 22.11.2014 Мировосприятие многих сторонников Open Source основано на перманентном ожидания новинок. Когда-нибудь что-то разработают, выпустят, допилят, обвешают плюшками — реальность состоит лишь из надежд на счастливое будущее в заоблачных далях. Мы же в эти самые дали слегка заглянем и посмотрим на Firefox OS глазами ординарного пользователя. После чего, возможно, какие-то надежды развеются и растают, однако истина дороже. Рассматривать будем релиз 2.0.

Все публикации >>>

Последние комментарии

Все комментарии >>>

xbb.uz

Текст любой ценой: RTF / Хабрахабр

Что ж продолжим наши изыскания на предмет получения текста из различных форматов данных. Не так давно мы с вами научились вытаскивать текст из zipped-xml-based файлов (odt и docx), а также, в начале этой недели, из pdf. Сегодня мы продолжим с обещанным rtf.

Rich Text Format (он же rtf), вы могли бы подумать, достаточно забытый, хотя и не очень сложный формат представления текстовых данных. Что ж, относительно несложный для получения текста, но за свою историю: от своей первой версии до текущей 1.9.1 — он приобрёл под 300 страниц официально документации и огромное количество надстроек, которые в большей степени нам будут мешать при получении plain text'а. Попробуем их обойти...

А что там внутри?
Как уж повелось давайте заглянем вовнутрь rtf-файла и посмотрим, что там внутри:

Что мы видим? Я вижу наше любимое стихотворение «Парус». Мы видим изначально текстовый 8-битный формат данных. Это уже радует — когда в исходных данных текст, понимать, что происходит, гораздо проще. Теперь давайте разберёмся, как эти самые данные прочитать. Для этого я расскажу немного теории по теме.

Будем считать, что rtf состоит из управляющих слов, которые могут быть сгруппированы во вложенные множества. Управляющие слово начинается на обратный слэш (\), группа обёрнута в фигурные скобки ({ и }).

Управляющие слово состоит из последовательности букв английского алфавита (от a до z) и может быть завершено численным параметром (возможно отрицательным). Как вариант, слово может содержать один не цифро-буквенный ascii-символ. Всё, что не подпадает под эти правила, не является частью управляющего слова. Таким образом, последовательность вида \rtf1\ansi\ansicpg1251 без проблем делится на три слова rtf с параметром 1 (major-версия формата), ansi (текущая кодировка) и ansicpg с параметром 1251 (текущая кодовая страница под номером 1251 — т.е. Windows-1251).

Группированные множества определяют область действия управляющих слов. Таким образом, управляющие слова описанные внутри фигурных скобок работают только внутри них и всех дочерних подмножеств. Для того, чтобы правильно отработать какие слова имеют место сейчас — требуется вести стек управляющих слов. При открытии фигурной скобки создавать новый элемент-массив в стеке, в который сразу же добавлять данные предыдущего слоя стека, при закрытии скобки — удалять самый верхний слой.

Ещё стоит отметить, что некоторые управляющие слова могут быть закрыты с помощью добавления параметра ноль, а не создания новой подгруппы. Например, следующие варианты эквивалентны: This is {\b bold} text, This is \b bold \b0 text = This is bold text.

Откуда брать текст?
С устройством нового для нас формата мы познакомились, теперь зададимся вопросом, а где брать текст. Тут всё не так сложно, как может показаться — текст надо брать там, где текущая последовательность не идентифицируется, как управляющее слово. С парой исключений, естественно.

Во-первых, стоит отметить, что исходная кодировка rtf-файла — это ANSI, поэтому без всякий изысков сохранится только, английский текст. Нас же интересует, как минимум, русский текст, а ещё лучше Unicode, не так ли? Что правда, то правда — rtf хоть и старый формат, но сгодится на сохранение и того и другого.

Итак, в rtf'е есть возможность использования второй половины таблицы ASCII, та что от 128 и выше. С учётом текущей кодировки (выше управляющее слово \ansicpg), конечно же. Для этого в RTF была введена последовательность вида \'hh, где hh — это двоичный hex-код символа из таблицы ASCII.

Ну и второй, более интересный вариант, это unicode-кодированные данные. Для них в формат включено лаконично короткое ключевое слово \uABCD с цифровым параметром ABCD. ABCD в данном случае код unicode-символа в десятичной системе счисления. Всё опять просто, как вы могли заметить.

Просто, да не очень. В rtf существует ещё одно ключевое слово \ucN, которое тесно связано с Unicode. Дело в том, что формат RTF очень рьяно поддерживает совместимость со старыми устройствами, на которых возможно придётся открывать данный файл. Как вариант, подобное устройство (ну например компьютер с Windows 3.11 :) не сможет прочитать Unicode, что ему делать? Для этого после каждого unicode-символа, шифрованного ключевым словом \u может быть указано от нуля до нескольких символов, которые должны быть отображены в случае, если rtf-viewer не способен отобразить или разобрать текущие данные (по документации, если просмотрщик не может отобразить верно данные, он должен их пропустить).

В связи с этим, большинство современных редакторов после unicode-управляющего слова ставят символ вопроса, как знак, что требуется показать вместо текущего символа. Но возможны и варианты, например: Lab\u915GValue. Зададимся вопросом — сколько символов требуется отобразить, если нет возможности показать Unicode. Всё опять же не очень сложно — указанное выше ключевое слово \ucN в качестве параметра N как раз и предоставляет это значение. Т.е. перед Unicode-данными обязательно появится что-то типа \uc1, что скажет нам пропустить один символ после unicode'а.

Давайте почитаем!
Похоже, что накопленных нами данных будет достаточно, чтобы прочитать наши первые rtf-файлы. Поехали:
  1. function rtf_isPlainText($s) {
  2.     $failAt = array("*", "fonttbl", "colortbl", "datastore", "themedata");
  3.     for ($i = 0; $i < count($failAt); $i++)
  4.         if (!empty($s[$failAt[$i]])) return false;
  5.     return true;
  6. }
  7. function rtf2text($filename) {
  8.     $text = file_get_contents($filename);
  9.     if (!strlen($text))
  10.         return "";
  11.     $document = "";
  12.     $stack = array();
  13.     $j = -1;
  14.     for ($i = 0; $i < strlen($text); $i++) {
  15.         $c = $text[$i];
  16.         switch ($c) {
  17.             case "\\":
  18.                 $nc = $text[$i + 1];
  19.                 if ($nc == '\\' && rtf_isPlainText($stack[$j])) $document .= '\\';
  20.                 elseif ($nc == '~' && rtf_isPlainText($stack[$j])) $document .= ' ';
  21.                 elseif ($nc == '_' && rtf_isPlainText($stack[$j])) $document .= '-';
  22.                 elseif ($nc == '*') $stack[$j]["*"] = true;
  23.                 elseif ($nc == "'") {
  24.                     $hex = substr($text, $i + 2, 2);
  25.                     if (rtf_isPlainText($stack[$j]))
  26.                         $document .= html_entity_decode("&#".hexdec($hex).";");
  27.                     $i += 2;
  28.                 } elseif ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
  29.                     $word = "";
  30.                     $param = null;
  31.                     for ($k = $i + 1, $m = 0; $k < strlen($text); $k++, $m++) {
  32.                         $nc = $text[$k];
  33.                         if ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
  34.                             if (empty($param))
  35.                                 $word .= $nc;
  36.                             else
  37.                                 break;
  38.                         } elseif ($nc >= '0' && $nc <= '9')
  39.                             $param .= $nc;
  40.                         elseif ($nc == '-') {
  41.                             if (empty($param))
  42.                                 $param .= $nc;
  43.                             else
  44.                                 break;
  45.                         } else
  46.                             break;
  47.                     }
  48.                     $i += $m - 1;
  49.                     $toText = "";
  50.                     switch (strtolower($word)) {
  51.                         case "u":
  52.                             $toText .= html_entity_decode("&#x".dechex($param).";");
  53.                             $ucDelta = @$stack[$j]["uc"];
  54.                             if ($ucDelta > 0)
  55.                                 $i += $ucDelta;
  56.                         break;
  57.                         case "par": case "page": case "column": case "line": case "lbr":
  58.                             $toText .= "\n"; 
  59.                         break;
  60.                         case "emspace": case "enspace": case "qmspace":
  61.                             $toText .= " "; 
  62.                         break;
  63.                         case "tab": $toText .= "\t"; break;
  64.                         case "chdate": $toText .= date("m.d.Y"); break;
  65.                         case "chdpl": $toText .= date("l, j F Y"); break;
  66.                         case "chdpa": $toText .= date("D, j M Y"); break;
  67.                         case "chtime": $toText .= date("H:i:s"); break;
  68.                         case "emdash": $toText .= html_entity_decode("&mdash;"); break;
  69.                         case "endash": $toText .= html_entity_decode("&ndash;"); break;
  70.                         case "bullet": $toText .= html_entity_decode("&#149;"); break;
  71.                         case "lquote": $toText .= html_entity_decode("&lsquo;"); break;
  72.                         case "rquote": $toText .= html_entity_decode("&rsquo;"); break;
  73.                         case "ldblquote": $toText .= html_entity_decode("&laquo;"); break;
  74.                         case "rdblquote": $toText .= html_entity_decode("&raquo;"); break;
  75.                         default:
  76.                             $stack[$j][strtolower($word)] = empty($param) ? true : $param;
  77.                         break;
  78.                     }
  79.                     if (rtf_isPlainText($stack[$j]))
  80.                         $document .= $toText;
  81.                 }
  82.                 $i++;
  83.             break;
  84.             case "{":
  85.                 array_push($stack, $stack[$j++]);
  86.             break;
  87.             case "}":
  88.                 array_pop($stack);
  89.                 $j--;
  90.             break;
  91.             case '\0': case '\r': case '\f': case '\n': break;
  92.             default:
  93.                 if (rtf_isPlainText($stack[$j]))
  94.                     $document .= $c;
  95.             break;
  96.         }
  97.     }
  98.     return $document;
  99. }
Код с комментариями вы можете получить на GitHub'е.
Заключение
Что мы имеем в итоге? Данный код справится верно с большинством rtf-файлов, но есть несколько способов его улучшить. Во-первых, стоит добавить дополнительные отсечения на нетекстовые данные — у меня отсекаются только шрифты, цветовая палитра, тема оформления, бинарные данные, а также всё, что помечено, как «не читай меня, если не можешь» (\*). Во-вторых же, стоит ещё распарсить кодировку и кодовую страницу, для того чтобы вернее отобразить ключевые слова вида \'hh.

Что дальше? Дальше я бы хотел затронуть форматы электронных книг, такие как fb2, epub и подобные им. В связи с этим, я хотел бы обратиться за помощью к читателям: во-первых, какие ещё форматы электронных книг стоит посмотреть, а во-вторых, где можно найти побольше файлов, указанных вами форматов. Заранее спасибо :)

Ссылки:

habrahabr.ru

Преобразование XML-данных в формат RTF для отображения в Word, с помощью ASP.NET и Visual Basic .NET

Автор:
  • Фрэнк Райс (Frank Rice), Корпорация Майкрософт

Опубликовано: июль 2004 года

В статье описываются различные способы преобразования XML-данных в формат RTF. Формат XML является удобным способом организации и представления данных. Текстовый формат RTF обеспечивает хранение форматированного текста, графики и структуры документа. Преобразование XML-данных в формат RTF позволяет быстро и без труда создавать документы на основе разнообразных источников данных.

 Оригинал статьи (EN)

Введение

В статье описывается, как можно генерировать данные в формате RTF (Rich Text Format) из XML (Extensible Markup Language) с помощью Microsoft Visual Basic .NET. Текстовый формат RTF обеспечивает хранение форматированного текста, графики и структуры документа. Он широко используется в текстовых процессорах, в том числе и Microsoft Office Word 2003. Поскольку RTF — текстовый формат, его довольно просто генерировать с помощью программного кода. Если имеются XML-данные , которые необходимо показать в Word (например, каталог, список или документ для слияния), то преобразование XML-данных в поток RTF может оказаться идеальным решением. К тому же, при разработке решений, генерирующих документы на стороне веб-сервера, применение текстовых форматов HTML или RTF является предпочтительным по сравнению с использованием серверного программирования объектов Word (automation).

В настоящей статье приведен код и пошаговые инструкции, описывающие несколько методов преобразования XML-данных в формат RTF для последующего показа в Word:

  • сохранение данных RTF в файл и открытие этого файла в Word;
  • передача данных RTF в Word с помощью буфера обмена Windows;
  • потоковая передача данных RTF из веб-приложения ASP.NET с использованием простого, а затем более сложного преобразования в приложение Word, которое работает в обозревателе Microsoft Internet Explorer.
Спецификация RTF, обсуждаемая в настоящей статье, является распространенным методом создания документов в Microsoft Office 2002 и более поздних версиях. Теме не менее для создания документов Word из XML-данных в выпусках Microsoft Office 2003 рекомендуется использовать Microsoft WordML в сочетании с XSLT.

Дополнительную информацию можно найти в следующих статьях:

 Office 2003 XML Reference Schemas (Эталонные схемы XML для Office 2003) (EN) Новые XML-функции в объектной модели Microsoft Office Word 2003 (EN) Работа с XML в системе Microsoft Office System (EN) Редактирование данных XML с помощью Microsoft Office Word 2003 и Microsoft Office Excel 2003 (EN) Поддержка XML в объектной модели Microsoft Office Word 2003 — обзор (EN)

Спецификация формата RTF

Спецификация RTF — это открытая спецификация для генерирования RTF-совместимых текстовых файлов. Документ Word 2002 Tool: Rich Text Format Specification (Средство для Word 2002: спецификация RTF) (EN) можно использовать в качестве ресурса для создания собственных RTF-файлов.

Преобразование XML-данных в формат RTF

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

Чтобы преобразовать пользовательские XML-данные в формат RTF и копировать результаты в файл или в буфер обмена, выполните следующие действия

  1. В Visual Basic .NET создайте Windows-приложение. Форма Form1 будет создана автоматически.
  2. Поместите на форму Form1 два элемента управления типа «кнопка».
  3. В меню View («Вид») выберите Code («Код»).
  4. Введите следующий код в верхней части окна перед реализацией класса Form1.

    Листинг 1.

    Imports System.Xml Imports System.Xml.Xsl Imports System.IO
  5. Добавьте следующий код к реализации класса Form1 (перед оператором End Class):

    Листинг 2.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Button1.Text = "To File" Button2.Text = "To Clipboard" End Sub Private Sub ButtonsClick(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click, Button2.Click Dim sPath As String = Directory.GetParent (Directory.GetCurrentDirectory()).ToString ' Open the XML file. Dim xmlDoc As New XmlDocument() xmlDoc.Load(sPath & "\Dictionary.xml") ' Open the XSL file. Dim xslDoc As New XslTransform() xslDoc.Load(sPath & "\Dictionary.xslt") Select Case sender.name Case "Button1" ' Transform the XSL and save it to a file. Dim TWrtr As New XmlTextWriter(sPath & "\Dictionary.RTF", System.Text.Encoding.Default) xslDoc.Transform(xmlDoc, Nothing, TWrtr) TWrtr.Close() MsgBox("Transformed RTF saved to " & sPath & "\Dictionary.RTF") Case "Button2" ' Transform the XSL and copy it to the clipboard. Dim SWrtr As New StringWriter() xslDoc.Transform(xmlDoc, Nothing, SWrtr) Dim datObj As New DataObject(DataFormats.Rtf, SWrtr) Clipboard.SetDataObject(datObj) SWrtr.Close() MsgBox("Transformed RTF copied to the clipboard.") End Select End Sub
  6. Добавьте в проект XML-файл, выполнив следующие действия.
  7. — В меню Project («Проект») выберите Add New Item («Добавить новый элемент»).
  8. — В списке шаблонов выберите XML File («XML-файл»).
  9. — Введите имя Dictionary.xml и нажмите кнопку Open («Открыть»).
  10. — Добавьте следующий код к содержимому файла Dictionary.xml:

    Листинг 3.

    <Dictionary> <Entries> <Entry> <Word Type="1">Energetic</Word> <Definition>Having, exerting, or displaying energy</Definition> </Entry> <Entry> <Word Type="1">Happy</Word> <Definition>Enjoying, displaying, or characterized by pleasure or joy</Definition> </Entry> <Entry> <Word Type="2">Emotion</Word> <Definition>A complex, strong subjective response</Definition> </Entry> </Entries> </Dictionary>
  11. Добавьте в проект файл XSLT, выполнив следующие действия.
  12. — В меню Project («Проект») выберите Add New Item («Добавить новый элемент»).
  13. — В списке шаблонов выберите XSLT File (Файл XSLT).
  14. — Введите имя Dictionary.xslt и нажмите кнопку Open («Открыть»).
  15. — Замените содержимое файла Dictionary.xslt следующим кодом.

    Листинг 4.

    <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>{\rtf1</xsl:text> <xsl:for-each select="Dictionary/Entries/Entry"> <xsl:text>\par\b </xsl:text> <xsl:value-of select="Word"/> <xsl:text>\b0\i </xsl:text> <xsl:if test="Word[@Type='1']">adj.</xsl:if> <xsl:if test="Word[@Type='2']">n.</xsl:if> <xsl:text>\i0\par </xsl:text> <xsl:value-of select="Definition"/> <xsl:text>\par</xsl:text> </xsl:for-each> <xsl:text>}</xsl:text> </xsl:template> </xsl:stylesheet>
  16. Нажмите клавишу F5 для построения и выполнения программы.
  17. Щелкните To File («В файл»), чтобы сохранить преобразованные данные XML в файл (Dictionary.rtf). Можно открыть полученный RTF-файл в приложении Word, чтобы проверить результаты преобразования.
  18. Щелкните To Clipboard («В буфер обмена»), чтобы скопировать преобразованные XML-данные в буфер обмена Windows. Затем можно скопировать содержимое буфера обмена в новый или существующий документ Word и посмотреть результаты. Например, запустите Word, щелкните в поле документа, чтобы появился курсор, затем откройте меню «Правка» и выберите «Вставить».

Преобразование объекта DataSet в формат RTF

В Visual Basic .NET можно преобразовывать и объекты DataSet. Обычно объекты DataSet содержат подмножество из некоторого источника данных и похожи на реляционную базу данных в оперативной памяти.

Следующая процедура демонстрирует извлечение реляционных данных из модельной базы данных Northwind (в локализованном варианте ­ «Борей») и преобразование их в формат RTF. Демонстрируются два варианта преобразования: простой RTF-документ с контактными данными заказчиков, и более сложный, содержащий сведения о заказах покупателей в формате слияния.

Чтобы преобразовать объект DataSet в формат RTF, выполните следующие действия

  1. Создайте веб-приложение Visual Basic ASP.NET и сохраните его по адресу http://localhost/RTFDemo. Форма WebForm1 будет создана автоматически.
  2. Поместите на форму WebForm1 два элемента управления типа «кнопка».
  3. В меню View «Вид») выберите Code («Код»).
  4. Добавьте следующий код в функцию Page_Load:

    Листинг 5.

    Button1.Text = "View Contact Information" Button2.Text = "View Customer Orders"
  5. Добавьте следующую функцию в класс WebForm1.
    В следующем коде указано, что сервер Microsoft SQL Server установлен на локальном узле. Если необходимо использовать другой компьютер, соответствующим образом измените в строке подключения член Data Source.

    Листинг 6.

    Private Sub ButtonsClick(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click, Button2.Click ' Connect to the data source. Dim nwindConn As SqlConnection = New SqlConnection( _ "Data Source=localhost;Initial Catalog=Northwind; Integrated Security=SSPI") nwindConn.Open() ' Build a dataset based on whether you requested to view ' a list of orders or a list of contacts. Dim ds As DataSet Dim sXSL As String Select Case (sender.id) Case "Button1" ds = New DataSet("Contacts") Dim ContactsDA As SqlDataAdapter = New SqlDataAdapter ("SELECT * FROM Customers", nwindConn) ContactsDA.Fill(ds, "Customers") ' XSLT to use for transforming this dataset. sXSL = "Contacts.xslt" Case "Button2" ds = New DataSet("CustomerOrders") Dim custDA As SqlDataAdapter = New SqlDataAdapter ("SELECT CustomerID, CompanyName, " & _ "Address, City, Region, PostalCode, Country FROM Customers", nwindConn) custDA.Fill(ds, "Customers") Dim ordersDA As SqlDataAdapter = New SqlDataAdapter ("SELECT OrderID, CustomerID, Freight " & _ "FROM Orders", nwindConn) ordersDA.Fill(ds, "Orders") Dim ordersdetailDA As SqlDataAdapter = New SqlDataAdapter( _ "SELECT [Order Details].OrderID, Products.ProductName, [Order Details].Quantity, " & _ "[Order Details].[UnitPrice]*[Quantity]* (1-[Discount]) AS ItemTotal " &21.10.2004 _ "FROM Products INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID " _ , nwindConn) ordersdetailDA.Fill(ds, "OrderDetails") nwindConn.Close() ds.Relations.Add("CustOrders", _ ds.Tables("Customers").Columns("CustomerID"), _ ds.Tables("Orders").Columns("CustomerID")) .Nested = True ds.Relations.Add("OrdersToOrdersDetail", _ ds.Tables("Orders").Columns("OrderID"), _ ds.Tables("OrderDetails").Columns("OrderID")) .Nested = True ' XSLT to use for transforming this dataset. sXSL = "CustOrders.xslt" End Select ' Close the connection to the data source. nwindConn.Close() ' Transform the dataset by using the appropriate stylesheet. Dim xmlDoc As XmlDataDocument = New XmlDataDocument(ds) Dim xslTran As XslTransform = New XslTransform() xslTran.Load(Server.MapPath(sXSL)) ' Stream the results of the transformation to Word. Response.ContentType = "application/msword" Response.Charset = "" Response.ContentEncoding = System.Text.Encoding.Default xslTran.Transform(xmlDoc, Nothing, Response.Output) End Sub
  6. Добавьте следующие строки кода в начало WebForm1.aspx.vb, перед реализацией класса WebForm1.

    Листинг 7.

    Imports System.Data.SqlClient Imports System.Xml Imports System.Xml.Xsl
  7. В меню Project («Проект») выберите Add New Item («Добавить новый элемент»).
  8. В списке шаблонов выберите XSLT File («XSLT-файл»), присвойте файлу имя Contacts.xslt, а затем нажмите кнопку Open («Открыть»).
  9. Замените содержимое файла Contacts.xslt следующим кодом.

    Листинг 8.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user= "urn:my-scripts" > <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>{\rtf1</xsl:text> <xsl:text>{\fonttbl{\f0\froman\fcharset0\fprq2 Times New Roman;}{\f1\fswiss\fcharset0\fprq2 Arial;}}</xsl:text> <xsl:text>{\header\pard\fs50 My Customer Contacts}</xsl:text> <xsl:text>{\footer\pard\fs18 Page {\field{\*\fldinst PAGE}</xsl:text> <xsl:text>{\fldrslt }} of {\field{\*\fldinst NUMPAGES}{\fldrslt 1}} \par}</xsl:text> <xsl:text>\f1\fs20</xsl:text> <xsl:for-each select="Contacts/Customers"> <xsl:text>\par\b </xsl:text><xsl:value-of select="CustomerID"/><xsl:text>\b0</xsl:text> <xsl:text>\par </xsl:text><xsl:value-of select="CompanyName"/> <xsl:text>\par </xsl:text><xsl:value-of select="ContactName"/> <xsl:text>\par </xsl:text><xsl:value-of select="Phone"/> <xsl:text>\par</xsl:text> </xsl:for-each> <xsl:text>}</xsl:text> </xsl:template> <xsl:template match="Customers"> <xsl:text>\par\b </xsl:text><xsl:value-of select="CustomerID"/><xsl:text>\b0</xsl:text> <xsl:text>\par </xsl:text><xsl:value-of select="CompanyName"/> <xsl:text>\par </xsl:text><xsl:value-of select="ContactName"/> <xsl:text>\par </xsl:text><xsl:value-of select="Phone"/> <xsl:text>\par</xsl:text> </xsl:template> </xsl:stylesheet>
  10. В меню Project («Проект») выберите Add New Item («Добавить новый элемент»). В списке шаблонов выберите XSLT, присвойте файлу имя CustOrders.xslt, а затем нажмите кнопку Open («Открыть»).
  11. Замените содержимое файла CustOrders.xslt следующим кодом.

    Листинг 9.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user= "urn:my-scripts" > <xsl:output method="text"/> <msxsl:script language="VB" implements-prefix="user"> Dim CustomerTotal as Double = 0 Dim OrderSubtotal as Double = 0 Function AddToOrderSubtotal(amt) amt.MoveNext OrderSubtotal = OrderSubtotal + System.Convert.ToDouble(amt.Current.Value) End Function Function GetOrderSubtotal GetOrderSubtotal = OrderSubtotal End Function Function GetCustomerTotal GetCustomerTotal = CustomerTotal CustomerTotal = 0 End Function Function GetOrderTotal(freight) freight.MoveNext nFreight = System.Convert.ToDouble(freight.Current.Value) GetOrderTotal = nFreight + OrderSubtotal CustomerTotal = nFreight + OrderSubtotal + CustomerTotal OrderSubtotal = 0 End Function </msxsl:script> <xsl:template match="CustomerOrders"> <xsl:text>{\rtf1</xsl:text> <xsl:text>{\colortbl;\red0\green0\blue0;\red0\green0\ blue255;\red0\green255\blue255; \red0\green255\blue0;\red255\green0\blue255;\red255\ green0\blue0;\red255\green255\blue0; \red255\green255\blue255;\red221\green221\blue221;}</xsl:text> <xsl:text>{\info{\title Sample RTF Document}{\author Microsoft Developer Support}}</xsl:text> <xsl:text>{\header\pard\qc{\fs50 ASP-Generated RTF\par}{\fs18\chdate\par}\par\par}</xsl:text> <xsl:text>{\footer\pard\qc\brdrt\brdrs\brdrw10\brsp100\fs18 Page {\field{\*\fldinst PAGE}</xsl:text> <xsl:text>{\fldrslt }} of {\field{\*\fldinst NUMPAGES} {\fldrslt 1}} \par}</xsl:text> <xsl:apply-templates select="Customers"/> <xsl:text>}</xsl:text> </xsl:template> <xsl:template match="Customers"> <xsl:text>\par\pard\fs20\cf2\qr\b </xsl:text><xsl:value-of select="CustomerID"/><xsl:text>\cf0\b0</xsl:text> <xsl:text>\par\pard </xsl:text><xsl:value-of select="CompanyName"/> <xsl:text>\par </xsl:text><xsl:value-of select="Address"/> <xsl:text>\par </xsl:text><xsl:value-of select="City"/> <xsl:text>, </xsl:text><xsl:value-of select="Region"/> <xsl:text> </xsl:text><xsl:value-of select="PostalCode"/> <xsl:text>\par </xsl:text><xsl:value-of select="Country"/> <xsl:text>\par\par</xsl:text> <xsl:apply-templates select="Orders"/> <xsl:text>\trowd\cellx7000\cellx9000\pard\intbl\ql\b\cbpat1 </xsl:text> <xsl:text>Order Total for the Current Period:\cell </xsl:text> <xsl:text>\qr</xsl:text> <xsl:variable name="CustTtl" select="user:GetCustomerTotal()"/> <xsl:value-of select="format-number($CustTtl,'$###0.00')"/> <xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\pard\par\pard</xsl:text> <xsl:text>\pard\plain\fs18\cf6\qc</xsl:text> <xsl:choose> <xsl:when test="$CustTtl = 0"> <xsl:text>\b We've missed hearing from you!\b0 </xsl:text> <xsl:text> At your convenience, please call your personal sales representative </xsl:text> <xsl:text>so that we may discuss our specials for new and returning customers!</xsl:text> </xsl:when> <xsl:when test="$CustTtl > 2000"> <xsl:text>\b Congratulations!\b0 Your purchases for this period qualify you for a \b 20%\b0 </xsl:text> <xsl:text> discount on one of your next orders. To take advantage of this offer, provide </xsl:text> <xsl:text>the coupon code ABC123XYZ when placing your order.</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text> We value your patronage with Northwind Traders and would love to hear from you. </xsl:text> <xsl:text>If you have any questions about our upcoming line of products or if you want </xsl:text> <xsl:text>a catalog for the coming season, call 1-888-000-000.</xsl:text> </xsl:otherwise> </xsl:choose> <xsl:text>\par\pard</xsl:text> <xsl:text>\par \page</xsl:text> </xsl:template> <xsl:template match="Orders"> <xsl:text>\trowd\cellx9000\pard\intbl\cbpat9</xsl:text> <xsl:text>\ql\b </xsl:text><xsl:value-of select="OrderID"/><xsl:text>\b0\cell </xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:apply-templates select="OrderDetails"/> <xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Subtotal:\cell </xsl:text> <xsl:value-of select="format-number (user:GetOrderSubtotal(),'$###0.00')"/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Freight:\cell </xsl:text> <xsl:value-of select="format-number (Freight,'$###0.00')"/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\trowd\cellx7000\cellx9000\pard\intbl</xsl:text> <xsl:text>\qr Total:\cell </xsl:text> <xsl:value-of select="format-number(user:GetOrderTotal(Freight), '$###0.00')"/><xsl:text>\cell</xsl:text> <xsl:text>\pard\intbl\row</xsl:text> <xsl:text>\trowd\cellx9000\pard\intbl \cell\pard\intbl\row</xsl:text> </xsl:template> <xsl:template match="OrderDetails"> <xsl:text>\trowd\cellx5000\cellx7000\cellx9000\pard\intbl\ ql </xsl:text> <xsl:value-of select="ProductName"/><xsl:text>\cell </xsl:text> <xsl:text>\qc </xsl:text><xsl:value-of select="Quantity"/><xsl:text>\cell </xsl:text> <xsl:text>\qr </xsl:text> <xsl:value-of select="format-number (ItemTotal,'$###0.00')"/><xsl:text>\cell</xsl:text> <xsl:variable name="RunTotal" select="user:AddToOrderSubtotal(ItemTotal)"/> <xsl:text>\pard\intbl\row</xsl:text> </xsl:template> </xsl:stylesheet>
  12. В меню Build («Построить») выберите Build Solution («Построить решение»).
  13. Запустите Internet Explorer и откройте страницу http://localhost/RTFDemo/Webform1.aspx.
  14. Выберите View Contact Information («Просмотр контактной информации»), чтобы отобразить в приложении Word первый вариант преобразования XML в RTF.
  15. Нажмите кнопку «Назад» в Internet Explorer.
  16. Выберите View Customer Orders («Просмотр заказов покупателей»), чтобы отобразить в приложении Word второй вариант преобразования XML в RTF.

Разрешение вопросов при работе с форматом RTF

Выводится сообщение типа Login failed for user "MachineName\ASPNET" (Нет доступа для пользователя "имя_компьютера\ASPNET")

Если при нажатии одной из кнопок появилось сообщение «Login failed for user ««MachineName\ASPNET», то, вернее всего, учетная запись \ASPNET не имеет необходимых разрешений в SQL Server и поэтому не может получить доступ к базе данных. Чтобы устранить проблему, выполните следующие действия:

  1. Запустите диспетчер SQL Server Enterprise Manager.
  2. Разворачивайте уровни дерева, пока не откроется узел (local) (Windows NT).
  3. Разверните папку Security («Безопасность»).
  4. Выберите значок Logins («Подключения»), щелкните его правой кнопкой мыши и выберите New Login («Новое подключение»).
  5. В поле Name («Имя») введите aspnet. Убедитесь в том, что выбран параметр Windows Authentication («Проверка подлинности средствами Windows»).
  6. В раскрывающемся списке Domain («Домен») выберите локальный домен компьютера. Оставьте заданный по умолчанию параметр безопасности Grant access («Предоставить доступ»).
  7. В группе Defaults («Значения по умолчанию») откройте раскрывающийся список Database («База данных») и выберите Northwind. Оставьте в качестве языка по умолчанию English.
  8. Нажмите кнопку ОК.
  9. Повторно нажмите одну из кнопок.

Сохранение RTF-данных в файле и перенаправление на сохраненный файл

Пример кода, приведенный в разделе Преобразование объекта DataSet в формат RTF, передает данные RTF непосредственно в обозреватель. Однако можно сохранить их в файл и выполнить перенаправление на сохраненный файл. Для этого необходимо заменить в примере следующие строки кода:

Листинг 10.

Response.ContentType = "application/msword" Response.ContentEncoding = System.Text.Encoding.Default Response.Charset = "" xslTran.Transform(xmlDoc, Nothing, Response.Output)

на другие:

Листинг 11.

Dim writer As XmlTextWriter = New XmlTextWriter( _ Server.MapPath("Results.doc"), System.Text.Encoding.Default) xslTran.Transform(xmlDoc, Nothing, writer) writer.Close() Response.Redirect("Results.doc")

Сохранив таким образом RTF-данные в файле, можно изучить их структуру с помощью текстового редактора, например «Блокнота». Это может быть удобно в тех случаях, когда преобразование XSL не дает ожидаемых результатов.

Обратите внимание на представление пробелов и возвратов каретки

Выполняя преобразование в формат RTF, обратите внимание на представление пробелов и возвратов каретки в таблице стилей, поскольку это может повлиять на то, как Word интерпретирует RTF-данные. В обоих примерах кода в этом разделе используется элемент <xsl:text>, поскольку он обеспечивает сохранение всех пробелов.

Убедитесь в том, что данные XML преобразовываются в текст

Используйте элемент <xsl:output method="text"> в таблице стилей, чтобы обеспечить преобразование данных XML в текст (а не в XML — формат вывода по умолчанию). Если не указать text как формат вывода, в файл могут быть добавлены инструкции по обработке XML. В результате Word может не опознать текст как RTF.

Заключение

В настоящей статье были рассмотрены различные способы преобразования XML-данных в формат RTF. В частности, мы описали, как преобразовать пользовательские XML-данные в формат RTF, копируя результаты в файл или в буфер обмена. Мы также рассмотрели простой способ преобразования наборов данных с помощью Visual Basic .NET. Поскольку RTF — это текстовый формат, RTF-данные легко создать в программном коде. Кроме того, сегодня XML де-факто является стандартом представления данных. По этой причине описанные методы вполне могут пригодиться разработчикам для создания RTF-документов в собственных приложениях.

Дополнительная информация

Дополнительные сведения по использованию RTF в собственных решениях можно найти в следующих статьях:

 Статья Microsoft Knowledge Base — 270906: HOWTO: Use ASP to Generate a Rich Text Format (RTF) Document to Stream to Microsoft Word (Генерирование документа RTF с помощью ASP для передачи в Microsoft Word) (EN) Статья Microsoft Knowledge Base -258513: HOWTO: Paste Rich Text Formatted String into Word with Visual Basic Automation (Вставка строки RTF в Word с помощью Visual Basic Automation) (EN)

Дополнительные сведения по преобразованию XML с помощью Visual Basic .NET можно найти в следующих статьях:

 Статья Microsoft Knowledge Base -300934: HOW TO: Apply an XSL Transformation to XML for Streaming by Using Visual Basic .NET (Применение XSLT к XML для потоковой передачи с использованием Visual Basic .NET) (EN) Статья Microsoft Knowledge Base -300929: HOW TO: Apply an XSL Transformation from an XML Document to an XML Document Using Visual Basic .NET (Применение XSLT для преобразования одного документа XML в другой с использованием Visual Basic .NET)

msdn.microsoft.com

Знакомство с XML и XSLT. Применение XML и XSLT. Зачем изучать XML и XSLT

Этой статьей я открываю новую рубрику на блоге dmitriydenisov.com под названием «Уроки XML и XSLT». В ней мы пошагово изучим такой очень функциональный, универсальный и расширяемый язык разметки, как XML. После этого мы плавно перейдем к технологии преобразования XSLT, которая позволяет с легкостью управлять данными XML и буквально творить чудеса.

Сразу также хочется заметить, что эти технологии в основном используются на крупных коммерческих проектах. Особенно это касается запада, где XML и XSLT активно используются уже на протяжении нескольких лет. К сожалению, до нас эти технологии еще не успели дойти в полной мере.

Из этого стоит сделать вывод, что знание XML и XSLT будет для вас огромным плюсом, так как на данный момент специалистов в этой области не так уж и много. В результате через несколько лет, когда XML и XSLT наберет популярности и у нас, у вас будет огромное преимущество перед теми, кто еще не успел овладеть этой технологией. Как вы уже поняли, это позволит вам расширить свои возможности и увеличить свой доход. А кто не хочет сейчас заработать? Думаю, таких мало.

В связи с этим я решил помочь всем желающим и написать серию статей посвященных этой теме. К сожалению, на данный момент очень мало качественной и понятной литературы для самостоятельного изучения XML и XSLT. Что касается разнообразных курсов, то они зачастую являются очень дорогостоящими и не у каждого могут оказаться деньги. Честно говоря, и у меня их нет, поэтому я и занимаюсь самостоятельным обучением, а не хочу по курсамJ

Сказать по правде, не всегда все идет гладко. Порой приходится долго разбираться в некоторых моментах для того, чтобы понять всю суть того, что изучаешь. Исходя из этого, я постараюсь писать статьи максимально кратко и понятно, и в то же время не загружать вас ничем лишним. Весь материал будет разбит на части и подробно изложен в статьях объемом 800 – 1200 слов. На мой взгляд, это оптимальный размер статьи, который позволяет подробно изложить весь материал и избежать нагромождения лишней информацией. Думаю, со мной многие согласятся.

Итак, теперь давайте рассмотрим, в каком порядке будет происходить изучение XML и XSLT.

Что будет рассматриваться в рубрике «Уроки XML и XSLT»

Для начала мы изучим основы языка разметки XML, рассмотрим базовые понятия XML, а также разберемся с описанием структуры XML документов (DTD, XML Schema). Таким образом, мы получим базовые знания для работы с XML.

Далее мы перейдем к изучению основ XSLT. Для этого нам понадобится также немного изучить основы XPath. Мы рассмотрим основные элементы XSLT, а также возможности XSLT. Также на протяжении всего обучения будут приводиться разнообразные примеры для лучшего усвоения материала. Таким образом, обучение будет максимально быстрым и интересным.

Ну а теперь давайте перейдем к завершающей части статьи и рассмотрим, где же применяется технологии XML и XSLT, а также какие они имеют возможности.

Использование расширяемого языка разметки XML

XML – очень функциональный язык разметки, который широко применяется во многих сферах. На нем работают многочисленные программы и приложения, начиная с обычных RSS лент и заканчивая такими крупными проектами, как Microsoft Word. Убедиться в последнем очень просто. Для этого смените расширение документа Microsoft Word с docx на zip. Далее распакуйте получившийся архив, после чего перейдите в папку word. В ней вы найдете XML файлы, в которых и хранится вся информация документа Word.

Отредактировав необходимые файлы, в частности файл word/document.xml, вы можете произвести обратную процедуру и запаковать все файлы обратно в zip архив. Далее сменить расширение архива на docx и открыть файл программой Microsoft Word. В результате вы увидите все изменения, которые вы вносили в XML документ.

Таким образом, мы видим, что XML это универсальный, расширяемый язык с очень широкими возможностями. Благодаря этому он с успехом может использоваться в самых разнообразных проектах, начиная с небольших сайтов и заканчивая многомиллиардными проектами, такими как Microsoft Office.

Поскольку это только вводная статья, то мы не будем слишком углубляться в основы языка и сферы его применения. Более подробно обо всем этом мы еще поговорим в соответствующих статьях рубрики «Уроки XML и XSLT».

Использование языка преобразования XML-документов XSLT

XSLT является очень мощным инструментом для работы с XML. С его помощью можно с легкостью преобразовывать XML данные, а также получать доступ к нужным нам элементам. Например, у нас есть исходный файл с перечислениями стран в формате XML и мы хотим получить названия всех стран Европы в формате HTML. Для этого достаточно написать небольшой XSLT шаблон, который обработает XML файл и сформирует готовую HTML страницу со списком нужных нам стран. Аналогичным образом результат может быть представлен также и в XHTML, XML или просто в виде текстового документа.

По сути сам XSLT является набором правил, которые применяются к документу при определенных условиях. Его также еще называют таблицами стилей XLST, хотя, на мой взгляд, между таблицами стилей CSS и XSLT практически нет ничего общего. Таким образом, в результате обработки XML документа мы получаем то, что задано в XSLT шаблоне. Это немного похоже на работу CSS, но только лишь немного. На самом деле в XSLT есть очень большое количество других возможностей, которые никак несравнимы с возможностями CSS.

Ну а теперь давайте подведем небольшой итог.

XML и XSLT являются очень мощными инструментами, как для веб-разработчиков, так и для разработчиков в других сферах. С их помощью решения множества задач становятся очень простыми, что в свою очередь и послужило тому, что данные технологии становятся все более и более популярными. При этом зачастую не требуется знание каких-либо языков программирования, хотя сам XSLT может с успехом использоваться в связке с C++, JavaScript и т.д.

Одним словом, XML и XSLT являются очень полезными инструментами, и их знание поможет вам значительно расширить свои возможности. Таким образом, если вы разработчик и у вас есть свободное время, рекомендую вам изучить XML и XSLT.

На этом данная статья подошла к концу. Может она получилась немного запутанной, но что сделано, то сделано. Возможностей здесь очень много и если писать обо всех из них, то можно написать целую книгу. Исходя из этого, был приведен лишь минимум информации для того, чтобы только заинтересовать и мотивировать вас к обучению.

Итак, если вы не хотите пропустить выпуска других статей уже непосредственно посвященных XML и XSLT, рекомендую подписаться на новостную рассылку любым удобным для вас способом в пункте «Подписка», либо воспользоваться формой подписки, которая находится чуть ниже на странице.

На этом все. Удачи вам и успехов в изучении XML и XSLT.

Обнаружили ошибку? Выделите ее и нажмите Ctrl+Enter

dmitriydenisov.com

Почтовый стандарт "MIME" (RFC1521)

Документ предсталяет собой неполный русский перевод спецификации RFC 1521 "MIME"

MIME означает "Multipurpose Internet Mail Extensions" (Многоцелевые расширения почтового стандарта Internet). Этот стандарт описывает как пересылать по электронной почте исполняемые, графические, мультимедийные, смешаные данные. Типичные применения MIME - пересылка графических изображений, аудио, документов Word, программ и даже просто текстовых файлов, то есть, когда важно, чтобы входе пересылки не производилось никаких преобразований над данными. MIME также позволяет размечать письмо на части различных типов так, чтобы получатель (почтовая программа) мог определить, что делать с каждой из частей письма.

Как читать письма в стандарте MIME? Т.к. MIME используется всего несколько лет, еще существуют старые почтовые программы, которые не понимают MIME. Однако, растет число почтовых программ, имеющих встроенную поддержку MIME (одна из самых популярных - "Pine", разработанная в Вашингтонском университете и реализованная для платформ UNIX, VMS, DOS, Windows). К тому же в некоторых почтовых системах имеются специальные шлюзы, обеспечивающие MIME-трансляцию. Но даже если у вас нет возможности использовать MIME-совместимую почтовую программу и нет доступа к подобному шлюзу, то можно также воспользоваться рядом программ, способных интерпретировать письма в MIME, сохраненные рпочтовой программой в файле. Например, програма "munpack", созданная в университете Carnegie Mellon. Существуют ее версии для Unix, PC, Macintosh, Amiga.

Долгое время для кодирования бинарных файлов в 7-битный формат (чтобы обеспечить их пересылку по почтовой системе Internet) использовалась кодировка UUENCODE, имеющая ряд технических ограничений. Стандарт MIME предполагает использовние более устойчивой кодировки "Base64", которая специально разработана для обеспечения сохранности данных, пересылаемых по email, при различных преобразованиях, имиеющих место в ходе прохождения почтовых шлюзов.

Стандарт MIME полностью описан в RFC-1521

 

  • I. Почтовый стандарт MIME

     

  • 1. Введение
  • 2. Замечания, соглашения и обобщения
  • 3. Поле заголовка 'MIME-Version'
  • 4. Поле заголовка 'Content-Type'
  • 5. Поле заголовка 'Content-Transfer-Encoding'
  • 5.1. Механизм конвертации "Quoted-Printable"
  • 5.2. Механизм конвертации Base64
  • 6. Дополнительные поля 'Content-'
  • 6.1. Необязательное поле заголовка 'Content-ID'
  • 6.2. Необязательное поле заголовка 'Content-Description'
  • 7. Предопределенные значения поля 'Content-Type'
  • 7.1. Тип 'Text'
  • 7.1.1. Параметр 'charset'
  • 7.1.2. Подтип 'Text/plain'
  • 7.2. Тип 'Multipart'
  • 7.2.1. Тип Multipart: общий синтаксис
  • 7.2.2. Подтип 'Multipart/mixed' (основной)
  • 7.2.3. Подтип 'Multipart/alternative'
  • 7.2.4. Подтип 'Multipart/digest'
  • 7.2.5. Подтип 'Multipart/parallel'
  • 7.2.6. Друтие подтипы типа 'Multipart'
  • 7.3. Тип 'Message'
  • 7.3.1. Подтип 'Message/rfc822' (основной)
  • 7.3.2. Подтип 'Message/Partial'
  • 7.3.3. Подтип 'Message/External-Body'
  • 7.3.3.1. Способы доступа "ftp" и "tftp"
  • 7.3.3.2. Способ доступа "anon-ftp"
  • 7.3.3.3. Способы доступа "local-file" и "afs"
  • 7.3.3.4. Способ доступа "mail-server"
  • 7.3.3.5. Примеры и дополнительные пояснения
  • 7.4. Тип 'Application'
  • 7.4.1. Подтип 'Application/Octet-Stream' (основной)
  • 7.4.2. Подтип 'Application/PostScript'
  • 7.4.3. Другие подтипы типа 'Application'
  • 7.5. Тип 'Image'
  • 7.6. Тип 'Audio'
  • 7.7. Тип 'Video'
  • 7.8. Экспериментальные значения поля 'Content-Type'

     

  • II. Применение возможностей MIME в транспортных почтовых системах

     

  • 1. Непринятая почта
  • 2. Разбиение (фрагментация) и сборка больших писем
  • 3. Использование или удаление указателей External-Body (внешнего тела)
  • 4. Преобразование графических и других форматов
  • 5. Надежное кодирование данных

 

 

1. Введение

Со времени опубликования в 1982 г., стандарт RFC 822 определил и полностью или частично внедрил формат текстовых писем в почтовой системе Internet. Но с расширением его использования, обнаружился ряд ограничений, заметно ограничивающих удовлетворение пользовательских потребностей. В частности, возможность пересылки нетекстовых данных, например, аудио и графики, посто не была упомянута в RFC822, описывавшем лишь формат текстовых сообщеий. И даже в случае текста, RFC 822 обошел вниманием нужды пользователей, использующих расширенный набор символов, что характерно для азиатских и большинства европейских языков. Итак, требовалась дополнительная спецификация. Основное ограничение RFC822 - относительно короткие строки и 7-битная символьная таблица. Пользователям дляотправки нетекстовых данных приходилось конвертировать тело своего письма в 7-битную форму с помощью UUENCODE, BINHEX и др.

Более очевидными стали ограничения RFC 822 при разработке почтовых шлюзов между хостами, использующими стандарт RFC822 и хостами, использующими стандарт X.400. X.400 имеет механизмы для включения нетекстовых данных в тело письма. В настоящее время стандарты для перевода почтовых сообщений из X.400 в RFC822 предполагают, что нетекстовые части тела письма должны быть сконвертированы (но не закодированы) в ASCII формат, либо должны быть "выброшены" из письма с уведомлением об этом получателя. А потеря информации крайне не желательна для пользователя.

MIME разработан как расширяемый механизм с расчетом на то, что набор пар content-type/subtype будет расти со временем. Некоторые другие поля заголовка MIMЕ, включая имена наборов символов, также , вероятно, получат большее число возможных значений. С этой целью MIME определяет процесс регистрации через Internet Assigned Numbers Authority (IANA), как центр регистрации этих значений. Описание процесса регистрации можно найти в приложении E RFC 1521.

 

2. Замечания, соглашения и обобщения

Термины "сообщение" и "письмо" являются синонимами. Термин "часть письма" или "часть тела письма" подразумевает одну из частей письма, разбитого на части разных типов данных. Часть тела письма, в свою очередь, имеет тело и заголовок, так что имеет смысл говорить о теле части тела письма. В дальнейшем, при отсутствии оговорок, "телом" будем называть тело рассматриваемого в данный момент объекта - части письма либо всего письма. Как уже ясно, формат MIME-сообщения, в общем случае, рекурсивен.

 

3. Поле заголовка "MIME-Version"

Поскольку старый стандарт RFC 822 все еще используется, а MIME возможно, изменится и дополнится в будущем, почтовой программе необходимо знать, применен ли новый стандарт в конкретном письме или нет. Поэтому в заголовок ввелено новое поле "MIME-Version", объявляющее версию стандарта, в соответствии с которым написано данное письмо.

Все почтовые сообщения, составленные в соответствии с MIME-стандартом, должны иметь это поле в своем заголовке, напрмер:

 

MIME-Version: 1.0

Так как возможно, в будущем формат заголовка письма может расшириться, формально содержание поля "MIME-version" дается следующим образом:

 

версия := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT

Т.о., будущие значения версии формата, коорые могут заменить "1.0", должны быть целыми числами, разделенными точкой. Если письмо получено со значением версии MIME, отличным от "1.0", оно не будет рассматриваться почтовой программой, как соответствующее данной спецификации.

Важно, что поле заголовка "MIME-Version", должно располагаться в самам начале письма. Это не обязательно для каждой из частей тела письма в случае многочастевого письма, но обязательно для заголовков частей типа "message", если и только если эта часть сама по себе декларирована как соответствующая спецификации MIME.

Не возможно полностью определить как почтовая программа, поддерживающая MIME, должна интерпретировать письмо, имеющее значение MIME-version, отличное от "1.0". Но, как минимум, почтовая программа должна предупредить пользователя о том, что письмо написано в незнакомом ей формате.

Все поля заголовка, включая MIME-Version, Content-type, и т.д., должны соответствовать общим синтаксическим правилам, определенным в RFC 822. В частности, допускается включение комментариев (т.е., следующие 2 примера эквивалентны):

 

MIME-Version: 1.0 MIME-Version: 1.0 (Generated by GBD-killer 3.7)

 

4. Поле заголовка "Content-Type"

Назначение этого поля - наиболее полное описание данных, содержащихся в теле, с тем, чтобы почтовый агент (программа) получателя могла выбрать соответствующий механизм для их обаботки. Впервые это поле было определено в RFC 1049, но имело более простой синтаксис.

Данное поле включает в себя идентификаторы типа и подтипа, а также может содержать некоторую вспомогательную информацию, которая может потребоваться для конкретного типа данных. После идентификаторов типа и подтипа оставшаяся часть поля - просто набор парамеров, заданных в порядке "атрибут/значение". Набор параметров зависит от типа данных. (В частности, не может быть глобально-значимых параметров, справедливых сразу для всех типов содержимого ьела письма. Глобальные механизмы в MIME-модели реализованы с помощью введения дополнительных полей "Content-*"). Очередность параметров значения не имеет. В числе определенных параметров - "charset", декларирующий символьный набор (кодировку, кодовую страницу - это все синонимы) тела письма. Комментарии допускаются.

Вообще, поле Content-Type самого верхнего уровня используется для объявления общего типа данных, в то время как подтип определяет специальный формат для данных этого типа. Так, значение "image/xyz" поля Content-Type сообщает пользовательской программе, что данные являются графическим изображением (image), даже если эта почтовая программа не имеет понятия о специальном формате "xyz" этой картинки. Но эта информация может быть использована программой, например, чтобы решить, показывать ли пользователю строкоые данные неизвестного подтипа -- показ таких данных может быть оправдан для незнакомых подтипов текста, но не для незнакомых подтипов графики, аудио или видео. По этой причине, данные зарегистрированного подтипа аудио, графики, текста или видео не должны содержать внутри себя части другого подтипа - для содержания в письме данных одного типа, но разных подтипов следует использовать тип "multipart" или "application".

Хотя многие параметры (модификаторы подтипов) имеют смысл лишь для конкретного типа, некоторые все же являются глобальными в том смысле. что они применимы ко всем типам (например, параметр "boundary" применим только с типом "multipart", а параметр "charset" может использоваться с несколькими типами).

Пока имен типов только семь, и пока этого достаточно. Кроме того, предполагается, что расширение существующего набора поддерживаемых типов данных будет производиться засчет введения новых подтипов этих изначально определенных типов данных. В будущем добавление имен типов верхнего уровня может быть произведено только при принятии новой версии стандарта MIME. Если по какой-либо другой причине в существующей версии используется незарегестрированный тип содежимого, ему должно быть дано имя, начинающееся с "X-", чтобы подчеркнуть его нестандартный статус и заранее предупредить конфликт с официальным именем типа, которое может быть введено позднее.

Правильное заполнение поля Content-Type:

 

содержимое := "Content-Type" ":" тип "/" подтип *(";" параметр) ; нечувствительное к регистру букв задание типа и подтипа тип := "application" / "audio" / "image" / "message" / "multipart" / "text" / "video" / признак нестандартного типа ; Все значения нечувствительны к регистру букв признак нестандартного типа := x- / iana- iana- := <общепринятый признак расширения, зарегистрированный соответ- ственно приложению "E" RFC 1521> x- := <Два последовательных символа "X-" или "x-", без пробела или другого символа между ними> подтип := слово ; регистр безразличен параметр := атрибут "=" значение атрибут := слово ; регистр безразличен значение := слово / строка в кавычках слово := любые ASCII-символы кроме пробелов, Ctrl-последова- тельностей и специальных символов Специальные символы:= "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "" / <"> / "/" / "[" / "]" / "?" / "=" ; Эти символы используются в строке значений параметров

Здесь набор специальных символов отличается от набора, определенного в RFC 822 только наличием символов "/", "?", "=" и отсутствием символа ".".

Указание подтипа в данном поле является обязательным, т.к. нет подтипов по умолчанию. В отличие от имен типов, подтипов и параметров, значения параметров в общем случае являются чувствительными к регистру букв, но могут быть и нечувствительными - в зависимости от параметра. Например, значения границ multipart-письма являются чувствительными, а значение "access-type" для message/External-body не является.

Существует два приемлимых механизма для введения новых подтипов для поля Content-Type:

 

  1. Нестандартные значения (начинающиеся с "X-") могут быть опредлены по договоренности для двух или более общающихся друг с другом почтовых агентов (программ) без какой-либо внешней регистрации и стандартизации.

     

  2. Новые стандартные значения подтипов должны быть документированы, зарегистрированы и опробованы в IANA, как описано в приложении "E" RFC 1521. Если новй подтип предлагается для широкого использования, формат, описываемый им, должен быть описан в опубликованной спецификации и, возможно, предложен к стандартизации.

Семь предопределенных типов верхнего уровня, более детально, представляют собой следующее:

text -- текстовая информация. Основой подтип - "plain" - соответствует обычному неформатировнному тексту и не требует специального программного обеспечения для отображения этого текста за исключением поддержки национальных кодировок. Другие подтипы используются в случае размеченного текста, когда с помощью специальной программы можно улучшить его визуалзацию, но для понимания идеи содержания можно обойтись и без дполнительного ПО. Возможные подтипы могут описывать легкочитаемые форматы различных текстовых процессоров.

multipart -- содержимое письма состоит из некоторого множества частей, содержащих данные различных взаимонезависимых типов. Изначально определено четыре подтипа:

  1. "mixed" - основной;
  2. "alternative" - для представления одних и тех же данных в разных форматах;
  3. "parallel" - если разные части документа должны просматриваться одновременно;
  4. "digest" - если каждая из частей тела письма имеет тип "message".

message -- письмо в письме. Тело, содержащее данные типа "message", само является письмом или частью письма, полностью отформатированного в соответствии со стандартом RFC 822, которое, в свою очередь, может содержать свое собственное поле заголовка "Content-Type".Подтипы:

  1. "rfc822" - основной;
  2. "partial" - определен для частично-цитируемых писем для предотвращения фрагментирования тел содержащихся писем в случае слишком большой их общей длины для возможностей почтового транспорта;
  3. "External-body" - используется, чтобы указать, что тело письма очень большое и находится вне письма.

image -- графические данные. Графика требует соответствующего устройства вывода (графический дисплей, принтер, факс) для отображения своей информации. Изначально определены два подтипа для наиболее распространенных графических форматов - jpeg и gif.

audio -- звуковая информация. Требует звуковое устройство (динамик или наушники) для вывода информации. Основной подтип - "basic".

video -- видео. Требует специальных аппаратных и программных возможностей для отображения видео-информации. Единстванный изначально определенный подтип - "mpeg".

application -- как правило, неинтерпретируемый двоичный код либо информация, предназначенная для обработки почтовой программой.Подтипы:

  1. "octet-stream" - основной подтип; предназначен для неинтерпретируемых двоичных данных, для которых рекомендуемым действием является предложение пользователю сохранить в файл на диске.
  2. "PostScript" - дополнительный подтип; применяется при пересылке PostScript-документов в теле письма.

По умолчанию, письма, как и в стандарте RFC 822 пишутся простым (неразмеченным) текстом в языковой кодировке US-ASCII, что по спецификации MIME может быть описано как "Content-type: text/plain; charset=us-ascii". Это значение полагается, если поле Content-type не определено. Поэтому почтовая программа получателя может неверно истолковать содержимое письма, если при отправке не было указано поле Content-type, но на самом деле текст письма имеет другую кодировку или даже тип.

При отсутствии поля Content-type или поля MIME-Version в заголовке MIME-письма нельзя быть точно уверенным, что письмо имеет языковую кодировку именно US-ASCII, поскольку могут еще встречаться почтовые программы, не использующие соглашения MIME. Но хотя возможно, что письмо, не содержащее в заголовке полей MIME-Version и Content-Type, может содержать все, что угодно, например, юниксовский tar-архив, сжатый gzip'ом и обработаный uuencode, все же, создателям почтовых программ рекомендуется оставлять этот факт без внимания и ориентироваться на значение по умолчанию, т.е. "text/plain; charset=us-ascii".

Необходимо учесть, что в будущем ожидается заметное увеличение числа регистрированных типов и особенно подтипов содержимого писем. Если почтовая программа встретит неизвестное ей значение поля Content-type, она должна интерпретировать содержимое этого письма как "application/octet-stream" (см.выше).

 

5. Поле заголовка Content-Transfer-Encoding

Многие типы данных, пересылаемых через email требуют "натурального" представления, то есть, 8-битный набор символов либо двоичный код (что для машины - одно и то же, только представимо для пользователя по-разному). В таком виде данные не могут быть пересланы по 7-битным почтовым протоколам, например, RFC 821, который, к тому же, ограничивает длину строки 1000 символами.

Стандартные механизмы конвертирования почты в 7-битный короткострочный формат, приемлимый для почтового транспорта, описывает поле заголовка Content-Transfer-Encoding.

В отличие от типов содержимого, увеличение множества значений Content-Transfer-Encoding не является необходимым и даже нежелательно. Но установление единого механизма конвертирования не представляется возможным. Существует противоречие между желанием эффективно "ужать" бинарные данные и желанием трансформировать данные, которые, хотя бы частично являются 7-битным текстом, так, чтобы их все-таки можно было читать. По этой причине необходимы по крайней мере 2 механизма конвертации: "читабельный" и "плотно ужимающий".

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

 

конвертация := "Content-Transfer-Encoding" ":" механизм механизм := "7bit" ; / "quoted-printable" / "base64" / "8bit" / "binary" / x-token

Значения не чувствительны к регистру букв, то есть, Base64, BASE64 и bAsE64 - одно и то же. Значение "7BIT" означает, что тело письма уже имеет 7-битный формат и не тренбует дополнительной обработки для пересылки по почте. Это значение полагается по умолчанию, если поле заголовка Content-Transfer-Encoding отсутствует.

Значения "8bit", "7bit" и "binary" означают, что никакой трансформации содержимого не производится. Однако, они сделаны различными для индикации того, что из себя представляет содержимое письма, и, соответственно, способа обработки, который может потребоваться для данной транспортной системы. В частности:

"7bit" означает, что данные являются текстом, имеют короткие строки и языковую кодировку US-ASCII.

"8bit" означает короткие строки, но в них могут содержаться не-ASCII символы (128-255).

"Binary" означает, что тело письма может содержать не-ASCII символы, но строки могут быть произвольной длины, т.е. слишком длинными для SMTP-транспорта, и может несоблюдаться соглашение по признаку конца строки (CRLF), принятое в SMTP-транспорте.

Хотя на первый взгляд разница в значениях Content-Transfer-Encoding может показатся неважной - ведь все они означают, что никакого преобразования нет, но четкая разметка важна для почтовых шлюзов между разными почтовыми системами, имеющими разные возможности и особенности работы, число которых со временем растет.

Спецификация на почтовый транспорт для пересылки некодированных 8-битных данных дана в RFC-1426. Однако, нет стандартизованных транспортов рочты Internet, для которых является приемлимым включение в тело письма некодированных двоичных данных. Таким образом, значение "binary" фактически не является легальным в Internet. Но в соответствии с MIME, при использовании почтовой системой транспорта, умеющего работать с двоичными данными, в случае, когда необходимо послать двоичные данные по e-mail, необходимо указать это в заголовке в поле Content-Transfer-Encoding.

Пять значений, определенных для поля Content-Transfer-Encoding, ничего не говорят о типе содержимого кроме указания алгоритма кодирования либо требований к почтовому транспорту в случае некодированных данных.

Производители почтового ПО, если необходимо, могут определить новые значения поля Content-Transfer-Encoding, но эти значения должны иметь префикс "X-" ("x-"), чтобы подчеркнуть их нестандартный характер. Однако, в отличие от типов и подтипов поля Content-Type, введение новых значений Content-Transfer-Encoding настоятельно не рекомендуется, так как может оказаться помехой для взаимосовместимости почтовых систем. Использование X-значений позволяется только как результат взаимосоглашения между взаимодействующими системами.

Если поле Content-Transfer-Encoding появляеися в заголовке тела какой-то части письма, оно применяется только к содержимому этой части. Если письмо (часть письма) имеет тип "multipart" или "message", то поле Content-Transfer-Encoding может иметь в качестве своего значения только длину символа ("7bit", "8bit" и т.д.) или "binary".

Необходимо заметить. что электронная почта является символьно-ориентированной, так что механизмы конвертации работают с данными как с потоком символов, а не битов. Если битовый поток должен быть кодирован посредством какого-либо из этих механизмов, сначала он должен быть конвертирован в 8-битный поток байтов, используя порядок битов, стандартный для сетей (старшие разряды в конце). То есть, передние биты в потоке становятся битами высшего порядка в байте. Если битовый поток оканчивается неполным байтом, недостающие разряды заполняются нулями.

Все кодирующие механизмы, определенные в спецификации MIME, кодируют любые данные в символьную форму. Так, к примеру, полагая, что тело письма (части письма) имеет поля заголовка вроде:

 

Content-Type: text/plain; charset=ISO-8859-1 Content-transfer-encoding: base64

то это означает, что тело письма представляет собой ASCII-код base64 текстовых данных, которые в нормальном виде имеют языковую кодировку ISO-8859-1, и будут в этой языковой кодировке после декодирования.

Все множество определенных значений поля content-transfer-encoding кроме начинающихся с префикса "X-", зарезервировано в IANA для будущего использования. Частные соглашения по значениям content-transfer-encoding также настоятельно не рекомендуются.

Некоторые значения Content-transfer-encoding могут использоваться только с определенными типами (поле Content-Type). В частности, запрещено использовать любые значения кроме "7bit", "8bit", или "binary" с любым типом, рекурсивно включающим заголовки с полем Content-Type (как правило, это типы "multipart" и "message"). Все кодирования, необходимые для содержимого тел многочастного письма должны быть произведены на более низком уровне.

 

Замечания по ограничениям конвертации:

Необходимо предотвращать случаи вложенного кодирования, когда данные проходят через алгоритм конвертации несколько раз и должны столько же раз быть декодированы, чтобы быть читаемыми. Вложенное кодирование добавляет сложностей пользовательским почтовым программам: кроме очевидных проблем с множественной конвертацией, они могут скрыть основную структуру письма. В частности, они могут привести к тому, что несколько операций по декодированию могут потребоваться только для того, чтобы определить, объекты каких типов находятся в письме. Запрещение вложенного кодирования может осложнить работу некоторых почтовых шлюзов, но это будет меньшей проблемой по сравнению с трудностями для пользовательских почтовых программ.

ЗАМЕЧАНИЕ ПО ПЕРЕВОДУ КОДОВ: Конверторы quoted-printable и base64 разработаны так, что данные после их применения легко взаимоконвертируемы. Единственный нюанс, возникающий в подобной ретрансляции - признак конца строки. При конвертации из quoted-printable в base64 перевод строки должен быть заменен последовательностью CRLF. Соответственно и наоборот, но ТОЛЬКО при конвертации текстовых данных.

 

5.1. Механизм конвертации "Quoted-Printable"

Этот механизм предназначен для представления данных, в основном состоящих из байтов, соответствующих символам, имеющим изображение в символьном наборе ASCII. В результате данного кодирования все байты будут иметь такие значения, гарантированные от дальнейшей модификации почтовым транспортом. Если конвертируемые данные в основном представляют собой ASCII-текст, то конечная их форма остается узнаваемой и читаемой для человека. Тело, полностью состоящее из ASCII-символов, также может быть конвертироавано в Quoted-Printable, что гарантирует его содержимому целостность при прохождении через всякие шлюзы, в которых происходит языковая перекодировка символов или преобразование концов строк и т.д.

В Quoted-Printable байты должны быть рпедставлены в соответствии со следующими правилами:

ПРАВИЛО #1: (обычное 8-битное представление). Каждый байт, кроме тех, которые используются для обозначения конца строки, может быть представлен с помощью двух шестнадцатиричных цифр, предворяемых знаком "=". При написании шестнадцатиричных цифр с A по F должны использоваться заглавные буквы. Кроме тех случаев, когда нижеследующие правила позволяют альтернативное кодирование, данное правило является обязательным.

ПРАВИЛО #2: (Буквенное представление). Байты с десятичным значением с 33 по 60 и с 62 по 126 МОГУТ быть представлены ASCII-символами, соответствующими этим значениям (с '!' по '<' и с '>' по '~').

ПРАВИЛО #3: (Пробелы): Байты со значениями 9 и 32 МОГУТ быть представлены как ASCII-символы "Табуляция" и "Пробел", но НЕ ДОЛЖНЫ быть представлены так в конце строки. Везде, где они представлены соответствующими ASCII-символами, за ними должен следовать символ, имеющий графическое изображение (печатный символ). В конце же строки символы табуляции и пробела должны быть представлены в соответствии с правилом #1, так как некоторые почтовые транспорты могут убирать пробелы в конце строки.

ПРАВИЛО #4: (Конец строки): Конец строки в тексте письма должен быть представлен (в соответствии с RFC 822) последовательностью CRLF. Так как в каноническом представлении текста не требуется визуального отображения символов конца строки, в Quoted-Printable не используется видимых символов для обозначения конца строки. Для представления бинарных данных более предпочтительной является кодировка base64.

Необходимо заметить, что многие реализации почтовых программ могут кодировать по-своему. В частности, при представлеии текста в системах, использующих другие соглашения по обозначению конца строки (отличные от CRLF). Такие реализации недопустимы, и генерация концов строки должна быть стандартизована везде, чтобы не требовалось распознавать, используется ли какое-либо альтернативное представление.

ПРАВИЛО #5: (Мягкий конец строки): В соответствии с Quoted-Printable длина строки не должна превышать 76 символов. В противном случае используется 'мягкий' перевод строки, представимый знаком равенства. Например, если исходная строка имела вид:

 

Now's the time for all folk to come to the aid of their country.

то в Quoted-Printable encoding он может быть представлена следующим образом:

 

Now's the time = for all folk to come= to the aid of their country.

Это обеспечивает механизм восстановления исходной длины строки пользовательским почтовыи агентом.

Поскольку символ дефиса ("-") представляется в Quoted-Printable в обычном виде, особую осторожность нужно соблюдать при заключении тела в Quoted-Printable в многочастное письмо, чтобы удостовериться, что граница этого включения не проявляется нигде внутри этого включения (лучше всего выбрать обозначение границы в виде последовательности символов "=_", которая никогда не появляется в теле, закодированном в Quoted-Printable. См. определение многочастного письма далее.)

ЗАМЕЧАНИЕ: Quoted-Printable представляет собой нечто вроде компромисса между читабельностью и сохранностью при пересылке. Тела в Quoted-Printable будут надежно защищены при прохождении многих почтовых шлюзов, но могут быть не очень хорошо переданы через некоторые шлюзы, использующие трансляцию в EBCDIC. (Теоретически, EBCDIC-шлюз должен кодировать тело из quoted-printable в base64 и затем декодировать обратно, но таких шлюзов пока не существует). Единственный способ добится действительно надежной транспортировки через EBCDIC-шлюз - экранировать ASCII-символы

 

!"#[email protected][]^`{|}~

в соответствии с правилом #1.

Так как данные в quoted-printable являются строчно-ориентированными, можно ожидать, что представление концов строки в Quoted-Printable будет изменено почтовым транспортом таким же образом, как и обычный текст может измениться при пересылке по Internet-почте между системами с разными соглашениями по представлению концов строки. Если подобные изменения могут нарушить целостность данных, то имеет смысл пользоваться кодировкой base64, а не Quoted-Printable.

Вниманию создателей ПО: Если двоичные данные пересылаются в Quoted-Printable, то надо соблюдать осторожность при кодировании символов CR и LF. В частности, последовательность CRLF должна быть представлена как "=0D=0A", в противном случае, если CRLF означает конец строки, то она может быть неверно интерпретирована в платформах с другими соглашениями по концу строки.

Синтаксис данных в quoted-printable описывается следующим образом:

 

quoted-printable := ([*(простой текст / ПРОБЕЛ / ТАБУЛЯЦИЯ) простой текст] ["="] CRLF) ; Максимальная длина строки - 76 символов, включая CRLF простой текст := байт /<любой ASCII-символ "=", ПРОБЕЛ или ТАБУЛЯЦИЯ> ; символы, не перечисленные в приложении B к RFC 1521 как безопас- ; ные для почты, также не рекомендуются к использованию байт := "=" 2(ФИФРА / "A" / "B" / "C" / "D" / "E" / "F") ; байт используется для символов > 127, =, ПРОБЕЛ, или ТАБУЛЯЦИЯ, ; и рекомендуется для представления любых символов, не перечислен- ; ных в приложении B к RFC 1521 как безопасные для почты

 

5.2. Механизм конвертации Base64

Этот алгоритм разработан для представления произвольных последовательностей байтов в форму, читаемую для человека. Кодирующий и декодирующий алгоритмы очень просты, но закодированные данные примерно на 33% больше, чем некодированные. этот метод идентичен тому, который используется в приложениях PEM (Privacy Enhanced Mail), описанной в RFC 1421 с одним отличием: base64 не приемлит встроенного "чистого" текста.

Base64 использует 65-символьный поднабор из US-ASCII, выделяя 6 бит на каждый печатный символ. (65-й символ "=" используется для обозначения функции спец. обработки).

ПРИМЕЧАНИЕ: этот поднабор имеет важное свойство: он идентичен всем версиям языковой кодировки ISO 646, включая US ASCII, а также всем версиям EBCDIC. Другие популярные механизмы кодирования (uuencode, base85 - часть уровня 2 PostScript) не разделяют этих свойств и поэтому не удовлетворяют требованиям переносимости для двоичных данных электронной почты.

Процесс кодирования преобразует 4 входных символа в виде 24-битной группы, обрабатывая их слева направо. Эти группы затем рассматриваются как 4 соединенные 6-битные группы, каждая из которых транслируется в одиночную цифру алфавита base64. При кодировании base64, входной поток байтов должен быть упорядочен старшими битами вперед.

Каждая 6-битная группа используется как индекс для массива 64-х печатных символов. Символ, на который указывает значение индекса, помещается в выходную строку. Эти символы выбраны так, чтобы быть универсально представимыми и исключают символы, имеющие специальное значение для SMTP-транспорта (".", CR, LF) и для синтаксиса вложенных тел MIME ("-").

 

Таблица 1: Алфавит Base64 Значение Код Значение Код Значение Код Значение Код 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w = (заполнитель) 15 P 32 g 49 x 16 Q 33 h 50 y

Выходной поток (закодированные бфайты) должен иметь длину строк не более 76 символов. Все признаки перевода строки и другие символы, отсутствующие в таблице 1, должны быть проигнорированы декодером base64. Среди данных в Base64 символы, не перечисленные в табл. 1, переводы строки и т.п. должны говорить об ошибке передачи данных, и, соответственно, почтовая программа должна оповестить пользователя о ней.

Если в хвосте потока кодируемых данных осталось меньше, чем 24 бита, справа добавляются нулевые биты до образования целого числа 6-битных групп. А до конца 24-битной группы остается от 0 до 3-х недостающих 6-битных групп, вместо каждой из которых ставится символ-заполнитель '='. Поскольку весь входной поток представляет собой целое число 8-битных групп (т.е., просто байтных значений), то возможны лишь следующие случаи: (1) входной поток как раз оканчивается 24-битной группой. В таком случае, выходной поток будет оканчиваться четырьмя символами Base64 без символа '='; (2) хвост входного потока имеет длину 8 бит. Тогда в конце выходного кода быдут два символа Base64, с добавлением двух символов '='; (3) хвост входного потока имеет длину 16 бит. Тогда в конце выходного будут стоять три символа Base64 и один символ '='.

Т.к. символ '=' является хвостовым заполнителем, его появление в теле письма может означать только то, что конец данных достигнут. Но такой гарантии нет, если число переданных битов кратно 24.

Любые бессмысленные последовательности в коде Base64 вроде "=====" должны быть игнорированы.

Если кодируемый текст не находится в канонической форме. то перед конвертацией в Base64 необходимо сначала все концы строк заменить стандартной последовательностью CRLF. Предпочтительнее эту функцию встроить в кодировщик Base64, нежели заставлять пользователя производить предварительную канонизацию текста другими средствами.

Нет нужды экранировать вложенные тела внутри многочастного тела (multipart) при кодировании его в Base64, так как в коде Base64 отсутствует символ '-'.

 

6. Дополнительные Content- поля заголовка

 

6.1. Необязательное поле Content-ID

При создании почтового агента верхнего уровня может быть желательно позволить одному телу иметь ссылку на другое. Для этого поля могут быть помечены с помощью поля заголовка "Content-ID", синтаксически идентичного полю "Message-ID":

 

идентификатор := "Content-ID" ":" идентификатор письма

Как и значения поля Message-ID, значения поля Content-ID должны быть абсолютно уникальными (для всего мира).

Такой идентификатор может быть использован для идентификации тела письма (части письма) в нескольких контекстах, в часности, для кэширования данных, указываемых с помощью механизма message/external-body. Хотя поле Content-ID является необязательным в общем случае, его использование необходимо в реализациях, генерирующих данные, имеющие дополнительный тип "message/external-body" (поле Content-type). Каждое тело такого типа должно обязательно иметь в своем заголовке поле Content-ID для обеспечения ссылки на такие данные.

Значение поля Content-ID имеет специальную семантику в случае типа multipart/alternative. (См. соотв. пункт).

 

6.2. Необязательное поле Content-Description

Возможность ассоциировать некоторую описательную информацию с данными часто очень желательна. например, может быть полезным описать тело, содержащее графическое изображение, как "a picture of the Space Shuttle Endeavor." Этот текст и может быть помещен в поле заголовка Content-Description.

 

описание := "Content-Description" ":" *текст

Описание должно иметь языковую кодировку US-ASCII, хотя механизм, определенный в RFC-1522 может быть использован для не-US-ASCII значений.

 

7. Предопределенные значения поля Content-Type

 

7.1 Тип 'Text'

Тип 'text' предназначен для пересылки текстовых материалов. Это значение поля - по умолчанию. Для обозначения языковой кодировки текста используется параметр "charset" для некоторых подтипов, включая основной подтип, "text/plain", соответствующий простому (неформатированному) тексту. В Internet'овской почте значением Content-Type по умолчанию является следующее: "text/plain; charset=us-ascii". Если текст является размеченным и нет соответствующего ПО для корректного визуального представления этого текста пользователю, имеет смысл сообщить ему подтип этих текстовых данных.

 

7.1.1. Параметр 'charset'

В отличие от других значений, значения этого параметра не являются чувствительными к регистру букв.

Спецификации любых новых подтипов типа 'text' должны определять, будет ли этот новый подтип использовать параметр "charset" либо наоборот, будет запрещать его использование. Любое тело, не содержащее внутри себя других, должно целиеом быть в одной языковой кодировке. В частности, создатели новых подтипов должны уделить внимание многбайтным символьным наборам.

Дополнительно к предопределенным новые языковые кодировки могут быть зарегистрированы через IANA, хотя стандартизация их использования требует опробирования IESG (см. RFC-1340). Если используется 8-битная языковая кодировка (например, koi8 или cp866), то необходимо наличие поля заголовка Content-Transfer-Encoding для обеспечения передачи через ряд протоколов, в частности, SMTP.

Необходимо заметить, что управляющие символы (0-31, 127), включая DEL, не имеют определенного значения за исключением последовательности CRLF (13,10), означающей конец строки. Два символа де-факто широко употребляются: FormFeed (12), означающий, что следующий за ним текст должен начинаться на новой странице; и TAB (9), часто, но не всегда означающий "перевести курсор на следующий ближайший столбец после данной позиции, где номер столбца кратен воьсми". Любое другое использование управляющих символов или DEL в теле должно быть в рамках частного соглашения между отправителем и получателем. Но такие соглашения крайне не рекомендуются и по возможности должны быть заменены другими возможностями MIME.

Существует огромное количество языковых кодировок, что не является положительным фактом. В дальнейшем предполагается ввести универсальную многобитную языковую кодировку, поддерживающую все языки мира. К сожалению, существующая практика говорит о том, что возможно, еще долгое время электронной почте придется иметь дело с многими кодировками. По этой причине предопределены имена для наиболее распространенных языковых кодировок:

 

  • US-ASCII
  • ISO-8859-X -- где "X" - цифра от 1 до 9 включительно, означающая номер версии кодировки ISO-8859

Параметр "charset" был определен в основном для текстовых данных, но возможно, для бинарных данных тоже может потребоваться указать языковую кодировку, в этом случае должен использоваться тот же синтаксис те же значения.

Почтовое программное обеспечение должно руководствоваться принципом наименьшего набора символов, то есть, если письмо пишется как-бы в восьмибитной ISO-8859-1, но в письме используются символы лишь некоторого поднабора, например, семибитного US-ASCII, то почтовая программа должна автоматически определить имя символьной кодировки как US-ASCII. В этом случае уменьшится нагрузка в сети и увеличаися шансы, что получатель прочтет письмо без искажений.

 

7.1.2. Подтип 'Text/plain'

Это основной подтип, соответствующий простому (неформатированному) тексту. Значение поля Content-Type для почты Internet по умолчанию - "text/plain; charset=us-ascii". Это тип данных, соответствующий RFC 822.

Других предопределенных подтипов для типа 'text' нет.

Формальный синтаксис для типа 'text':

 

тип := "text" "/" подтип [";" "charset" "=" имя языковой кодировки] подтип := "plain" / расширение (не предопределенный подтип) имя языковой кодировки:= "us-ascii"/ "iso-8859-1"/ "iso-8859-2" / "iso-8859-3" / "iso-8859-4"/ "iso-8859-5"/ "iso-8859-6" / "iso-8859-7" / "iso-8859-8" / "iso-8859-9" / расширение (не предопределенная кодировка)

 

7.2. Тип 'multipart'

Этот тип используется, если один или более различных наборов данных заключены в одном письме. Каждая часть тела должна иметь синтакс письма RFC 822 (то есть, иметь заголовок,ь пустую строку и тело), но должна иметь открывающую и закрывающую границы.

Часть письма не должна интерпретироваться как настоящее письмо RFC 822. Вообще, для части письма наличие заголовка не обязательно, так что она может начинаться и с пустой строки, но при этом, все признаки, описываемые в заголовке, имеют значение по умолчанию. Для частей письма имеют смысл только поля, описывающие содержимое, то есть. начтинающиеся с "Content-". Все остальные поля, необходимые в заголовке верхнего уровня, обычно игнорируются в частях письма при обработке почты, более того, в некоторых почтовых шлюзах они могут быть просто удалены. Для экспериментальных и частных целей могут использоваться "X-" поля, но информация, в них заложенная, может быть потеряна при прохождении некоторых почтовых шлюзов.

ЗАМЕЧАНИЕ: Различие между письмом RFC 822 и частью письма MIME является маленькой, но важной. Шлюз между почтой Internet и X.400, например, должен иметь возможность отличить часть письма, содержащую графическое изображение, от части письма, содежащей вложенное письмо, телом которого является графическое изображение. Для представления последнего соответствующая часть письма должна иметь "Content-Type: message" и ее тело после пустой строки должно являться вложенным письмом со своим собственным полем заголовка "Content-Type: image". Схожесть синтаксиса обеспечивает легкость конверсии от письма к части письма, но различие между ними должно быть усвоено производителями ПО.

Граница части письма не должна появляться внутри самой части письма.

Все существующие и будущие подтипы типа "multipart" должны иметь идентичный синтаксис. Они могут различаться своей семантикой. Это требование гарантирует, что совместимые пользовательские агенты смогут по крайней мере распознать и разделить части многочастного письма, даже имеющего неизвестный им подтип.

Как упомянуто в определении поля Content-Transfer-Encoding, использование других значений кроме "7bit", "8bit" или "binary" запрещено для типа "multipart". Почтовые шлюзы и другие почтовые агенты часто вносят изменения в заголовки верхнего уровня. В частности, они могут добавлять, убирать, переупорядочивать определенные поля. Такие изменения запрещены для заголовков частей письма, находяшихся внутри тела типа "multipart".

 

7.2.1. Multipart: общий синтаксис

Поле Content-Type многочастного письма требует одного параметра, "boundary", который определяет границы вложения. Границей является строка, состоящая из двух символов "-" (десятичный код 45) и значения параметра 'boundary' из поля заголовка Content-Type.

ЗАМЕЧАНИЕ: Два символа "-" используются для совместимости с более ранним методом вложения писем, описанным в RFC 934 и для облегчения поиска границ. Однако, многочастные письма MIME не полностью совместимы с RFC 934; в частности, они не подчиняются соглашению RFC 934 по экранированию строк символом "-", так как с каждым новым уровнем экранирования длина строк увеличивается. А поскольку SMTP-транспорты часто обрезают длинные строки, этот механизм становится неприменимым в случае многоуровневой структуры письма типа 'multipart'.

ВНИМАНИЮ ПРОИЗВОДИТЕЛЕЙ ПО: синтаксис параметров поля Content-Type таков, что зачастую необходимо значения границ в параметре 'boundary' заключать в кавычки. Это не всегда требуется, но никогда не повредит. Программистам следует изучить синтаксис внимательно, чтобы не допустить ошибок в поле Content-Type. Типичное поле Content-Type для типа 'multipart' может выглядеть следующим образом:

 

Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08jU534c0p

Но в следующем примере содержится ошибка:

 

Content-Type: multipart/mixed; boundary=gc0p4Jq0M:2Yt08jU534c0p

(из-за двоеточия), которая может быть исправлена следующим образом:

 

Content-Type: multipart/mixed; boundary="gc0p4Jq0M:2Yt08jU534c0p"

Это означает, что тело письма состоит из нескольких частей, каждая из которых соответствует синтаксису письма RFC 822, за исключением того. что область заголовка может быть абсолютно пустой и начальная граница каждой части отмечена последовательностью:

 

--gc0p4Jq0M:2Yt08jU534c0p

Нужно обратить внимание, что метка границы части письма должна располагаться в начале строки, то есть, сразу же после признака конца строки CRLF. Причем, последовательность CRLF полагается элементом метки границы, а не последним элементом тела предыдущей части (так как тело предыдущей части может неоканчиваться концом строки, что принципиально важно в случае бинарных данных. Если же тело предыдущей части оканчивается концом строки, то метке границы соответственно должны предшествовать два конца строки). Сразу за меткой границы должен следовать конец строки (CRLF), или при отсутствии заголовка следующей части письма, два конца строки.

Метка границы не должна иметь длину более 70 символов, не считая два начальных дефиса.

Метка границы, следующая за последней частью письма, должна отличаться от предыдущих меток, чтобы показать, что далее не последует другой части письма. Отличие последней метки состоит в добавлении двух дефисов в конец:

 

--gc0p4Jq0M2Yt08jU534c0p--

Обычно оставляется пространство для дополнительной информации перед первой меткой границы и после последней. Обычно его следует оставлять пустым, и обработчики почты должны игнорировать все, что в этом пространстве содержится.

ЗАМЕЧАНИЕ: Эти области приамбулы и эпилога обычно не используются из-за отсутствия точной семантики для обработки этих областей почтовыми шлюзами, однако, многие программные MIME-продукты считают удобным помещать туда пояснительную информацию для получателей, которые пользуются до-MIME'овским ПО. По этой причине, MIME-совместимые программы должны игнорировать эти области.

ЗАМЕЧАНИЕ: Поскольку метки границы не должны появляться внутри тел частей письма, почтовая программа, создающая письмо, должна иметь алгоритм, позволяющий автоматически подобрать уникальную последовательность, не встречающуюся в теле ни одной из частей, либо имеющую минимальную вероятность появления, если данные предварительно не сканируются на наличие таковой.

В качестве простого примера предлагается двухчастное письмо, вторая часть которого оканчивается признаком конца строки, а первая нет:

 

From: Nathaniel Borenstein To: Ned Freed Subject: Sample message MIME-Version: 1.0 Content-type: multipart/mixed; boundary="simple boundary" Это приамбула. Должна быть игнорирована --simple boundary Это простой ASCII-текст. Он НЕ оканчивается признаком конца строки. --simple boundary Content-type: text/plain; charset=us-ascii Это простой ASCII-текст. Он оканчивается признаком конца строки. --simple boundary-- Это эпилог. Тоже должен игнорироваться MIME-программами.

Часть письма, в свою очередь, также может иметь тип 'multipart', то есть. быть многочастным телом, но при этом метки границ, использующиеся во внешнем и во внутреннем multipart-телах, должны отличаться друг от друга.

Использование типа 'multipart' в одночастном письме может быть полезно в некоторых контекстах и не запрещено.

Единственным обязательным параметром для типа 'multipart' является параметр 'boundary', состоящий из 1-70 символов без хвостовых пробелов (которые могут быть удалены в процессе пересылки, и тогда почтовая программа получателя не сможет разделить вложенные части).

 

граница := 0*69<символов границы> символ_границы_кроме_пробела символ границы := символ_границы_кроме_пробела / " " символ_границы_кроме_пробела := ЦИФРА / БУКВА ЛАТИНСКОГО АЛФАВИТА / "'" / "(" / ")" / "+" /"_" / "," / "-" / "." / "/" / ":" / "=" / "?"

Общий вид многочастного тела - следующий:

 

многочастное тело := приамбула вложения признак_конца эпилог вложение := разделитель часть_тела CRLF разделитель := "--" метка_границы CRLF ; метка границы должна браться из поля Content-Type. ; Не должно быть пробелов между "--" и меткой границы. признак конца := "--" метка_границы "--" CRLF ; Опять, без пробела перед "--", приамбула := игнорируемый текст эпилог := игнорируемый текст игнорируемый текст := *(*текст CRLF) часть_тела := <письмо RFC 822, со всеми необязательными полями заголовка>

ЗАМЕЧАННИЕ: В некоторых транспортах такие ограничения RFC 822, как использование тольеко печатных символов в теле, могут не действовать. Ослабления таких ограничений должны быть истолкованы как локальные расширения определения тела письма настолько, насколько они поддерживаются почтовым транспортом и адекватно документированы в поле заголовка Content-Transfer-Encoding. Однако, ни при каких обстоятельствах в заголовках как письма, так и его частей, не должно содержаться каких-либо символов, кроме US-ASCII.

 

7.2.2. Основной подтип "multipart/mixed"

Это основной подтип для типа 'multipart', он предназначен для случая, когда части письма взаимонезависимы. Любые новые подтипы, неизвестные почтовой программе, должны быть истолкованы аналогично подтипу 'mixed'.

 

7.2.3. Подтип "multipart/alternative"

Этот подтип синтаксически идентичен предыдущему, но имеет несколько другую семантику.

Почтовые системы должны распознавать, что данные из разных частей взаимозаменяемы. Системы должны выбрать наиболее подходящий вариант для локальной платформы и других условий, в некоторых случаях, с согласия пользователя. Как и в предыдущем случае, порядок частей в письме существенен. В этом случае альтернативы располагаются в порядке уменьшения отличия от оригинала. Обычно, выбирается последняя часть (альтернатива) из тех, которые имеют тип, поддерживаемый локальной системой получателя.

Multipart/alternative может быть использована, к примеру, для пересылки текста в некотором гипотетическом формате:

 

From: Nathaniel Borenstein To: Ned Freed Subject: Formatted text mail MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=boundary42 --boundary42 Content-Type: text/plain; charset=us-ascii ... Здесь содержится версия простым текстом .... --boundary42 Content-Type: text/richtext .... Здесь содержится версия с разметкой RFC 1341 ... --boundary42 Content-Type: text/x-whatever .... Здесь содержится версия в гипотетическом формате ... --boundary42--

В этом примере пользователь, чья система понимает этот гипотетический формат, увидят именно эту версию, в то время как остальные будут видеть размеченный либо простой текст в зависимости от возможностей их системы.

Обычно пользовательский агент, создающий письмо в multipart/alternative, должны располагать альтернативные части в порядке увеличения предпочтительности формата, то есть, предполагая, что наш гипотетический формат является самым удобным для конкретных данных (иначе зачем было бы его изобретать?), пользовательский агент должен располагать альтернативу в простейшем формате первой, а самую размеченную последней. Агент получателя должен отобразить последнюю из понимаемых им альтернатив. В случае, если одна из альтернатив сама имеет тип 'multipart' и содержит подчасти неизвестных типов, пользовательский агент может выбрать, показывать ли эту альтернативу, предыдущую или обе.

ЗАМЕЧАНИЕ: С точки зрения программиста, может показаться более удобным располагать альтернативы в обратном порядке, но данный порядок позволяет устаревшим не-MIME'овским почтовым программам отобразить в первую очередь наиболее понятный вариант.

ЗАМЕЧАНИЕ ПО СЕМАНТИКЕ ПОЛЯ 'CONTENT-ID' В ПИСЬМЕ MULTIPART/ALTERNATIVE: Рекомендуется, чтобы каждая часть имела уникальное значение поля Content-ID в случае, если содержимое этих частей не является идентичным. Однако, там, где содержащаяся информация идентична (например, если несколько частей типа "application/external- body" определяют альтернативные пути доступа к одним и тем же внешним по отношению к письму данным), должно использоваться одно и то же значение Content-ID, чтобы оптимизировать работу кэширующего механизма на системе получателя. Однако, не рекомендуется, чтобы значения Content-ID, использующиеся для частей, отличались от значения Content-ID, использующегося в заголовке верхнего уровня, если такое поле в нем присутствует.

 

7.2.4. Подтип "multipart/digest"

Этот подтип идентичен подтипу 'multipart/mixed', но имеет другую семантику. Например, для 'digest' значением по умолчанию является не "text/plane", а "message/rfc822".

В соответствии с этим подтипом, письмо-дайджест может выглядеть следующим образом:

 

From: Moderator-Address To: Recipient-List MIME-Version: 1.0 Subject: Internet Digest, volume 42 Content-Type: multipart/digest; boundary="---- next message ----" ------ next message ---- From: someone-else Subject: my opinion ... тело вложенного письма ... ------ next message ---- From: someone-else-again Subject: my different opinion ... тело другого вложенного письма ... ------ next message ------

 

7.2.5. Подтип "multipart/parallel"

Отличие этого подтипа от "multipart/mixed", в частности, состоит в том, что порядок расположения частей письма не принципиален.

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

 

7.2.6. Другие подтипы типа "multipart"

В будущем ожидается введение новых подтипов. Программистам рекомендуется интерпретировать незнакомые подтипы типа 'multipart' аналогично "multipart/mixed".

Формальный синтаксис поля Content-Type для данных типа "multipart":

 

multipart-тип := "multipart" "/" multipart-подтип ";" "boundary" "=" метка_границы multipart-подтип := "mixed" / "parallel" / "digest" / "alternative" / подтип-расширение

 

Полный пример Multipart-письма

Данный пример иллюстрирует письмо из пяти частей: две - простой текст, одна - вложенное multipart-письмо, одна - размеченный текст и одна - вложенное письмо, содержащее текст в не-US-ASCII языковой кодировке. Третья часть (вложенное multipart-письмо) состоит из двух частей, требующих параллельного представления пользователю, - графическое изображение и звуковой фрагмент.

 

MIME-Version: 1.0 From: Nathaniel Borenstein To: Ned Freed Subject: A multipart example Content-Type: multipart/mixed; boundary=unique-boundary-1 Это область преамбулы multipart-письма. Почтовые программы, понимающие формат multipart, должны игнорировать все, что в ней находится. Если же вы при получении подобного письма видите этот текст на экране, вам следует сменить почтовую программу. --unique-boundary-1 ...Здесь находится некоторый текст... [Обратите внимание, что предшествующая пустая строка означает, что поля заголовка не были заданы, и это - простой текст в языковой кодировке US ASCII.] --unique-boundary-1 Content-type: text/plain; charset=US-ASCII Это часть предыдущей части, но иллюстрирующая ясную, а не подразумеваемую типизацию содержимого. --unique-boundary-1 Content-Type: multipart/parallel; boundary=unique-boundary-2 --unique-boundary-2 Content-Type: audio/basic Content-Transfer-Encoding: base64 ... кодированный в base64 одноканальный звуковой фрагмент для час- тоты 8000 Hz в формате mu-law.... --unique-boundary-2 Content-Type: image/gif Content-Transfer-Encoding: base64 ... здесь находится кодированное в base64 графическое изображение.... --unique-boundary-2-- --unique-boundary-1 Content-type: text/richtext Это текст с разметкой в соответствии с определением RFC 1341 Неправда ли, он крут? --unique-boundary-1 Content-Type: message/rfc822 From: (имя отправителя в US-ASCII) To: (адрес в US-ASCII) Subject: (subject в US-ASCII) Content-Type: Text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: Quoted-printable ... Некоторый текст в ISO-8859-1 ... --unique-boundary-1--

 

7.3. Тип 'message'

При пересылке почты часто возникает необходимость включить внутрь письма другое письмо. Для этого и используется тип 'message'.

Основной подтип - "rfc822" - не требует параметров в поле Content-Type. Дополнительные подтипы - "partial" и "External-body" - предполагают наличие параметров.

ЗАМЕЧАНИЕ: Для перенаправляемой и возвращаемой почты можно было бы определить отдельные подтипы, однако, такая почта может пересылаться как multipart-письмо, в котором первая часть содержит некоторую пояснительную текстовую информацию, а другая, имеющая тип 'message/rfc822', содержит перенаправляемое/возвращаемое письмо. Подобный способ перенаправления/возвращения почты сохраняет информацию о типе оригинального письма и позволяет ему быть корректно представленным получателю, и поэтому настоятельно рекомендуется.

 

7.3.1. Основной подтип 'message/rfc822'

Этот подтип указывает, что тело письма содержит вложенное письмо в стандарте RFC 822, однако, в отличие от заголовка RFC 822 верхнего уровня, для каждой части, являющейся письмом RFC 822, не требуется наличия полей "From", "Subject" и, по крайней мере, одного поля "To".

Не смотря на использование числа "822", тело, имеющее подтип 'message/rfc822', может включать дополнительную информацию в соответствии со стандартом MIME. Другими словами, письмо 'message/rfc822' может быть MIME-письмом.

 

7.3.2. Подтип 'message/partial'

Этот подтип определен с целью обеспечения возможности пересылки очень больших объектов в виде нескольких раздельных частей, автоматичски "склеиваемых" почтовой программой получателя. Этот механизм может пригодиться, когда промежуточные почтовые шлюзы ограничивают индивидуальный размер пересылаемых писем. Т.о., этот подтип говорит о том, что письмо содержит лишь часть большого послания.

Для этого подтипа необходимо указание трех параметров:

 

  1. "id" - уникальный идентификатор, позволяющий обнаружить остальные части послания.
  2. "number" - целое число, означающее номер части послания.
  3. "total" - целое число, означающее общее количество частей. Требуется лишь в последней части и не обязателен (хотя рекомендуется) для предыдущих частей. Эти параметры могут следовать в произвольном порядке.

Пример: часть 2 3-х частного послания имеет следующие варианты заголовка:

 

Content-Type: Message/Partial; number=2; total=3; Content-Type: Message/Partial; ; number=2

Но часть 3 обязательно должна содержать параметр "total":

 

Content-Type: Message/Partial; number=3; total=3;

Необходимо заметить, что нумирация частей начинается с 1, а не с 0.

Когда подобным образом разбитые части собираются вместе, они образуют полное MIME-письмо, содержимое которого может иметь любой другой тип и, соответственно, свое поле заголовка Content-Type, описывающее этот тип.

Семантика partial-письма должна быть та же, как в обычном письме с содержимым данного типа, а не как в письме, содержащем "внутреннее" письмо. Это позволяет, например, переслать большой аудио-файл ввиде нескольких более мелких, остающихся, тем не менее, видимыми получателю как обычные аудио-письма, а не как вложенные аудио-письма.

При "сборке" таких посланий в пункте назначения должны учитываться следующие правила:

(1) Все поля заголовка части 1, кроме начинающихся с "Content-" и специальных "Message-ID", "Encrypted" и "MIME-Version" должны быть скопированы в заголовок нового (общего) письма.

(2) Только поля заголовка ВЛОЖЕННОГО письма, начинающиеся с "Content-", а также поля "Message-ID", "Encrypted" и "MIME-Version", должны быть добавлены к заголовку нового общего письма, все остальные поля должны игнорироваться.

(3) Заголовки второй и последующих частей целиком игнорируются.

Например, если письмо с аудио-данными было разбито на две части, первая из них может выглядеть следующим образом:

 

X-Weird-Header-1: Foo From: [email protected] To: [email protected] Subject: Audio mail Message-ID: MIME-Version: 1.0 Content-type: message/partial; ; number=1; total=2 X-Weird-Header-1: Bar X-Weird-Header-2: Hello Message-ID: MIME-Version: 1.0 Content-type: audio/basic Content-transfer-encoding: base64 ... здесь имеет место быть первая часть закодированных аудио-данных ...

А вторая может выглядеть так:

From: [email protected] To: [email protected] Subject: Audio mail MIME-Version: 1.0 Message-ID: Content-type: message/partial; ; number=2; total=2 ... здесь имеет место быть вторая часть закодированных аудио-данных ...

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

 

X-Weird-Header-1: Foo From: [email protected] To: [email protected] Subject: Audio mail Message-ID: MIME-Version: 1.0 Content-type: audio/basic Content-transfer-encoding: base64 ... первая часть закодированных аудио-данных ... ... вторая часть закодированных аудио-данных ...

Замечание по кодированию тела MIME-письма, заключенного внутри тела message/partial: так как данные типа "message" никогда не могут быть кодированы в Base64 или Quoted-Printable, следующая проблема может возникнуть в случае, если тела писем типа message/partial созданы в системе, поддерживающей 8-битный транспорт. Двоичные данные будут разбиты на несколько message/partial-объектов, каждому из которых требуется транспортировка в двоичном виде. Если бы таким объектам пришлось пройти через шлюз в 7-битную транспортную среду, их невозможно было бы перекодировать в сеимбитную форму без ожидания прибытия всех частей послания, собирания их воедино и затем кодирования целого послания в 7-битную кодировку (base64 или quoted-printable). Поскльку существует вероятность, что разные части пойдут разными путями (через различные шлюзы), то подобное решение не приемлимо. Поэтому MIME определяет, что письма типа message/partial должны иметь 7-битную кодировку и соответствующее ей значение поля content-transfer-encoding. Даже для систем с транспортом, поддерживающим "8-бит" и "binary", запрещается их использование для данных message/partial.

Многие почтовые агенты могут автоматически фрагментировать большие письма.

Включение поля "References" в заголовки второй и последующих частей, ссылающегося на идентификатор предыдущей части, может оказаться полезным для почтовых программ, понимающих и обрабатывающих ссылки. Однако, наличие этого поля не обязательно.

Поле заголовка "Encrypted" вышло из употребления, но вышеприведенные правила обеспечивают корректную его интерпретацию, если оно встречается при обработке фрагментов типа message/partial.

 

7.3.3. Подтип 'Message/External-Body' Этот подтип указывает на то, что тело не содержится в самом письме, а на него есть ссылка. Параметры подтипа описывают способ доступа к данным тела письма.

Письмо (часть письма) этого подтипа состоит из заголовка, двух последовательных концов строки и заголовка вложенного письма. Если встречается другая пара концов строки, она означает конец заголовка вложенного письма. Однако, поскольку тело вложенного письма является внешним, оно не следует за концом заголовка. Например,

 

Content-type: message/external-body; access- type=local-file; name="/u/nsb/Me.gif" Content-type: image/gif Content-ID: Content-Transfer-Encoding: binary ТЕЛА НЕТ!

Область в конце, которую можно назвать "призрачным телом", игнорируется для большинства писем подтипа 'external-body'. Однако, в нее можно помещать дополнительную информацию, как например, в случае, когда параметр 'access-type' равен "mail-server". Во всех остальных случаях призрачное тело игнорируется.

Единственный всегда обязательный параметр для 'message/external-body' - "access-type". Остальные параметры могут быть или не быть обязательными в зависимости от значения параметра "access-type".

Значение этого параметра - слово, нечувствительное к регистру букв, означающее механизм доступа, с помощью которого файл или данные могут быть получены. Значения могут быть следующими (но не ограничиваются этим рядом): "FTP", "ANON-FTP", "TFTP", "AFS", "LOCAL-FILE" и "MAIL-SERVER". Будущие возможные значения, кроме экспериментальных, начинающихся с "X-", должны быть зарегистрированы в IANA.

Дополнительно, следующие три параметра являются необязательными для всех способов доступа:

EXPIRATION -- Дата (RFC 822 "date-time" синтаксис допускает 4 цифры в этом поле), после которой существование внешних данных не гарантируется.

SIZE -- размер (в байтах) данных. Позволяет получателю решить, расходовать ли ресурсы на считывание внешних данных. Размер указывается для канонической формы данных (то есть, до применения каких-либо преобразований).

PERMISSION -- нечувствительное к регистру букв поле, говорящее о том, ожидается или нет, что клиент может перезаписывать данные. По умолчанию или когда этот параметр имеет значение "read", полагается, что клиент не имеет на это права, и что если данные однажды считаны, то больше они не понадобятся. Если PERMISSION имеет значение "read-write", любая локальная копия может рассматриваться не более как кэш. "read" и "write" - единственные предопределенные значения для PERMISSION.

Вложенные заголовки во ВСЕХ телах типа message/external-body ДОЛЖНЫ включать поле заголовка Content-ID для задания уникального идентификатора, указывающего на внешние данные.

Обозначения, описывающие данные типа external-body, такие как имена файлов или команды mail-сервера, должны быть в символьном наборе US-ASCII.

Как и для типа message/partial, тело типа message/external-body должно иметь значение content-transfer-encoding "7-bit" (по умолчанию). В частности, даже в системах, поддержиавющих 8-битный транспорт, применение content-transfer-encoding "8-bit" и "binary" запрещено для данных типа message/external-body.

 

7.3.3.1. Типы доступа "ftp" и "tftp"

Тип доступа по FTP или TFTP означает, что тело сообщения доступно как внешний файл по протоколу FTP [RFC-959] или TFTP [RFC-783] соответственно. Для этих типов доступа обязательны следующие дополнительные параметры:

NAME -- Имя файла, содержащего данные тела письма.

SITE -- Полный доменный адрес или псевдоним компьютера, с которого файл может быть получен по указанному протоколу.

Перед тем, как начнется считывание данных по FTP, пользователь обычно должен быть спрошен на предмет логина и пароля для машины, указанной в параметре 'site'. По причинам безопасности логин и пароль не указываются как параметры Content-Type и должны быть получены от получателя письма.

Дополнительно определены следующие необязательные параметры:

DIRECTORY -- каталог, содержащий тело письма на удаленной машине.

MODE -- Нечувствительное к регистру букв строка, указывающая режим передачи данных. Допустимые эначения для типа доступа TFTP:

NETASCII, OCTET и MAIL. Для типа доступа FTP: ASCII, EBCDIC, IMAGE и LOCALn, где n - десятичное целое число, обыч- но 8. Эти значения соответствуют типам представления A, E, I и Ln, определенным FTP-протоколом. Заметьте, что "BINARY" и "TENEX" не являются допустимыми значениями для параметра MODE. Вместо них должны использоваться "OCTET", "IMAGE" или "LOCAL8". Если параметр MODE отсутствует, значением по умолчанию является "NETASCII" для TFTP и "ASCII" для FTP.

 

7.3.3.2. Способ досупа "anon-ftp"

Этот способ доступа идентичен "ftp", за исключением того, что пользователю не требуется указывать свой логин и пароль для удаленной машины. FTP-протокол будет использоваться с логином "anonymous" и email-адресом получателя вместо пароля.

 

7.3.3.3. Способы доступа "local-file" и "afs"

Способ доступа "local-file" означает, что тело письма доступно как файл на локальной машине. "afs" означает, что тело доступно как файл через общую файловую систему AFS. В обоих случаях требуется единственный обязательный параметр:

NAME -- Имя файла, содержащего данные тела письма.

Следующий необязательный параметр может быть использован для локализации ссылки на файл и содержит адрес сайта или сайтов, на которых данный файл виден:

SITE -- Доменный адрес машины или машин, на которых возможен доступ к файлу данных. Допускаются маски с использованием звездочки вместо части доменного имени, например, "*.bellcore.com", для обозначения набора машин, на которых файл виден напрямую. Единственная звездочка вместо всего доменного имени может означать, что файл, где би он ни был, виден через глобальную файловую систему.

 

7.3.3.4. Способ доступа "mail-server"

Применяется, когда тело письма доступно через почтовый сервер. Обязательный параметр для этого способа доступа:

SERVER -- email-адрес mail-сервера, с которого могут быть запрошены данные тела письма.

Так как почтовые серверы предполагают множество различных синтаксисов, некоторые из них могут быть многострочными, полная команда, которую нужно послать на mail-сервер, не включается как параметр в однострочное поле 'content-type'. Вместо этого она помещается в мнимое тело, когда значением поля 'content-type' является 'message/external-body', и параметр 'access-tyoe' имеет значение 'mail-server'.

Необязательный параметр для этого способа доступа:

SUBJECT -- Subject, который будет использован в заголовке письма-запроса, которое почторый клиент получателя пошлет на указанный почтовый сервер для получения данных тела письма. Заметьте, что помещение адреса сервера в subject не рекомендуется, однако, известны mail-серверы, требующие этого.

MIME-стандарт не определяет синтаксиса обращения к почтовому серверу. Поэтому он допускает включение полной команды для mail-сервера в мнимое тело.

В отличие от других способов доступа, доступ через mail-сервер не синхронен, и данные могут быть получены в непредсказуемый момент в будущем. По этой причине важно иметь механизм, обеспечивающий вставку полученных от mail-сервера данных в исходное письмо. Mail-сервер при отправке запрошенных данных должен использовать то же самое значение поля Content-ID в заголовке письма с возвращаемыми данными, какое было в первоначальном "бестелесном" письме, чтобы облегчить работу этого механизма.

 

7.3.3.5. Примеры и дополнительные пояснения

С появлением возможности очень широких (протяженных) файловых систем стало непредсказуемым, на каком наборе машин файловой системы данный файл будет доступен напрямую, а на каком - нет. Поэтому, имеет смысл указывать как имя файла, так и сетевой адрес (адреса) машин, на которых файл доступен.

Если внешнее тела письма доступно посредством нескольких различных механизмов, отправитель может включить несколько частей типа message/external-body в письмо типа multipart/alternative.

Однако, механизм external-body не должен быть ограничен получением удаленных файлов. Например, можно представить использование видеосервера с внешними ссылками на видеофрагменты.

Если письмо / часть письма имеет тип "message/external-body", то оно / она будет содержать поля заголовка вложенного письма. Тело само по себе неходится где-либо во вне. Это значит, что если тело типа "message/external-body" содержит два последовательных конца строки (CRLF), то все, что идет далее, не является чстью сообщения и просто должно игнорироваться. Однако, этот "хвост" - удобное место для каких-либо дополнительных данных, которые не могут быть помещены в поле заголовка Content-Type. В частности, если значение "access-type" есть "mail-server", то "хвост" может содержать команды, посылаемые затем mail-серверу по адресу, на который указывает параметр SERVER.

Поля заголовка вложенного письма, которые на самом деле являются телом общего письма типа "message/external-body", должны нести информацию о типе содержимого внешнего (удаленного) тела, если оно не является простым ASCII-текстом (что подразумевается по умолчанию), поскольку эти внешние данные сами по себе не имеют заголовка, опрпеделяющего их тип. Также, необходимо указывать Content-transfer-encoding, если он имеет значение, отличное от "7-bit". Так, полное письмо типа message/external-body, ссылающееся на документ в формате PostScript, может выглядеть следующим образом:

 

From: Whomever To: Someone Subject: whatever MIME-Version: 1.0 Message-ID: Content-Type: multipart/alternative; boundary=42 Content-ID: --42 Content-Type: message/external-body; name="BodyFormats.ps"; site="thumper.bellcore.com"; access-type=ANON-FTP; directory="pub"; mode="image"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: --42 Content-Type: message/external-body; name="/u/nsb/writing/rfcs/RFC-MIME.ps"; site="thumper.bellcore.com"; access-type=AFS expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: --42 Content-Type: message/external-body; access-type=mail-server server="[email protected]"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: get RFC-MIME.DOC --42--

В приведенных примерах значение Content-transfer-encoding для внешних данных в формате postscript полагается по умолчанию как "7bit".

Заголовки общего и вложенного(их) писем (имеющих внешнее тело) должны удовлетворять тем же правилам, что и для типа message/partial во избежание путаницы.

Поскольку внешнее тело не пересылается в виде почты, то оно не обязано удовлетворять требованиям длины строк и иметь 7-битную форму, оно может быть просто бинарным файлом. Поэтому поле Content-Transfer-Encoding не является необходимым, хотя его наличие допускается.

Тело письма типа "message/external-body" обрабатывается в сответствии с основным синтаксисом стандарта RFC 822, в частности, все, что идет до первой последовательной пары концов строки (CRLF), является заголовком письма, а все, что идет после, является "мнимым" телом письма, которое игнорируется для большинства типов доступа.

Формальный синтаксис поля заголовка 'content-type' для данных типа 'message' - следующий:

 

message_тип := "message" "/" message_подтип message_подтип := "rfc822" / "partial" 2-3 partial_параметра / "external-body" 1 external_параметр / расширение (не предопределенный подтип) partial_параметр := (";" "id" "=" значение) / (";" "number" "=" 1*ЦИФРА) / (";" "total" "=" 1*ЦИФРА) ; id и number требуются всегда; total требуется для последнего фрагмен- ; та послания. external_параметр := (";" "access-type" "=" тип_доступа) / (";" "expiration" "=" дата-время) ; Дата-время должны быть экранированы кавычками / (";" "size" "=" 1*Цифра) / (";" "permission" "=" ("read" / "read-write")) ; Значение permission нечувствительно к регистру букв / (";" "name" "=" значение) / (";" "site" "=" значение) / (";" "dir" "=" значение) / (";" "mode" "=" значение) / (";" "server" "=" значение) / (";" "subject" "=" значение) ; access-type требуется всегда; все остальное - в зависимости от значе- ; ния access-type тип_доступа := "ftp" / "anon-ftp" / "tftp" / "local-file" / "afs" / "mail-server" / / расширение (непредопределенный параметр) ; Нечувствителен к регистру букв

 

7.4. Тип 'Application'

Этот тип используется для данных, неподпадающих под остальные категории, в частности, для данных, обрабатываемых прикладными почтовыми программами. Это информация, которая должна быть обработана соответствующим приложением для того, чтобы принять наглядную либо исполняемую для получателя форму. Предполагаемое использование для этого типа включает в себя пересылку файлов по почте, таблицы, данные для почтовых систем расписания, языки лдя "активной" (вычислительной) почты. (Последняя, в частности, может поднять проблемы безопасности, которые должны быть поняты разработчиками ПО и рассмотрены ниже в параграфе "Application/PostScript").

Например, тот, кто занимается расписанием встреч, может определить стандартное представление информации о датах запланированных встреч. "Умный" пользовательский почтовый агент может использовать эту информацию для проведения диалога с пользователем, и может затем посылать в дальнейшем почту, основанную на том диалоге. Вообще, существует несколько "активных" почтовых языков, разработанных для специализированных программ, которые посылаются по почте и автоматчески запускаются в системе получателя.

Подобные приложения могут быть определены как подтипы для типа "application". Изначально предопределено два подтипа: "octet-stream" и "PostScript".

В общем, подтип для 'application' зачастую может быть именем приложения, для которого предназначены пересылаемые данные. Однако, это не означает, что любое имя прикладной программы может свободно использоваться как подтип для 'application'. Такие употребления (кроме подтипов, начинающихся с "x-") должны быть зарегестрированы в IANA.

 

7.4.1. Основной подтип 'Application/Octet-Stream'

Используется для обозначения того, что тело содержит бинарные данные. Набор возможных параметров включает следующие (но не ограничивается ими):

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

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

Дополнительный параметр, "conversions", определенный в [RFC-1341], был исключен в последствии.

В RFC 1341 также определен параметр "NAME", указывающего имя файла, которое должно быть использовано при сохранении данных на диск. Но он опять же был отменен в ожидании введения отдельного поля заголовка Content-Disposition, которое будет определено в ближайшем будущем.

Рекомендуемое действие для почтовой программы, получившей почту типа application/octet-stream, - просто предложить записать данные в файл без какого-либо преобразования, или. возможно, произвести его в соответствии с указанием пользователя.

Для уменьшения опасности передачи вирусных и других намеренно разрушающих систему программ по почте, строго рекомендуется, чтобы почтовая программа получателя не производила запуск программы, заданной в параметре поля "Content-Type" (например, в параметре "interpreter="), использующей в качестве входных данных тело письма.

 

7.4.2. Подтип 'Application/PostScript'

Тип "application/postscript" означает, что пересылается PostScript-документ и требует специальной программы для его обработки. В настоящий момент используются два языка - level 1 и более поздний - level 2.

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

В некоторых интерпретаторах PostScript могут иметь место ошибки, которые могут быть использованы хакерами для несанкционированного доступа к системе получателя, и нельзя предложить какого-либо специфического действия для предотвращения подобной возможности, кроме исправления со временем подобных ошибок (если они, конечно, есть) производителями соответствующего ПО.

 

7.4.3. Другие подтипы типа Application

Ожидается, что многие подтипы типа 'Application' будут введены в будущем. MIME-совместимые почтовые программы должны интерпретировать любой незнакомый им подтип как эквивалент 'application/octet-stream'.

Формальный синтаксис дла поля 'content-type' для данных типа 'application' дается следующим образом.

 

application_тип := "application" "/" application_подтип application_подтип := ("octet-stream" *stream_параметр) / "postscript" / расширение (непредопределенный под- тип) stream_параметр := (";" "type" "=" значение) / (";" "padding" "=" число_дополняющих_битов) число_дополняющих_битов := "0" / "1" / "2" / "3" / "4" / "5" / "6" / / "7"

 

7.5. Тип 'Image'

Этот тип означает, что тело письма содержит графический объект. Его подтипы соответствуют конкретным графическим форматам. Их значения нечувствительны к регистру букв. Два предопределенных подтипа - "jpeg" для формата JPEG с кодированием JFIF, и "gif" - для формата GIF.

Формальный синтаксис поля 'Content-Type':

 

image_тип := "image" "/" ("gif" / "jpeg" / подтип-расширение)

 

7.6. Тип 'Audio'

Этот подтип означает, что тело содержит аудио-данные. Хотя пока еще нет консенсуса по "идеальному" аудио-формату для компьютеров, сейчас имеется сильная потребность в универсальном формате.

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

Содержимое тела, имеющего подтип "audio/basic", - аудио-данные в 8-битной форме, кодированные с использованием ISDN mu-law. Формат, соответствующий этому подтипу, предполагает максимальную частоту звучания 8000 Hz и единственный канал.

Формальный синтаксис лдя поля 'Content-Type':

 

audio_тип := "audio" "/" ("basic" / подтип-расширение)

 

7.7. Тип 'Video'

Этот тип означает, что в теле письма содержится анимационное изображение, возможно, со звуком и цветом. Термин "video" используется безотносительно к технологии получения подвижного во времени изображения. Подтип "mpeg" указывает на видео, кодированное в соответствии со стандартом MPEG.

Хотя MIME-стандарт запрещает смешение разнородных мультимедийных данных в одном теле (письма или части письма), многие так называемые "video"-форматы включают синхронизированный звук, что допускается для подтипов типа "video".

Формальный синтаксис лдя поля 'Content-Type':

 

video-type := "video" "/" ("mpeg" / подтип-расширение)

 

7.8. Экспериментальные значения поля 'Content-Type'

Значение типа, начинающееся с "X-", считается частным, предназначенным для использования по договоренности между двумя или более почтовыми системами. Публично определенные (регестрированные) значения никогда не должны начинаться с префикса "X-".

В общем, использование X-типов верхнего уровня не рекомендуется. Производители почтового ПО должны по возможности обходиться использованием X-подтипов для предопределенных типов. Во многих случаях использование экспериментального подтипа более приемлимо, нежели типа верхнего уровня.

 

Все определенные на сегодняшний день типы и подтипы

 

ТИП ПОДТИП
text plain
richtext
enriched
tab-separated-values
multipart mixed
alternative
digest
parallel
appledouble
header-set
message rfc822
partial
external-body
news
application octet-stream
postscript
oda
atomicmail
andrew-inset
slate
wita
dec-dx
dca-rft
activemessage
rtf
applefile
mac-binhex40
news-message-id
news-transmission
wordperfect5.1
pdf
zip
macwriteii
msword
remote-printing
image jpeg
gif
ief
tiff
audio basic
video mpeg
quicktime

Значения полей Content-Type и subtype, а также другие параметры заголовка являются чувствительными к регистру букв, если только не оговорены исключения для конкретного значения параметра.

 

Применение возможностей MIME в транспортных почтовых системах

Хотя новые возможности, предоставляемые MIME, ориентированы в основном на пользовательские почтовые программы, однако, транспортные системы тоже могут воспользоваться преимуществами MIME.

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

Чтобы заниматься реализацией любого из механизмов, описанных ниже, необходимо ознакомиться с отличием между службой почтового транспорта и шлюзовой службой. В основном, почтовый транспорт ответственен за перемещение почтовых сообщений в пределах пространства почтовых сетей, подобных друг другу. С другой стороны, почтовые шлюзы совершают обмен почтой между двумя принципиально отличными почтовыми пространствами, в том числе и через неэлекторнные службы (как бумажная почта, например).

Общеполагается для почтовых транспортных систем неприемлимым изменять содержимое сообщений. В случае почтовых шлюзов, изменения зачастую неизбежно. Таким образом, многие из механизмов, описаных ниже, применяются только к шлюзам, и не должны использоваться в простых транспортных системах. Однако, возможно, что в некоторых специфических ситуациях (таких как в случае SMTP-соединений через межконтинентальную связь) может потребоваться изменять содержимое для обеспечения приемлимого обслуживания для таких ситуаций, и потому такой почтовый транспорт должен считаться уже фактически шлюзом. То есть, почтовые транспорты, которые намерены использовать описанные ниже функции, должны переклассифицировать себя как шлюзы.

 

1. Непринятая почта

К сожалению частой обязанностью транспортных служб является отсылка почты обратно отправителю. Такое может произойти, если почту невозможно доставить или если она не удовлетворяет требованиям шлюза (слишком большой объем, например).

Раньше не было стандартных правил для отказа от принятия почтовых сообщений. Это было досадной, но не главной проблемой для текстовых сообщений. Для нетекстовых, однако, недостаток в стандартном формате отказа от приема является более критичным, потому что типично возвращенные пиьсма представляются их отправителю как текст, и пользователь, просматривающий картинку или звук, как если бы они были текстом, редко бывает счастлив от этого.

MIME позволяет легко инкапсулировать письма в том смысле, что полностью сохраняется их семантика. Простейший путь добиться этого - каждое возвращаемое письмо помещать в тело письма с типом "multipart/mixed", которое содержало бы две части - текстовую, содержащую пояснение причины отказа в принятии оригинального письма и вложение самого этого письма.

Подчеркивается, что транспорные программы вообще не нуждаются в распознавании структуры возвращаемого письма. От них лишь требуется правильно вложить его. Следующий пример показывает, как любое MIME-письмо может быть вложено (инкапсулировано) в письмо возврата так, что вся информация в нем будет корректно воспроизведена, если получатель (он же первый отправитель) будет читать его с помощью MIME-ориентированной почтовой программы:

 

From: Mailer-Daemon Subject: Rejected Message Content-type: multipart/mixed; boundary=unique-boundary --unique-boundary Content-type: text/plain; charset=us-ascii Посланное Вами письмо не принято. Детали отказа следующие: From: Nathainel Borenstein Message-ID: <[email protected]> To: [email protected] Subject: I know my rights! Rejection-reason: Прием почты из Вашей организации запре- щен. Оригинальное письмо прилагается ниже. --unique-boundary Content-type: message/rfc822 Здесь находится ВОЗВРЩАЕМОЕ ПИСЬМО ПОЛНОСТЬЮ, начиная с заголовка. --unique-boundary--

В данном примере единственная вещь, которая не берется из стандартного набора фраз, это выбор метки границы. Фраза "unique-boundary" должна быть заменена строкой, не появляющейся ни в одной из частей сообщения.

ВАЖНО: Формат, приведенный выше, - лишь один из возможных путей отсылки непринятых писем с использованием MIME.

 

2. Разбиение (фрагментация) и сборка больших писем

Одна из проблем, встречающихся все чаще и чаще в Internet-почте, возврат писем из-за ограничений по их объему. Особенный рост этой проблемы обусловлен расширением использования MIME, так как MIME позволяет посылать очень большие объекты, такие как звук, видео, графику. К счастью, MIME также обеспечивает механизмы, которые могут помочь ослабить эту проблему.

В частности, к ним относится MIME-тип "message/partial", который можно использовать для автоматического разбиения и сборки больших писем. Эта функция может поддерживаться полностью как на уровне пользовательских почтовых агентов, так и транспортными службами, которые могут его использовать для обеспечения полее разумного поведения при шлюзовании почты.

Ниже приводится пример, показывающий, как простое коротенькое письмо может быть разбито на два письма типа "message/partial". На практике, конечно, данное свойство разумно применять лишь для очень больших писем.

Первоначальное письмо:

 

From: Nathaniel Borenstein To: Ned Freed: Subject: a test message Content-type: image/gif Content-Transfer-Encoding: base64 R0lGODdhQAGMAbMAAAAAAP/u7swzIu6ZiLsiEd1EM+5VRGaI3WYAAO67qkRV uwARd6q7/ywAAAAAQAGMAUME/hDISau9OOvNu/9gKI6kRJwoUa5s675wLM90l XW5YKxqPyKRygxv2dr4czwlMCZrQLFTYHBJ2hlyQYFiaz+i0WWBou7fOq1x8vXWfU qU1fJ2qEhYaHGjhZQmJ2QT1xBW1ak1xUdV0/VjtsbpUEDaEJCQOIpqeoNV+LXo5W fVN3dZKceAQPvgyhwQ2lqcXGxx5wja59eJIGUNCszF90sYp50CoqFZ4DoqMMo6M

может быть обратимо преобразовано в следующие два message/partial- -письма:

 

From: Nathaniel Borenstein To: Ned Freed Subject: a test message Content-type: message/partial;; number=1; total=2 Content-type: image/gif Content-Transfer-Encoding: base64 R0lGODdhQAGMAbMAAAAAAP/u7swzIu6ZiLsiEd1EM+5VRGaI3WYAAO67qkRV

и

 

From: Nathaniel Borenstein To: Ned Freed Subject: a test message Content-type: message/partial;; number=2; total=2 uwARd6q7/ywAAAAAQAGMAUME/hDISau9OOvNu/9gKI6kRJwoUa5s675wLM90l XW5YKxqPyKRygxv2dr4czwlMCZrQLFTYHBJ2hlyQYFiaz+i0WWBou7fOq1x8vXWfU qU1fJ2qEhYaHGjhZQmJ2QT1xBW1ak1xUdV0/VjtsbpUEDaEJCQOIpqeoNV+LXo5W fVN3dZKceAQPvgyhwQ2lqcXGxx5wja59eJIGUNCszF90sYp50CoqFZ4DoqMMo6M

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

Фрагментирование и сборка писем могут быть выполнены, в зависимости от обстоятелств, как отправляющей, так и принимающей системой, в зависимости от того, какая из них знает больше о способностях другой.

 

3. Использование или удаление указателей External-Body (внешнего тела)

Другой MIME-тип, ориентированный на слишком большие письма, это "message/external-body". Он обеспечивает почтовым транспортным службам, оптимизировать почтовый траффик в своей системе. Однако, когда почта пересекает медленный и дорогой участок, например, звено спутниковой связи через Тихий океан, может иметь смысл считать указываемые данные и передать их в качестве действительного тела письма, либо скопировать в новое, более доступное место, соответствующим образом изменив ссылку в заголовке письма. Поскольку спецификация данного типа допускает наличие даты аннулирования ресурса, почтовый транспорт может идти на компромисс между пропускной способностью своей системы и ее дисковым пространством, отданным под хранение внешних данных писем, чтобы оптимизировать использование этих внешних данных.

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

Например, приведенное ниже письмо содержит ссылку на внешние PostScript-данные:

 

From: Nathaniel Borenstein To: Ned Freed Subject: The latest MIME draft Content-Type: message/external-body; name="BodyFormats.ps"; site="thumper.bellcore.com"; access-type=ANON-FTP; directory="pub"; mode="image"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript

Шлюз в Австралию может выбрать - скопировать ли файл в какой-либо австралийский FTP-архив, изменив соответствующие параметры в заголовке письма, или оставить все без изменений, или считать данные и вложить их в письмо целиком:

 

From: Nathaniel Borenstein To: Ned Freed Subject: The latest MIME draft Content-type: application/postscript %!PS-Adobe-1.0 %%Creator: greenbush:nsb (Nathaniel Borenstein,MRE 2A- 274,4270,9938586,21462) и так далее...

Этот пример предполагает как выгоду (немедленно доступные получателю данные), так и возможные затраты (если список рассылки велик, то письмо придется разослать всем, хотя только некотоые из получателей обратились бы за данными письма в ближайшее время).

Кроме того, вместо замены ссылки на внешние данные их натуральным включением в письмо, можно трансформировать оригинальное письмо в письмо типа "multipart/alternative", содержащее как ссылку на внешние данные, так и копию этих данных. Это означает, что при перенаправлении письма другому пользователю перенаправлена будет только та часть, которая содержит ссылку. Кроме того, получатель, хоть и получит данные сразу целиком, все равно не потеряет информацию о местоположении оригинального ресурса, и при необходимости сможет скачать более новую его версию в будущем. Это иллюстрируется следующим примером:

 

From: Nathaniel Borenstein To: Ned Freed Subject: The latest MIME draft Content-type: multipart/alternative; boundary=foo --foo Content-Type: message/external-body; name="BodyFormats.ps"; site="thumper.bellcore.com"; access-type=ANON-FTP; directory="pub"; mode="image"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript --foo Content-type: application/postscript %!PS-Adobe-1.0 %%Creator: greenbush:nsb (Nathaniel Borenstein,MRE 2A- 274,4270,9938586,21462) etc... --foo--

Аналогично, в случае, когда внешние данные копируются транспортной системой на локальный FTP, можно сделать в письме две части типа 'external-body', что позволит получателю выбрать, с какого из FTP предпочтительнее забирать тело письма.

 

4. Преобразование графических и других форматов

В настоящее время MIME определяет два графических формата - image/gif и image/jpeg. Первый - более удобен для многих пользователей, понятен многим системам, и отображается довольно быстро. Последний гораздо более компактен и потому менее сказывается на увеличении траффика.

Почтовые транспортные системы могут оптимизировать и траффик, и удобства получателей разумной трансляцией этих форматов (а также других, которые могут быть добавлены в будущем). Если письмо типа image/gif пересылается на длинную дистанцию, оно может быть перетранслировано в image/jpeg. Когда же данные типа image/jpeg получены системой, в которой находится получатель, для конечной доставки, они снова могут быть перетранслированы в GIF для удобств получателя.

Подобные преобразования форматов также рекомендуются и для аудио-данных.

Если преобразование выполнено, настоятельно рекомендуется добавлять каким-либо образом (например, в поле заголовка Received) информацию об истории преобразований документа, в письме содержащегося.

Однако, трансляция форматов обычно ограничивается шлюзовыми службами и менее предпочтительна для обычных транспортных служб. Причем, те службы, которые выполняют преобразования, должны распознавать поле Conterent-Conversion, в котором отправитель может разрешить либо запретить любые преобразования форматов данных, поскольку многие пользователи принципиально неприемлют преобразования, так как считают, что при некоторые из них могут привести к ухудшению качества документа:

 

Content-Conversion: prohibited

или:

 

Content-Conversion: permitted

По умолчанию (если это поле отсутствует) предполагается значение 'permitted'.

 

5. Надежное кодирование данных

В некоторых случаях при прохождении через шлюз данные могут не сохранить своего вида к следующему шагу транспортировки. К примеру, почта проходящая через шлюз ASCII -> EBCDIC, может потерять информацию, содержащую некоторые спецсимволы. В подобных случаях шлюз может обеспечить данным сохранность, применив один из MIME-алгоритмов - base64 или quoted-printable к телу письма или его части. Это, как правило, трансформация без потерь, но необходимо добиться, чтобы результирующее письмо целиком отвечало стандарту MIME, даже если изначально оно таковым не было (в частности, должно быть добавлено поле заголовка MIME-Version).

 

Комментарии

RSS комментарии

27.01.2008 Алексей Спасибо.

17.06.2008 MSD Большое спасибо за перевод, за столь объемный перевод. С английского заманешься переводить.11.07.2008 admin Извините, но перевод не мой. Не могу сказать точно, кто хозяин перевода.27.07.2009 Master Boe Человеческая благодарность -помогло01.11.2011 arr Очень помогло, даже в 2011 ), спасибо )10.11.2011 виктор Так этот стандарт не менялся пока еще... Поэтому до сих пор актуален01.03.2012 mik Как прояснилось в голове-то! Спасибо

Добавить свой комментарий

webi.ru


Смотрите также