Почему при выгрузке в XML меняется порядок атрибутов и как на него повлиять

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Анализ проблемы: почему скачет порядок атрибутов

Посмотрим на классический пример формирования узла XML в коде 1С:


ХМЛГлБухгалтер = ХМЛкорень.СоздатьПодчиненныйЭлемент("ГлБухгалтер");
ХМЛГлБухгалтер.УстановитьАтрибут("Отчество", глбухОтчество);
ХМЛГлБухгалтер.УстановитьАтрибут("Имя", глбухИмя);
ХМЛГлБухгалтер.УстановитьАтрибут("Фамилия", глбухФамилия);

После сохранения документа в файл мы можем обнаружить, что атрибуты поменялись местами:

<ГлБухгалтер Фамилия="Красных " Отчество="Юрьевна " Имя="Надежда "/>

Выясним причину такого поведения. Оно обусловлено двумя ключевыми факторами:

  1. Спецификация стандарта XML (W3C XML 1.0): согласно официальному стандарту, порядок следования атрибутов внутри XML-элемента не имеет семантического значения. Корректный XML-парсер обязан воспринимать атрибуты как неупорядоченное множество (коллекцию пар «ключ-значение»). Доступ к значению атрибута всегда должен производиться по его имени (getAttribute("Имя")), а не по индексу позиции.
  2. Особенности работы DOM-модели: при работе через объектную модель документов (DOM, например, через MSXML2.DOMDocument или компоненту v7plus.dll) атрибуты узла сохраняются во внутренней хэш-таблице (NamedNodeMap). Такая структура оптимизирована для быстрого поиска по имени, а не для сохранения хронологии добавления. При сохранении (сериализации) дерева в текст порядок вывода атрибутов определяется внутренними алгоритмами библиотеки.
  3. Отображение в программах просмотра: некоторые обозреватели (например, Internet Explorer) при визуализации XML перестраивают дерево и могут сортировать атрибуты по собственным правилам, что также визуально меняет их порядок.

Что делать, если порядок атрибутов критически важен

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

Вариант 1. Использование дочерних элементов вместо атрибутов

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


ХМЛГлБухгалтер = ХМЛкорень.СоздатьПодчиненныйЭлемент("ГлБухгалтер");
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Фамилия");
ХМЛЭлемент.Значение = глбухФамилия;
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Имя");
ХМЛЭлемент.Значение = глбухИмя;
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Отчество");
ХМЛЭлемент.Значение = глбухОтчество;

Вариант 2. Прямое формирование текстового файла

Если сторонний сервис жестко требует именно атрибуты и именно в заданной последовательности, можно отказаться от DOM-модели и сформировать текстовое представление файла вручную через объект Текст. Это гарантирует сохранение точного порядка символов и строк.


ТекстXML = СоздатьОбъект("Текст");
СтрокаУзла = "<ГлБухгалтер Отчество=""" + СокрЛП(глбухОтчество) + """ Имя=""" + СокрЛП(глбухИмя) + """ Фамилия=""" + СокрЛП(глбухФамилия) + """/>";
ТекстXML.ДобавитьСтроку(СтрокаУзла);
ТекстXML.Записать(ПутьКФайлу);

Вариант 3. Использование потоковой записи (SAX / ЗаписьXML)

При использовании потоковых механизмов записи данные отправляются напрямую в поток вывода по мере выполнения команд:

  1. В 1С 7.7: можно задействовать COM-объект MSXML2.MXXMLWriter совместно с интерфейсом MSXML2.SAXAttributes. В этом случае атрибуты записываются в файл строго в порядке их передачи в генератор потока.
  2. В 1С 8: потоковый объект ЗаписьXML при вызове метода ЗаписатьАтрибут() сохраняет последовательность вызовов непосредственно в выходной файл без перестроения дерева в памяти.

Вариант 4. Канонизация XML (C14N)

Если совпадение структуры необходимо для формирования электронной цифровой подписи (XML-DSig), файл перед расчетом контрольной суммы должен проходить процедуру канонизации (Canonical XML). Данный алгоритм автоматически сортирует все атрибуты каждого тега в лексикографическом порядке, обеспечивая гарантированную идентичность хэша на любой платформе.

← На главную