Как передать пустую дату в формате 0000-00-00 в XML из 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции систем 1С с внешними программными продуктами (особенно на базе старых версий MySQL или специфических легаси-решений) разработчики часто сталкиваются с требованием передать "пустую" дату именно в формате 0000-00-00T00:00:00. Однако стандарт XML Schema (W3C), которому строго следует платформа 1С, считает такую запись недопустимой. Согласно спецификации ISO 8601, летоисчисление начинается с 0001 года, и "нулевого" года не существует.

В этой статье мы подробно разберем, почему возникает эта проблема и какими способами ее можно обойти, сохранив работоспособность обмена данными.

Проанализируем причину возникновения ошибки

Когда мы пытаемся передать в функцию XMLСтрока() пустую дату 1С — Дата(1, 1, 1) — платформа преобразует ее в канонический вид 0001-01-01T00:00:00. Если же мы пытаемся вручную записать строку 0000-00-00T00:00:00 в узел, типизированный как dateTime, сериализатор 1С выдает ошибку соответствия простому типу. Это происходит потому, что валидатор проверяет значение на соответствие правилам XSD перед записью.

Способ 1. Использование текстовой замены (Post-processing)

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

  1. Сформируем XML-документ обычным способом, используя ЗаписьXML.
  2. Для пустых дат используем стандартное значение Дата(1, 1, 1).
  3. Выгружаем результат в строку.
  4. Выполняем замену подстроки 0001-01-01T00:00:00 на требуемую 0000-00-00T00:00:00.
  5. Записываем итоговую строку в файл или отправляем в HTTP-запрос.

Посмотрим на пример реализации данного метода:


// Сначала формируем XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// ... логика записи узлов ...
// Предположим, мы записали пустую дату:
ЗаписьXML.ЗаписатьСоответствующееЗначение(Дата(1,1,1), "PartsOrderReceivedDateTime");

ТекстXML = ЗаписьXML.Закрыть();

// Выполняем подмену "неправильного" года
ТекстXML = СтрЗаменить(ТекстXML, "0001-01-01T00:00:00", "0000-00-00T00:00:00");

// Теперь ТекстXML содержит требуемый формат для внешней системы

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

Способ 2. Изменение типа данных в XDTO-пакете

Если вы используете XDTO для генерации XML, система будет жестко контролировать типы. Чтобы обойти ограничение типа dateTime, мы можем изменить определение элемента в схеме. Рассмотрим ситуацию, когда мы меняем тип данных элемента на string (строку).

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

  1. В объекте XDTO-пакет найдите нужное свойство.
  2. Измените его тип с {http://www.w3.org/2001/XMLSchema}dateTime на {http://www.w3.org/2001/XMLSchema}string.
  3. При заполнении значения свойства проверяйте: если дата пустая, передавайте строку "0000-00-00T00:00:00", если заполнена — преобразуйте ее в XML-строку самостоятельно.

Пример кода при использовании измененного XDTO-пакета:


Если ЗначениеЗаполнено(Объект.ДатаПриема) Тогда
    ОбъектXDTO.PartsOrderReceivedDateTime = XMLСтрока(Объект.ДатаПриема);
Иначе
    ОбъектXDTO.PartsOrderReceivedDateTime = "0000-00-00T00:00:00";
КонецЕсли;

Способ 3. Работа через объектную модель DOM

Использование ЗаписьDOM позволяет более гибко управлять содержимым узлов. В отличие от прямой записи через ЗаписьXML с типизацией, DOM-модель позволяет создать текстовый узел с любым содержимым. Разберем, как это реализовать.

Проанализируем пример кода:


ДокументDOM = Новый ДокументDOM;
КорневойУзел = ДокументDOM.СоздатьЭлемент("Data");
ДокументDOM.ДобавитьПодчиненный(КорневойУзел);

ЭлементДата = ДокументDOM.СоздатьЭлемент("PartsOrderReceivedDateTime");
// Мы просто записываем текст, 1С не проверяет формат даты в DOM-узле
ТекстДаты = ДокументDOM.СоздатьТекстовыйУзел("0000-00-00T00:00:00");
ЭлементДата.ДобавитьПодчиненный(ТекстДаты);
КорневойУзел.ДобавитьПодчиненный(ЭлементДата);

// Записываем DOM в файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\export.xml");
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();

Способ 4. Передача пустого значения (xsi:nil)

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

В XML это выглядит так: <DateNode xsi:nil="true" />. В 1С при работе с XDTO это реализуется установкой свойства в значение Неопределено (при условии, что в схеме установлен флаг Возможно пустое / nillable).


// Если в XDTO свойство помечено как nillable
ОбъектXDTO.DateNode = Неопределено; 
// При сериализации 1С сама добавит атрибут xsi:nil="true"

Резюме

Выбор метода зависит от гибкости принимающей стороны. Если они категорически требуют 0000-00-00, наиболее надежным и простым методом остается Способ 1 (СтрЗаменить). Если же вы проектируете систему с нуля, старайтесь придерживаться типа string для таких полей или использовать стандартный xsi:nil, чтобы избежать конфликтов со спецификацией XML.

← На главную