- 1 января 2001 г.
Элементы или атрибуты?
Во второй статье освещается один из важнейших вопросов проектирования
XML-документов: выбор наиболее подходящей структуры создаваемого документа.
Вопросы проектирования 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-парсер, компоновка атрибутов, вероятно, будет несколько отличной от первоначальной, находящейся в исходном 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)