Автор: Дэвид Мертц (David Mertz)
Перевод: Intersoft Lab
Авторские права: market@iso.ru
Необычность XML заключается в том, что этот язык предлагает два почти эквивалентных, хотя и не совсем, способа написания фразы: "это данные". Первый способ указания значения данных - поместить его во вложенный элемент, второй - присвоить значению атрибута. Поскольку очевидный ответ на вопрос, когда какой из этих двух подходов является наиболее походящим, как правило, отсутствует, XML не является полностью ортогональным (в теории программирования под этим термином понимается следующее: "каждая конструкция выполняет одну вещь, и никакая другая конструкция не делает то же самое"). В этой статье приводятся рекомендации о том, когда использовать вложенные элементы, а когда атрибуты.
Единственно, когда не требуется решать, каким образом данные передаются - это в случае, если вам вручили спецификацию XML-диалекта, которой необходимо придерживаться - заданную как DTD или W3C XML-схема, или же описанную неформально или с помощью примера. Поэтому, если вам не нужно выбирать, оставьте без внимания рекомендации, приведенные в этой статье. Однако, разработчикам часто приходится разрабатывать точный XML-диалект для использования при обработке. Если это ваш случай, эта статья - для вас.
Важно помнить о различии между XML-документами, которые должны быть просто корректно оформлены, и теми, что обязаны быть допустимыми согласно некоторому DTD/Схеме. Допустимость является гораздо более строгим критерием: с ее помощью можно потребовать, чтобы были представлены определенные данные, и чтобы они были структурированы заданным образом. Именно по этой причине приходится прикладывать гораздо больше усилий для того, чтобы процесс создания заданного документа соответствовал условиям допустимости. У обоих подходов имеются свои преимущества; использование DTD усложняет задачу выбора элементов/атрибутов, но у обоих случаях есть свои плюсы и минусы. Ниже рассмотрены эти две альтернативы.
Использование DTD гарантирует, что вложенные элементы, в отличие от атрибутов, будут строго упорядочены. В только корректно оформленных XML-документах можно свободно манипулировать порядком - в этом случае любой тег может находиться внутри любого другого тега, на любом уровне вложенности. В обоих случаях атрибуты обычно лучше подходят для неупорядоченных данных. Однако, если речь идет о XML-документах с DTD, использование атрибутов едва ли не обязательно для этого типа данных.
Рассмотрим, например, список контактов (контактной информации), каждый из которых должен включать имя, возраст и номер телефона. Разумеется, с точки зрения логики, данные о возрасте не должны обязательно предшествовать номеру телефона. Поэтому, атрибуты и неупорядочены, и потому являются более интуитивным выбором. Сравните два небольших XML-документа, приведенные в Листингах 1 и 2:
<?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>
<?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:
<!ELEMENT contacts (contact*)>
<!ELEMENT contact EMPTY>
<!ATTLIST contact name CDATA #REQUIRED
age CDATA #REQUIRED
telephone CDATA #REQUIRED >
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-документов. К сожалению, иногда реальная ситуация зависит от множества обстоятельств (указывающих на противоположенные направления). Часто структура данных изменяется настолько, что делает недействительными предыдущие мотивировки. Используй рекомендации, изложенные в этой статье, когда это возможно, но прежде всего полагайтесь на здравый (основанный на имеющейся информации) смысл.
Дэвид Мертц использует абсолютно неструктурированный интеллект, чтобы писать о форматах структурированных документов. Дэвид доступен по адресу: mertz@gnosis.cx, а жизнь его описана на http://gnosis.cx/publish/.
[1] По всей видимости, это опечатка (в оригинале стоит Listing 2): и вместо Листинга 2 должен быть Листинг 1 (прим. пер.)