При формировании электронных документов в формате XML для систем электронного документооборота (ЭДО), таких как Диадок, программисты часто сталкиваются с жесткими требованиями XSD-схем. Одной из самых распространенных проблем в 1С 7.7 является появление лишних пробелов и символов перевода строки внутри тегов. Это происходит из-за особенностей работы со стандартными текстовыми файлами и попыток сделать XML «читаемым» для человека. Рассмотрим, почему это происходит и как правильно сформировать файл, чтобы он прошел валидацию.
Проанализируем ситуацию, описанную автором темы. При ручной сборке XML-файла с помощью методов записи в текст (например, через WriteLine) в файл попадают невидимые символы. В примере автора тег БезАкциз выглядит так:
<Акциз>
<БезАкциз>
без акциза
</БезАкциз>
</Акциз>
Для человека это выглядит аккуратно, но для программного парсера значением тега становится не строка без акциза, а строка с символом переноса строки в начале и несколькими пробелами. Согласно приказу ФНС, регулирующему формат УПД, значение этого поля должно строго соответствовать шаблону. Любой лишний символ делает документ невалидным.
Выясним причину в коде. Автор использует процедуру xml_file.WriteLine, которая принудительно добавляет \r\n (перевод строки и возврат каретки) после каждой команды. Кроме того, в коде программно добавляются «отступы» для красоты структуры. Именно эти отступы и переносы внутри текстового узла вызывают ошибку.
Если мы продолжаем использовать текстовую выгрузку, нам необходимо исключить использование WriteLine для элементов, содержащих конечные данные. Разберем по шагам, как изменить логику записи.
Во-первых, заменим метод WriteLine на Write в тех местах, где мы записываем значение тега. Во-вторых, необходимо отказаться от записи отступов перед закрывающим тегом, если внутри него находится текст. Посмотрим на исправленный фрагмент логики:
// Вместо этого:
xml_file.WriteLine(">");
xml_file.WriteLine(xml_Отступы + прм_Текст);
// Нужно записывать всё в одну строку без перевода:
xml_file.Write(">" + прм_Текст + "</" + стрИмяТега + ">");
Проанализируем ситуацию с тегом Акциз. Чтобы получить правильный результат, код вызова должен выглядеть примерно так:
xml_ЗаписатьНачалоЭлемента("Акциз");
// Для текстового узла пишем все в одну строку без перевода каретки
xml_file.Write("<БезАкциз>без акциза</БезАкциз>");
xml_ЗаписатьКонецЭлемента("Акциз");
Важный момент: Обратите внимание на закрывающий слэш. Ошибка в синтаксисе типа /<БезАкциз> или отсутствие слэша в закрывающем теге (как было замечено в обсуждении) приведет к полной нечитаемости XML-структуры.
Использование текстовых функций в 1С 7.7 — это путь, полный ошибок (экранирование спецсимволов, кодировки, переносы). Рассмотрим более надежный метод с использованием COM-объекта MSXML2.DOMDocument. Этот объект сам следит за тем, чтобы структура была корректной, а текстовые узлы не содержали лишнего мусора.
Разберем реализацию этого метода. Для начала создадим объект и определим базовые функции для работы с узлами. Это позволит нам писать код в стиле, близком к 1С 8.x.
Проанализируем функции-помощники:
// Функция создания узла
Функция ДобавитьУзел(XML_DOM, XML_NODE, Имя)
XML_CHILD = XML_DOM.createNode(1, Имя, "");
XML_NODE.appendChild(XML_CHILD);
Возврат XML_CHILD;
КонецФункции
// Функция добавления текста в узел
Процедура ДобавитьТекст(XML_NODE, Значение)
XML_NODE.text = Значение;
КонецПроцедуры
// Функция добавления атрибута
Процедура ДобавитьАтрибут(XML_NODE, Имя, Значение)
XML_NODE.setAttribute(Имя, Значение);
КонецПроцедуры
Теперь посмотрим, как с помощью этих функций решить задачу автора темы без риска получить лишние пробелы:
XML_DOM = СоздатьОбъект("MSXML2.DOMDocument.6.0");
// Создаем корень и структуру
Root = XML_DOM.createElement("Файл");
XML_DOM.appendChild(Root);
// Добавляем таблицу и сведения о товаре
СведТов = ДобавитьУзел(XML_DOM, Root, "СведТов");
ДобавитьАтрибут(СведТов, "НаимТов", "Известь строительная");
// Формируем блок Акциз
Акциз = ДобавитьУзел(XML_DOM, СведТов, "Акциз");
БезАкциз = ДобавитьУзел(XML_DOM, Акциз, "БезАкциз");
ДобавитьТекст(БезАкциз, "без акциза"); // Здесь DOM никогда не добавит лишний перевод строки!
// Сохраняем файл
XML_DOM.save("C:\exports\upd.xml");
В процессе обсуждения возник вопрос о странности структуры <СумНал><СумНал>...</СумНал></СумНал>. Выясним, является ли это ошибкой. Согласно формату ФНС для УПД:
СумНал — это составной элемент, описывающий налоговую составляющую строки.СумНал — это непосредственное значение суммы налога.Следовательно, такая иерархия абсолютно корректна и должна сохраняться. При использовании ручного метода записи программисты часто ошибаются и «схлопывают» эти теги, что приводит к отказу в приеме файла со стороны Диадока.
При использовании текстового метода (Решение №1) крайне важно не забывать про спецсимволы. Если в наименовании товара встретится амперсанд & или кавычка ", XML «развалится». В 1С 7.7 необходимо вручную обрабатывать каждую строку через СтрЗаменить:
& заменяем на &< заменяем на <> заменяем на >" заменяем на "Важный совет: Если вы перейдете на MSXML2.DOMDocument, все эти замены объект будет выполнять автоматически. Вы просто передаете строку как есть в свойство text, и система сама преобразует её в валидный XML-вид.
Подводя итог, можно сказать, что проблема автора вызвана исключительно попыткой форматирования вывода (красивые отступы и переводы строк). Для систем ЭДО визуальная красота XML не имеет значения, важна лишь строгость структуры и точность значений.
Мы рекомендуем:
WriteLine в пользу Write при формировании содержимого тегов.ADODB.Stream, если требуется запись в специфических кодировках (например, UTF-8 без BOM), так как стандартные средства 1С 7.7 ограничены в этом плане.MSXML2.DOMDocument, что снимет 90% проблем с форматированием, кодировками и спецсимволами.Следуя этим правилам, вы сможете успешно интегрировать 1С 7.7 с современными системами электронного документооборота и избежать длительных простоев из-за ошибок валидации.