Вопросы XML: Еще легче, чем микроформаты: пикоформаты (исходники)

Дит Элза (Dethe Elza), Дэвид Мертц (David Mertz)

В прошлом выпуске колонки Вопросы XML Дэвид Мертц объяснял, что reStructured Text - это облегченный язык разметки для форматирования преимущественно текстовых документов, а до этого был рассмотрен YAML, облегченный язык разметки для документов, которые содержат преимущественно данные. Являются ли эти технологии полезными и сейчас, с появлением AJAX и микроформатов, иными словами - достаточно ли "легки" микроформаты? Посмотрите, как можно использовать JSON (который проще, чем YAML) при помощи MochiKit для AJAX без X, и примените reStructured Text для генерирования микроформатов.

XML всегда использовался для разметки как документов, так и структурированных данных, что в зависимости от точки зрения конкретного автора интерпретировалось то как самое большое достоинство этого языка, то как самый большой недостаток. В тех случаях, когда нет резких границ между документом и данными, XML может быть лучшим вариантом, но в качестве общего решения XML может быть и более сложным, чем любое имеющееся частное решение проблемы. Ранее Дэвид рассказывал о YAML. YAML ("Ain't Markup Language" (тоже язык разметки) или, по-другому, "Yet Another Markup Language" (еще один язык разметки) - это диалект, предназначенный для того, чтобы упростить транспорт данных (чисел, строк, списков, простых структур) по сравнению с XML. В данной статье мы будем говорить о стандарте JSON (JavaScript Object Notation), который является подмножеством YAML, но при этом проще в разработке и синтаксическом разборе. В JavaScript и Python, если JSON поступил от надежного источника, он может быть просто обработан механизмом выполнения сценариев, но синтаксические анализаторы, которые существуют для JSON, происходят от менее надежных источников.

Поскольку мы будем использовать JSON, чтобы подойти к спектру "документ-данные" со стороны данных, вы можете использовать структурированные текстовые форматы, не обращая внимания на свойства микроформата как документа. Существует три основных подхода к структурированию текста (если не учитывать многие разновидности разметки Wiki): reStructured Text, Markdown и Textile. Мы рассмотрим каждый из этих подходов, чтобы посмотреть, как они смогут справиться с нашим примером микроформата, хотя бы теоретически.

Что входит в микроформат?

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

  • Содержание/Название;
  • Размещение;
  • URL;
  • Дата (и, по желанию, время) начала действия;
  • Дата (и, по желанию, время) окончания действия;
  • Временная зона;
  • Описание.

На самом деле придется написать не очень большой код. В листинге 1 показан пример события hCalendar:

Листинг 1. Событие hCalendar

                

<div class="vevent">
    <a class="url"
        href="http://www.vanpyz.org/conference/keynotes.html">
        <abbr class="dtstart" title="20060804T1900-0700">
            4 Август 2006 г. - 19:00
        </abbr> -
        <abbr class="dtend" title="20060804T2100-0700">
            21:00
        </abbr> -
        <span class="summary">
            Vancouver Python Workshop Keynotes
        </span> - at
        <span class="location">
            Fletcher Challenge Canada Theatre,
            SFU Harbour Center,
            Downtown Vancouver
        </span>
    </a>
    <div class="description">
        <p>The Vancouver Python Workshop keynote address is an
        opportunity to hear from leading members of the Python
        community. This years speakers are Guido van Rossum of
        Google and Jim Hugunin from Microsoft.</p>
    </div>
</div>

Если вы просмотрите этот листинг от начала до конца, чтобы понять суть данных, вы сможете написать подобный код при помощи JSON. Обратите внимание на то, что для даты, времени и временной зоны используется кодировка ISO8601, стандартный способ форматирования даты и времени, которые сами по себе являются микроформатом. Следующий пример (листинг 2) - это корректный код в языках JavaScript или Python:

Листинг 2. Код с использованием JSON

                

event = {
    'title':  'Vancouver Python Workshop Keynotes',
    'location': 'Fletcher Challenge Canada Theatre,                  SFU Harbour Center, Downtown Vancouver',
    'url': 'http://www.vanpyz.org/conference/keynotes.html',
    'start': '2006-08-04T19:00-0700',
    'end': '2006-08-04T21:00-0700',
    'description': 'The Vancouver Python Workshop keynote address     is an opportunity to hear from leading members of the Python     community. This years speakers are Guido van Rossum of Google     and Jim Hugunin from Microsoft.'};

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

Вы внесли данные в мои документы!

Использование JSON для контента микроформата представляет подход с точки зрения данных. Что касается документа, в микроформатах мы можем идти от структурированного текста. Как выглядел бы календарь hCalendar, написанный при помощи reStructured Text? Известно, что reST позволяет создавать подключаемые модули расширения при помощи директив, поэтому директива о проведении синтаксического разбора данных hCalendar будет выглядеть примерно так:

                

.. event::

    LOCATION: Fletcher Challenge Canada Theatre,
    SFU Harbour Center, Downtown Vancouver
    DTSTART: TZID=America/Vancouver:20060804T190000
    DTEND: TZID=America/Vancouver:20060804T210000
    SUMMARY: Vancouver Python Workshop Keynotes
    DESCRIPTION: The Vancouver Python Workshop keynote address
    is an opportunity to hear from leading members of the Python
    community. This years speakers are Guido van Rossum of Google
    and Jim Hugunin from Microsoft.

Интересно, что данный вид hCalendar представляет собой отображение более раннего стандарта iCalendar на подмножество HTML. Но на что же похож этот загадочный iCalendar? В листинге 3 показано то же событие в iCalendar:

Листинг 3. Событие в iCalendar

                

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Computer\, Inc//iCal 2.0//EN
BEGIN:VEVENT
DURATION:PT3H
LOCATION: Fletcher Challenge Canada Theatre,
SFU Harbour Center, Downtown Vancouver
DTSTAMP:20060615T034522Z
UID:FE31377A-AB78-4D99-BC25-3F09C99E5928
DTSTART;TZID=America/Vancouver:20060704T100000
SUMMARY:Vancouver Python Workshop Keynotes
DESCRIPTION:The Vancouver Python Workshop keynote address
is an opportunity to hear from leading members of the Python
community. This years speakers are Guido van Rossum of Google
and Jim Hugunin from Microsoft.
END:VEVENT
END:VCALENDAR

Да, iCalendar - это текстовый формат, который относительно прост для синтаксического разбора, можно найти соответствующие библиотеки, а с результатом работать в том языке программирования, который вы предпочитаете. Поэтому, хотя и допустимо создать для reStructured Text директиву, которая будет извлекать все элементы данных hCalendar, лучше изменить директиву .. include:: так, чтобы сделать возможным включение контента iCalendar напрямую, в формате hCalendar. Поскольку многие из существующих инструментов, такие, как iCal от Apple, предусматривают возможность импортирования и экспортирования форматирования iCalendar, многократное использование форматирования напрямую может быть довольно полезным. Мы не будем подробно рассматривать добавление или изменение директив в reStructured Text, как в интересах краткости, так и потому, что Дит уже написал практическое руководство по этой теме вместе с ведущим разработчиком reStructured Text Дэвидом Гуджером (David Goodger).

Это легче воздуха, но дышится труднее

Хотя JSON предоставляет более простой способ форматирования данных, чем YAML или XML, reStructured Text может быть довольно сложным инструментом. Документ в reStructured Text может читаться проще, чем XML, и может быть проще в использовании, если вы не станете пытаться использовать все его функции. Но когда вы начнете добавлять большое количество директив, таблиц и других функций, Измеритель сложности, предложенный Дитом, будет зашкаливать. Поскольку JSON добивается простоты за счет специализации (известный компромисс,  который восходит к Domain Specific Languages, или DSL), можно и дальше упрощать структурированный текст, если вы не боитесь пожертвовать некоторыми функциями и гибкостью reStructured Text. И оказывается, что такое еще более легкое и ориентированное на документ форматирование существует.

Мы рассмотрим Textile и MarkDown, два облегченных варианта структурированного текста, которые упрощают микроформатирование данных. К сожалению, те же свойства, которые делают эти инструменты столь подходящими для создания контента на основе документа, приводят к их непригодности для решения задач с подходом на основе данных, таких, как hCalendar. Textile не имеет разметки для <div> или <abbr> или других способов добавить классы в <a>. Хотя этот стандарт достаточно гибкий и упрощает добавление атрибутов class, id и style, в нем нет механизма, позволяющего добавить атрибуты title. В Markdown вообще не предусмотрен механизм добавления атрибутов (хотя PyMarkdown имеет расширение для их поддержки), и не имеет структур для <div> и <abbr>. Любая из двух систем может быть использована в виде преформатированного HTML, но тогда вы сразу теряете преимущество использования облегченного форматирования.

Отсутствие поддержки микроформатов в этих облегченных языках разметки понятно. Микроформаты - это, по своей сути, данные, а языки Textile и MarkDown создавались как инструменты, предназначенные для того, чтобы писать в интернете. Они пытаются упростить получение слов, которые вам нужны, за счет минимального форматирования, но игнорируют проблемы вставки данных, предназначенных для чтения машиной. Одна из самых старых проблем XML - это то, что язык используется как для данных (информации, которая предназначена для чтения машиной) так и для контента (текста, который предназначен для чтения человеком). Форматы структурированного текста теряют преимущества там, где начинается содержимое , тогда как YAML и JSON плавно теряют преимущества, когда речь заходит о данных. Каждый из них может делать свою работу так же хорошо или даже лучше, чем XML, но в тех случаях, когда граница между данными и содержимым стерта, как в микроформатах, эти языки могут столкнуться с затруднениями на переходе.

REST - JSON

Многие примеры, в которых используется язык JSON, показывают, как браузер может получать сообщения JSON от сервера, использующего метод GET. Но парадигма REST состоит из четырех глаголов: GET, POST, PUT и DELETE, и для этого есть причина. GET следует использовать для того, чтобы выполнять стандартные запросы к Web-ресурсу (то есть, метод GET должен быть идемпотентом), POST, чтобы создавать новые ресурсы, PUT, чтобы обновлять существующие ресурсы, и DELETE для удаления ресурса. Поскольку мы хотим быть верными приверженцами REST, давайте создадим простую инфраструктуру для перемещения данных JSON, воспользовавшись всеми четырьмя глаголами.

Ниже приводится код программы CGI на языке Python, которая инкапсулирует простейший каркас для перемещения по битам воображаемого кода JSON. Программа использует библиотеку Боба Ипполито (Bob Ippolito) simplejson для более безопасного разбора кода JSON, вместо того, чтобы просто использовать процедуру eval для строки, полученной через интернет. Безусловно, нужно намного больше, чтобы создать интерфейс REST (создание URI для каждого ресурса - непростая задача). В листинге 4 демонстрируется простейший сервер REST/JSON:

Листинг 4. Сервер REST/JSON

                

#!/usr/local/bin/python

'''
Minimal JSON REST server
'''

import os
import cgi
import cgitb
cgitb.enable()
import simplejson

sample_data = {'name': 'King Arthur',
    'quest': 'To seek the holy grail',
    'airspeed_of_unladen_European_swallow': '24 MPH'}




def post(args):
    '''
    Used to create a new resource
    '''
    new_uri = 'http://example.org/' # URI of newly created resource
    sample_data['result_uri'] = new_uri
    print simplejson.dumps(sample_data)


def put(args):
    '''
    Used to update an existing resourc
    '''
    sample_data.update(args)
    print simplejson.dumps(sample_data)


def get(args):
    '''
    sed for any side-effect free request
    '''
    print simplejson.dumps(sample_data)

def delete(args):
    '''
    Used to remove an existing note
    '''
    print simplejson.dumps({'content':'None'})


def main():
    method = os.environ.get('REQUEST_METHOD', 'GET')
    if method == 'GET':
        args = None
    else:
        json_value = cgi.FieldStorage().getfirst('json_value')
        args = simplejson.loads(json_value)
    if method == 'POST':
        method = args['method'] # fix for browsers that don't
                                # send PUT or DELETE properly

    # Start an HTTP response
    print "Content-type: text/plain"
    print ""

    # Python dispatch idiom using a dictionary vs. case-statement
    dict(POST=post,
         PUT=put,
         GET=get,
         HEAD=get,
         DELETE=delete)[method](args)

if __name__ == '__main__':
    main()

Программа листинга 4 предназначена для обработки основного кода REST и JSON на стороне сервера. Для стороны клиента Дит написал небольшой фрагмент на JavaScript, который можно встроить в Web-страницу. В этом примере тоже используется код Боба Ипполито (Bob Ippolito) - библиотека MochiKit JavaScript, которой мы остались очень довольны. В листинге 5 приводится код простейшего клиента JSON/REST:

Листинг 5. Простейший клиент JSON/REST

                

//
//   rest.js
//
//   Simplistic framework for bi-directional JSON transport via REST
//

SERVER = 'http://localhost/rest_cgi.py'

function handle_success(result){
    alert('Success: ' + result.responseText);
}

function handle_error(result){
    logError(result.responseText);
}

var sample_content = {'name': 'Sir Lancelot',
         'quest': 'To seek the holy grail',
         'favorite_color': 'blue'};

function _sendVerb(verb, content, handler){
    var req = getXMLHttpRequest();
    // Certain browsers don't actually support verbs besides GET
    // and POST, spoiling the party for the rest of us
    content['method'] = verb;
    if (verb != 'GET'){
        verb = 'POST'
    }
    req.open(verb, SERVER);
    # queryString is the easiest way to send data to the server
    json_content = queryString(['json_value'],
        [serializeJSON(content)]);
    var req = sendXMLHttpRequest(req, json_content)
    req.addCallbacks(handler, handle_error);
}

function get(){
    _sendVerb('GET', '', handle_success);
}

function post(){
    _sendVerb('POST', sample_content, handle_success);
}

function put(){
    _sendVerb('PUT', sample_content, handle_success);
}

function test_delete(){
    _sendVerb('DELETE', sample_content, handle_success);
}

JSON и микронавты

При помощи программ из листингов 4 и 5 вы можете перемещаться по битам кода JSON достаточно свободно, но вам все еще нужно что-то делать для этого. Учитывая все, что было сказано раньше, естественным желанием будет конвертировать данные обратно в формат hCalendar или iCalendar, в зависимости от того, обрабатываются ли данные на стороне клиента или на стороне сервера, а также от конкретных задач. Например, можно использовать MochiKit (особенно функции быстрого вызова DOM) на стороне клиента, чтобы создать пример шаблона для данных JSON в листинге 2 и переформатировать их в формат hCalendar прямо в браузере, заменив функцию handleSuccess(), как показано в листинге 6:

Листинг 6. Замена функции handleSuccess()

                

function handleSuccess(result){
    var data = evalJSON(result.responseText);
    // Преобразуем данные json в узлы DOM
    var hCalendarData = objectToCalendar(data);
   // In a real application we would add/replace this in our
    // Web page somewhere, but for this demo we'll just display it.
    alert(toHTML(hCalendarData));
}

var ABBR = createDOMFunc('abbr');

function pad2(number){
    if (number < 10){
        return '0' + number;
    }else{
        return '' + number;
    }
}

function time(date){
    return pad2(date.getHours()) +
        ':' +
        pad2(date.getMinutes());
}

function objectToCalendar(obj){
    var startDate = isoTimestamp(obj.start);
    var endDate = isoTimestamp(obj.end);
    var cal = DIV({'class':'vevent'},
                  A({'class':'url', 'href': obj.url},
                      ABBR({'class':'dtstart', 'title': obj.start},
                          startDate.toLocaleDateString(),
                          ' - ',
                          time(startDate)
                      ),
                      ' - ',
                      ABBR({'class': 'dtend', 'title': obj.end},
                          time(endDate)
                      ),
                      ' - ',
                      SPAN({'class': 'summary'}, obj.summary),
                      ' - at ',
                      SPAN({'class': 'location'}, obj.location)
                  ),
                  DIV({'class':'description'},
                      P(obj.description)
                  )
              );
    return cal;
}

Из примера не вполне понятно, какие функции выполняет код в листинге 6; MochiKit определяет множество функций быстрого вызова HTML DOM, которые позволяют достаточно легко создать структуру DOM фрагмента hCalendar. Если нет встроенных ярлыков для элементов <abbr>, код также создает один такой ярлык. MochiKit выполняет конвертирование объектов JavaScript Date в формат ISO8601 и обратно, но встроенная строковая интерпретация объекта Date - это не совсем то, что нам нужно, поэтому нужно написать программу, которая сама выполняла бы интерпретацию. Ничего особенно сложного, но все еще не очень ясно, поэтому рекомендуем обратиться к превосходной документации по Mochikit.

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

Прополка в саду ветвящихся тропинок

Какую выгоду от всего этого можете получить именно вы? Действительно ли удобнее включить iCalendar в код reStructured Text или лучше переслать биты кода JSON не в hCalendar, а в браузер? Почему просто не написать двоичный код, или XML, и покончить с этим?

В действительности, окажется ли методика, описанная здесь, полезной для вас или нет, описывается старой поговоркой специалистов по информационным технологиям: поживем увидим. Если вы создаете Web-сервисы на основе REST, то передача данных через JSON, а не через XML, может быть более быстрой и более удобной. Если вы используете язык reStructured Text для упрощенного (и более читабельного) создания HTML-контента, то возможность непосредственного включения микроформатов, либо в виде HTML (hCalendar), либо в виде простого текста (iCalendar) может упростить задачу. При создании новой системы стоит подумать об обеих технологиях.

Конечная задача микроформатов - сделать данные проще для человеческого восприятия, в то же время сохраняя их дружественными к машинному синтаксическому разбору. Философия микроформатов состоит в многократном использовании уже имеющихся семантических форматов, в частности, HTML, везде, где это возможно. AJAX, JSON и REST упрощают и обогащают создание систем для микроформатов и другого контента, в то время как облегченная разметка делает создание и редактирование контента для таких систем более простым, быстрым и дружественным для человеческого восприятия. Поэтому все упомянутые технологии имеют право на существование, и вы можете заметить синергетический эффект, если будете применять их в сочетаниях друг с другом.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=5394