При формировании выгрузок в формате XML разработчики нередко сталкиваются с ситуацией, когда атрибуты узла записываются в результирующий файл не в том порядке, в котором они добавлялись в программном коде. Разберем, почему возникает такое поведение, нарушает ли это стандарты обмена данными и как поступить, если принимающая система требует строгого порядка следования полей.
Посмотрим на классический пример формирования узла XML в коде 1С:
ХМЛГлБухгалтер = ХМЛкорень.СоздатьПодчиненныйЭлемент("ГлБухгалтер");
ХМЛГлБухгалтер.УстановитьАтрибут("Отчество", глбухОтчество);
ХМЛГлБухгалтер.УстановитьАтрибут("Имя", глбухИмя);
ХМЛГлБухгалтер.УстановитьАтрибут("Фамилия", глбухФамилия);
После сохранения документа в файл мы можем обнаружить, что атрибуты поменялись местами:
<ГлБухгалтер Фамилия="Красных " Отчество="Юрьевна " Имя="Надежда "/>
Выясним причину такого поведения. Оно обусловлено двумя ключевыми факторами:
getAttribute("Имя")), а не по индексу позиции.MSXML2.DOMDocument или компоненту v7plus.dll) атрибуты узла сохраняются во внутренней хэш-таблице (NamedNodeMap). Такая структура оптимизирована для быстрого поиска по имени, а не для сохранения хронологии добавления. При сохранении (сериализации) дерева в текст порядок вывода атрибутов определяется внутренними алгоритмами библиотеки.В подавляющем большинстве случаев порядок атрибутов не требует никаких правок, так как любая сертифицированная программа-приемник считывает значения по именам. Однако если внешняя система написана некорректно (например, разбирает XML построчно строковыми функциями или регулярными выражениями) или требует строгого формата для криптографической подписи, рассмотрим возможные варианты решения.
Если формат схемы обмена разрабатывается вами или допускает модификацию, наиболее правильный путь — хранить упорядоченные данные не в атрибутах, а в виде отдельных вложенных тегов. В отличие от атрибутов, порядок следования элементов внутри родительского узла строго регламентирован стандартом XML и всегда сохраняется парсерами.
ХМЛГлБухгалтер = ХМЛкорень.СоздатьПодчиненныйЭлемент("ГлБухгалтер");
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Фамилия");
ХМЛЭлемент.Значение = глбухФамилия;
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Имя");
ХМЛЭлемент.Значение = глбухИмя;
ХМЛЭлемент = ХМЛГлБухгалтер.СоздатьПодчиненныйЭлемент("Отчество");
ХМЛЭлемент.Значение = глбухОтчество;
Если сторонний сервис жестко требует именно атрибуты и именно в заданной последовательности, можно отказаться от DOM-модели и сформировать текстовое представление файла вручную через объект Текст. Это гарантирует сохранение точного порядка символов и строк.
ТекстXML = СоздатьОбъект("Текст");
СтрокаУзла = "<ГлБухгалтер Отчество=""" + СокрЛП(глбухОтчество) + """ Имя=""" + СокрЛП(глбухИмя) + """ Фамилия=""" + СокрЛП(глбухФамилия) + """/>";
ТекстXML.ДобавитьСтроку(СтрокаУзла);
ТекстXML.Записать(ПутьКФайлу);
При использовании потоковых механизмов записи данные отправляются напрямую в поток вывода по мере выполнения команд:
MSXML2.MXXMLWriter совместно с интерфейсом MSXML2.SAXAttributes. В этом случае атрибуты записываются в файл строго в порядке их передачи в генератор потока.ЗаписьXML при вызове метода ЗаписатьАтрибут() сохраняет последовательность вызовов непосредственно в выходной файл без перестроения дерева в памяти.Если совпадение структуры необходимо для формирования электронной цифровой подписи (XML-DSig), файл перед расчетом контрольной суммы должен проходить процедуру канонизации (Canonical XML). Данный алгоритм автоматически сортирует все атрибуты каждого тега в лексикографическом порядке, обеспечивая гарантированную идентичность хэша на любой платформе.