Журнал ВРМ World

Мировая история развития технологий управления эффективностью бизнеса – обзоры зарубежных публикаций

Элементы или атрибуты?

Во второй статье освещается один из важнейших вопросов проектирования
XML-документов: выбор наиболее подходящей структуры создаваемого документа.

Вопросы проектирования XML-форматов

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

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

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

Важно помнить о различии между XML-документами, которые должны быть просто корректно оформлены, и теми, что обязаны быть допустимыми согласно некоторому DTD/Схеме. Допустимость является гораздо более строгим критерием: с ее помощью можно потребовать, чтобы были представлены определенные данные, и чтобы они были структурированы заданным образом. Именно по этой причине приходится прикладывать гораздо больше усилий для того, чтобы процесс создания заданного документа соответствовал условиям допустимости. У обоих подходов имеются свои преимущества; использование DTD усложняет задачу выбора элементов/атрибутов, но у обоих случаях есть свои плюсы и минусы. Ниже рассмотрены эти две альтернативы.

Важен ли порядок следования данных

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

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

Листинг 1. Использование атрибутов для передачи контактной информации

<?xml version="1.0" ?>
<!DOCTYPE contacts SYSTEM "attrs.dtd" >
<contacts>
  <contact
     name="Jane Doe"
     age="74"
     telephone="555-3412" />
  <contact name="Chieu Win" telephone="555-8888" age="44" />
</contacts>
Листинг 2. Использование вложенных элементов для передачи контактной информации

<?xml version="1.0" ?>
<!DOCTYPE contacts SYSTEM "subelem.dtd" >
<contacts>
  <contact>
    <name>Jane Doe</name>
    <age>74</age>
    <telephone>555-3412</telephone>
  </contact>
  <contact>
    <name>Chieu Win</name>
    <telephone>555-8888</telephone>
    <age>44</age>
  </contact>
</contacts>

Теперь представим, какой DTD может быть задан для каждого из этих XML-форматов. Для Листинга 1, демонстрирующего использование атрибутов, это мог бы быть следующий DTD:

Листинг 3. DTD для документа с использованием атрибутов

<!ELEMENT contacts (contact*)>
<!ELEMENT contact EMPTY>
<!ATTLIST contact name      CDATA #REQUIRED
                  age       CDATA #REQUIRED
                  telephone CDATA #REQUIRED >

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

Листинг 4. DTD для документа с использованием вложенных элементов

<!ELEMENT contacts  (contact*)>
<!ELEMENT contact   (name,age,telephone)>
<!ELEMENT name      (#PCDATA)>
<!ELEMENT age       (#PCDATA)>
<!ELEMENT telephone (#PCDATA)>

Очевидный недостаток DTD, приведенного в Листинге 4, состоит в том, что этот простой пример (Листинг 2) является недопустимым согласно этому DTD. Дело в том, что порядок вложенных элементов нарушен. В таблице справа показано, как можно использовать неупорядоченные вложенные элементы с DTD, хотя, если не имеется иных непреодолимых причин, лучший выбор - воспользоваться заданием атрибутов для передачи неупорядоченных данных.

Возможность нахождения многочисленных данных на одном уровне

Если одни и те же данные неоднократно повторяются в пределах объекта, вложенные элементы несомненно предпочтительней. Например, в рассмотренном выше примере объект contacts содержит множество объектов contact. Понятно, что в этом случае каждый контакт должен быть описан в элементе-потомке элемента contacts.

Однако, в реальной жизни при внесении изменений разработчики часто уходят от этого принципа проектирования. Рассмотрим, как это может происходить: сначала вы определяете, что у каждого Flazbar имеется прикрепленный к нему flizbam (а flizbam описывается одной величиной). Кажется вполне разумным сберечь дополнительное наполнение вложенных элементов и создать атрибут flizbam для тега Flazbar. Однако, затем - после того, как вы уже написали великолепный рабочий код для обработки несколькими Flazbar - вы узнаете, что в некоторых случаях у Flazbar могут быть два flizbam. Но это не проблема: вы вносите незначительные изменения в установленный код и просто переписываете DTD:

<!ATTLIST Flazbar flizbam   CDATA #REQUIRED
                  flizbam2  CDATA #IMPLIED>

После исправления кода ваши старые XML-документы по-прежнему допустимы, и новые работоспособны. Немного погодя вы обнаруживаете, что у Flazbar может быть третий flizbam...

Трудно не соблазниться этим коварным принципом проектирования. Однако, данные и объекты развиваются, и единичные предметы часто становятся двойными или многочисленными. По этой причине некоторые XML-программисты сторонятся атрибутов, но мне кажется, это уже слишком. Мой совет - тщательно продумайте на этапе проектирования, не появится ли позднее у единичной величины элементы одного уровня. Если есть все причины полагать, что в будущем появится множество элементов одного уровня, используйте вложенные элементы с самого начала. Если же вы уверены, что объект данных будет оставаться уникальным, придерживайтесь атрибутов.

Моделирование неупорядоченных вложенных элементов

Для того, чтобы XML-документ, представленный в Листинге 2, был допустимым, в DTD следует добавить следующее определение:


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

<!ELEMENT contact   (name?,age?,telephone?)+>

Однако, приведенное выше DTD предусматривает слишком большую гибкость. В этом случае у элементов contact могут отсутствовать элементы name, а также быть несколько элементов age, что нарушает семантические требования. Для того, чтобы решать поставленную задачу, потребовалось бы чрезвычайно громоздкое определение, приведенное ниже:


Громоздкое, но точное DTD для элементов, несущих контактную информацию

<!ELEMENT contact  ((name,age,telephone)|
                    (name,telephone,age)|
                    (age,name,telephone)|
                    (age,telephone,name)|
                    (telephone,name,age)|
                    (telephone,age,name))>

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

Обязательность сохранения свободного места

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

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

Важность удобочитаемости

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

Лично мне гораздо легче читать и писать атрибуто-ориентированные XML-форматы, а не ориентированные на вложенные элементы. Чтобы пояснить сказанное, вернемся к Листингам 1 и 2. Ни один из них не так уж сложно читать, но Листинг 2[1], который демонстрирует подход, основанный на использовании атрибутов - проще, его также легче писать, поскольку не нужно озадачиваться проблемой непостоянства порядка следования вложенных элементов.

Заключение

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

Ресурсы

  • Все, что действительно необходимо знать о XML, это Рекомендация W3C "Расширяемый язык разметки (XML) 1.0" (Extensible Markup Language (XML) 1.0). Разумеется, чтобы понять, какое она имеет значение, требуется немного проницательности.
  • В рубрике XML Cover Pages приводятся рекомендации по "Использованию элементов и атрибутов" (Using elements and attributes). На этой странице также можно найти ссылки на ряд статей, в которых предлагаются взаимопротиворечащие рассуждения о том, что выбрать атрибуты или элементы. Именно по этой причине мы, программисты, и "получаем наш длинный доллар"!
  • Еще один способ понять различие между атрибутами и элементами - это изучить материалы "Форматы, основанные на документах, или форматы, основанные на данных" ("Document-Centric" vs. "Data-Centric").
  • Познакомьтесь с другими статьями колонки "Советы о XML" (XML tips), публикуемыми в разделе developerWorks XML.

Об авторе

Дэвид Мертц использует абсолютно неструктурированный интеллект, чтобы писать о форматах структурированных документов. Дэвид доступен по адресу: mertz@gnosis.cx, а жизнь его описана на http://gnosis.cx/publish/.



[1] По всей видимости, это опечатка (в оригинале стоит Listing 2): и вместо Листинга 2 должен быть Листинг 1 (прим. пер.)



Автор: Дэвид Мертц (David Mertz)