Сравнить собственный XML после канонизации в строку и в поток

Учебные задачи

Два новых документа с одинаковыми данными и разным порядком установки атрибутов сравниваются в каноническом виде. Поток проверяется против строки, а намеренное изменение b должно обнаружиться.

Где и как запускать

Полный модуль управляемой формы; серверная функция без контекста, два собственных DOM и поток в памяти.

Подготовка

  1. Создайте собственную новую пустую конфигурацию УчебнаяКанонизацияXML85, управляемое приложение, платформа8.5.1.1343. Не используйте production или базу с чужими обработчиками.

  2. Обработки → ОпытXML85 → управляемая форма Форма, основная форма обработки. Для каждого урока создайте отдельную обработку либо заменяйте целиком модуль формы: три модуля ниже не вставляются друг в друга.

  3. Создайте указанную в уроке команду с одноимённым действием и перетащите её на форму. Код — полный модуль формы; вспомогательную серверную функцию оставьте на уровне модуля.

  4. Нажмите F7 и обновите только новый стенд. runtimeVerifiedScenarios=0: справочник проверялся статически; данный код в 1С здесь не выполнялся.

  5. Откройте обработку через функции для технического специалиста. Клиент показывает только итоговую строку; ДокументDOM, фильтр, поток и итератор остаются на сервере.

  6. Исходные данные заданы прямо в коде. Нет внешнего XML, DTD, сети, подписания документов или записи прикладных объектов.

  7. Команда и кнопка ПроверитьКанонизацию85. Реквизиты формы не требуются: весь опыт создаётся в серверной функции.

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

&НаКлиенте
Процедура ПроверитьКанонизацию85(Команда)
    Сообщить(КанонизироватьСвоиДокументы());
КонецПроцедуры

&НаСервереБезКонтекста
Функция КанонизироватьСвоиДокументы()
    Первый = Новый ДокументDOM("", "demo");
    КореньПервого = Первый.ЭлементДокумента;
    КореньПервого.УстановитьАтрибут("b", "2");
    КореньПервого.УстановитьАтрибут("a", "1");
    КореньПервого.ДобавитьДочерний(Первый.СоздатьТекстовыйУзел("A & B"));
    Второй = Новый ДокументDOM("", "demo");
    КореньВторого = Второй.ЭлементДокумента;
    КореньВторого.УстановитьАтрибут("a", "1");
    КореньВторого.УстановитьАтрибут("b", "2");
    КореньВторого.ДобавитьДочерний(Второй.СоздатьТекстовыйУзел("A & B"));

    Преобразователь = Новый ПреобразованиеККаноническомуXML;
    Алгоритм = ТипКаноническогоXML.КаноническийXML1_1;
    КанонПервого = Преобразователь.КанонизироватьВСтроку(Первый, Алгоритм);
    КанонВторого = Преобразователь.КанонизироватьВСтроку(Второй, Алгоритм);
    Если КанонПервого <> КанонВторого Тогда
        ВызватьИсключение "Одинаковые данные с разным порядком установки атрибутов должны совпасть";
    КонецЕсли;
    Если КанонПервого <> "<demo a=""1"" b=""2"">A &amp; B</demo>" Тогда
        ВызватьИсключение "Проверьте ожидаемую каноническую форму своего простого документа";
    КонецЕсли;

    Поток = Новый ПотокВПамяти;
    Попытка
        Преобразователь.КанонизироватьВПоток(Первый, Поток, Алгоритм);
        ДанныеПотока = Поток.ЗакрытьИПолучитьДвоичныеДанные();
    Исключение
        ОшибкаКанонизации = ОписаниеОшибки();
        Попытка
            Поток.Закрыть();
        Исключение
            ОшибкаКанонизации = ОшибкаКанонизации + " Ошибка закрытия: " + ОписаниеОшибки();
        КонецПопытки;
        ВызватьИсключение ОшибкаКанонизации;
    КонецПопытки;
    КанонПотока = ПолучитьСтрокуИзДвоичныхДанных(ДанныеПотока, КодировкаТекста.UTF8);
    Если КанонПотока <> КанонПервого Тогда
        ВызватьИсключение "Канонизация в поток должна дать тот же UTF-8 текст";
    КонецЕсли;

    КореньВторого.УстановитьАтрибут("b", "3");
    Измененный = Преобразователь.КанонизироватьВСтроку(Второй, Алгоритм);
    Если Измененный = КанонПервого Тогда
        ВызватьИсключение "Изменение данных должно изменить каноническую строку";
    КонецЕсли;
    Возврат "Строка и поток совпали: " + КанонПервого + "; изменение b обнаружено. Файлы не создавались.";
КонецФункции

Разбор по шагам

  1. Первый и Второй — самостоятельные собственные ДокументDOM. Корни demo содержат атрибуты a=1, b=2 и один текстовый узел A & B; порядок добавления атрибутов противоположный.

  2. Новый ПреобразованиеККаноническомуXML создаёт реальный преобразователь без неизвестного объекта-источника. Для всех вызовов явно выбран один алгоритм КаноническийXML1_1.

  3. КанонизироватьВСтроку вызывается для обоих документов. Сравниваются полные строки, затем проверяется ожидаемая форма простого собственного XML с экранированным амперсандом.

  4. КанонизироватьВПоток записывает первый документ в новый ПотокВПамяти. ЗакрытьИПолучитьДвоичныеДанные завершает поток и отдаёт его реальные байты; UTF-8 декодируется явно.

  5. Текст потока сравнивается с канонической строкой. При ошибке записи отдельно предпринимается закрытие потока, а обе ошибки сохраняются в исключении.

  6. Второй документ меняется на b=3 и канонизируется заново. Несовпадение подтверждает, что алгоритм не скрывает изменение данных. Возвращается только строка итогов.

Как проверить результат

  1. Одинаковые данные дают одинаковую строку независимо от порядка установки a и b.

  2. Ожидается <demo a="1" b="2">A &amp; B</demo>; XML-декларация не входит в эту каноническую строку.

  3. UTF-8 данные потока дают ту же строку; ни один файл не создаётся.

  4. После изменения b=3 каноническая строка отличается от исходной. Повторный запуск создаёт новые документы.

Ожидаемый результат

Строка и поток совпадают; изменение b обнаружено. Канонизация выполняется полностью в памяти.

На что обратить внимание

  1. Канонизация — не красивое форматирование, не шифрование, не подпись и не сравнение бизнес-смысла документов.

  2. Сравнивайте одинаковый алгоритм, одинаковый набор узлов и одинаковые настройки включения пространств имён. В уроке фильтр XPath и список префиксов не используются.

  3. Текстовые пробелы внутри XML являются данными. Не добавляйте форматирующие отступы в собственное дерево и не ожидайте, что канонизация их удалит.

  4. Нельзя заменить выбранный алгоритм старым КаноническаяЗаписьXML или КаноническийDOM и предположить одинаковое поведение: эти объекты не рекомендуются с8.3.9.

  5. После ЗакрытьИПолучитьДвоичныеДанные поток закрыт; последующих операций с ним нет. DOM не возвращается в тонкий клиент.

  6. Ожидаемая строка относится только к этому простому документу без пространств имён, комментариев и DTD. Другой XML требует своих контрольных значений.

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

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.