Как прочитать и изменить текстовое значение элемента XML с атрибутами через Фабрику XDTO

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

При работе с XML-данными в среде 1С программисты часто выбирают ФабрикаXDTO как наиболее мощный и гибкий инструмент. Однако существуют сценарии, которые ставят в тупик даже опытных разработчиков. Один из таких случаев — чтение значения элемента, который одновременно содержит и атрибуты, и текстовое содержимое, особенно если чтение происходит «на лету» без заранее подготовленной XSD-схемы.

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

Анализ проблемы: почему значение «теряется»

Рассмотрим типичный фрагмент XML-файла, с которым возникают сложности:

<ns2:subjectRF dCode="RF7" dRn="1" rRn="1">76</ns2:subjectRF>

Когда мы используем метод Фабрика.ПрочитатьXML(ЧтениеXML), 1С анализирует структуру. Если у нас нет жестко заданной схемы (XSD), система создает объект типа anyType. Для такого объекта атрибуты (dCode, dRn и т.д.) становятся свойствами ОбъектXDTO, и мы можем обратиться к ним напрямую. Однако текстовое значение «76» не привязывается ни к одному именованному свойству. В отладчике мы увидим атрибуты, но само значение элемента будет казаться отсутствующим.

Многие разработчики пытаются использовать системное свойство __content, но оно доступно только в том случае, если в схеме объект описан как complexType с расширением simpleContent. При чтении без схемы этот механизм не работает. Здесь нам на помощь приходит механизм последовательностей.

Решение 1: Извлечение текста через Последовательность

Проанализируем структуру ОбъектXDTO глубже. В 1С объекты XDTO могут поддерживать «смешанное содержимое» (mixed content). Весь текст, который находится внутри тегов, но не принадлежит конкретным дочерним элементам, попадает в специальную коллекцию — последовательность.

Чтобы получить значение «76» из нашего примера, необходимо использовать следующий программный код:


// Предположим, СтруктураДанных.subjectRF — это наш ОбъектXDTO
Попытка
    ТекстовоеЗначение = СтруктураДанных.subjectRF.Последовательность().ПолучитьТекст(0);
    Сообщить("Значение элемента: " + ТекстовоеЗначение);
Исключение
    Сообщить("У объекта нет текстового содержимого в последовательности");
КонецПопытки;

Разберем по шагам, что здесь происходит:

  1. Метод Последовательность() возвращает объект типа ПоследовательностьXDTO. Это упорядоченный набор всех текстовых блоков и дочерних элементов внутри родительского тега.
  2. Метод ПолучитьТекст(Индекс) позволяет достать конкретный текстовый узел. Поскольку в нашем примере текст идет сразу после открытия тега, его индекс — 0.

Решение 2: Изменение текстового значения в существующем объекте

Проанализируем ситуацию, когда нам нужно не только прочитать, но и изменить это значение. Обычная попытка использовать метод Установить() или Добавить() к самому объекту часто приводит к ошибке «Несоответствие типов», так как у anyType нет свойства, отвечающего за контент.

Правильный способ изменения текста заключается в работе с той же последовательностью. Рассмотрим пример кода для замены текста:


Последовательность = СтруктураДанных.subjectRF.Последовательность();
Если Последовательность.Количество() > 0 Тогда
    // Если текст уже есть, мы его перезаписываем по индексу
    Последовательность.УстановитьТекст(0, "НовоеЗначение77");
Иначе
    // Если текста не было, добавляем его
    Последовательность.ДобавитьТекст("НовоеЗначение77");
КонецЕсли;

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

Решение 3: Ошибка «Несоответствие типов» и создание ЗначениеXDTO

Выясним причину ошибки, возникающей при вызове метода Добавить() у объекта. В сообщениях форума упоминалось, что попытка передать обычную строку в СтруктураДанных.Добавить(ИмяСвойства, Значение) вызывает исключение. Это происходит потому, что ФабрикаXDTO ожидает объект типа ЗначениеXDTO или ОбъектXDTO, а не примитивный тип 1С (строку или число).

Чтобы «на лету» превратить обычную строку в формат, понятный фабрике, выполним следующие действия:


// Создаем тип "string" из стандартного пространства имен XML Schema
ТипСтрока = Фабрика.Тип("http://www.w3.org/2001/XMLSchema", "string");

// Создаем ЗначениеXDTO на основе нашей строки
НовоеЗначениеXDTO = Фабрика.Создать(ТипСтрока, "76");

// Теперь это значение можно корректно использовать в методах XDTO
// Например, в последовательности:
СтруктураДанных.subjectRF.Последовательность().Добавить(НовоеЗначениеXDTO);

Альтернативный способ: Использование модели DOM

Если структура XML очень сложная или работа с последовательностями XDTO кажется избыточной для разовой задачи, мы можем рассмотреть использование ДокументDOM. В отличие от XDTO, модель DOM предоставляет прямой доступ к текстовому узлу любого элемента через свойство ТекстовоеСодержимое.

Рассмотрим краткий пример реализации:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(вхТекстXML);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

// Поиск нужного узла
Узел = ДокументDOM.ПолучитьЭлементыПоИмени("ns2:subjectRF").Получить(0);
Если Узел <> Неопределено Тогда
    Значение = Узел.ТекстовоеСодержимое; // Сразу получим "76"
КонецЕсли;

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

Подведем итоги

Мы проанализировали основные сложности при работе со смешанным контентом в ФабрикаXDTO. Главный вывод: если объект содержит и атрибуты, и текст, его текстовое значение всегда ищите в Последовательность().

Краткая шпаргалка для разработчика:

Используя эти методы, вы сможете корректно обрабатывать XML любой сложности, сохраняя все преимущества строгой типизации XDTO.

← На главную