[РЕШЕНО] Проверить пустой узел xml

Тема в разделе "Конфигурирование на платформе "1С:Предприятие 8"", создана пользователем Samouchka, 13 окт 2015.

  1. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Приветствую всех. В файле xml есть узел "ФайлПФР" типа "элемент" комплексного типа данных (ну т.е. состоит из атрибутов и других элементов). Сначала нужно записать атрибуты и элементы, если их текст не пустой. А затем записать элемент "ФайлПФР" при условии что он не пустой (т.е. содержит хотя бы 1 подчиненный элемент). Но, соответственно, провернуть это в нужном порядке, а не последовательно. Можно ли определить будет ли "ФайлПФР" пустой, не перебирая все текстовые значения, влияющие на его заполнение? Щас могу решить задачу только так - представляю упрощенный код:

    Код:
    Окружение_Ат1="";
        ИмяФайла_Эл1="";
       
        XML=Новый ЗаписьXML;
        XML.ОткрытьФайл(КаталогВыгрузкиXML,"Windows-1251");
        XML.ЗаписатьОбъявлениеXML();
       
        Если Окружение_Ат1<>"" Тогда
        Если ИмяФайла_Эл1<>"" Тогда
               
        XML.ЗаписатьНачалоЭлемента("ФайлПФР");
       
        Если Окружение_Ат1<>"" Тогда
            XML.ЗаписатьНачалоАтрибута("Окружение");
            XML.ЗаписатьТекст(Окружение_Ат1);
            XML.ЗаписатьКонецАтрибута();
        КонецЕсли;
       
        Если ИмяФайла_Эл1<>"" Тогда
            XML.ЗаписатьНачалоЭлемента("ИмяФайла");
            XML.ЗаписатьТекст(ИмяФайла_Эл1);
            XML.ЗаписатьКонецЭлемента();
        КонецЕсли;
       
        XML.ЗаписатьКонецЭлемента();
       
        КонецЕсли;
        КонецЕсли;
    
        XML.Закрыть();
    Надо обойтись без
    Код:
    Если Окружение_Ат1<>"" Тогда
    Если ИмяФайла_Эл1<>"" Тогда
    поскольку таких условий будет невероятно много, и узел подобный "ФайлПФР" не один (метод проверки пустого элемента мне нужен и во всех других случаях). Конечные узлы перебирать все равно надо вручную, т.к. у них может быть разный тип данных (где-то надо проверить не пустой ли текст, а где-то не равенство 0). Как после этого не записывать комплексный элемент, если он окажется пустым? Объект ЗаписьXML думаю, не подойдет, поскольку он пишет последовательно. Оптимально будет узнать, станет ли "ФайлПФР" пустым еще до записи текстовых (конечных) узлов. Не оптимально, но тоже подойдет, если после записи всех (и комплексных, и конечных) элементов перебрать и удалить пустые узлы. Я, к сожалению, не знаю код для обоих случаев, поэтому обращаюсь за помощью. Благодарю заранее.
  2. Ktyf
    Offline

    Ktyf Опытный в 1С

    Регистрация:
    16 янв 2013
    Сообщения:
    457
    Симпатии:
    12
    Баллы:
    29
    Не совсем поняла, что вам нужно, но может поможет построительDOM:
    Код:
    ЧтениеXML    = Новый ЧтениеXML;
            ЧтениеXML.ОткрытьФайл(ФайлДанных,,,"windows-1251");
            ПостроительДОМ    = Новый ПостроительDOM;
            ДокументДОМ     = ПостроительДОМ.Прочитать(ЧтениеXML);
            Док    = ДокументДОМ.ПолучитьЭлементыПоИмени("Данные");
            КолВо = Док.Количество();
    Если количество =0 - значит ФайлПФР -пустой и можно не заморачиваться
    Samouchka нравится это.
  3. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Ну вообще у вас не совсем оптимальное построение кода.
    Зачем вам куча переменных?
    Засовываете их например в структуру (или соответствие).
    Тогда ваша задача решается элементарно, что то типа такого:

    Код:
    ---------------------------
    СтруктураЭлементы = Новый Структура;
    СтруктураЭлементы .Вставить("ИмяФайла", ИмяФайла_Эл1);
    и т.д.......
    
    
    Если НадоВставлятьЭлементы(СтруктураЭлементы) Тогда
    
    XML.ЗаписатьНачалоЭлемента("ФайлПФР");
    
    Для каждого КлючЗначение Из СтруктураЭлементы Цикл
    XML.ЗаписатьНачалоЭлемента(КлючЗначение.Ключ);
    XML.ЗаписатьТекст(КлючЗначение.Значение);
    XML.ЗаписатьКонецЭлемента();
    КонецЦикла;
    
    XML.ЗаписатьКонецЭлемента();
    КонецЕсли;
    
    ---------------------------
    Функция НадоВставлятьЭлементы(Структура)
    Результат = Ложь;
    Для каждого КлючЗначение Из Структура Цикл
    Если ЗначениеЗаполнено(КлючЗначение.Значение) Тогда
    Результат = Истина;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
    КонецФункции;
    Samouchka нравится это.
  4. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    shurikvz, у меня по поводу написания кода для выгрузки xml, есть своя процедура. Вот она:
    Код:
    СчИдентиф=0;
        СчИдентиф2=0;
        СчетчикСтрок=0;
       
        Текст=Новый ТекстовыйДокумент;
        Текст.ДобавитьСтроку("Процедура ВыгрузитьНажатие(Элемент)");
        Текст.ДобавитьСтроку("");
       
        //Код диалога открытия файла
        Текст.ДобавитьСтроку("ИмяФайла=""ФайлВыгрузаПроверка.xml"";");
        Текст.ДобавитьСтроку("Диал=Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);");
        Текст.ДобавитьСтроку("Диал.Заголовок=""Выберите каталог для выгрузки файла"";");
        Текст.ДобавитьСтроку("");
       
        Текст.ДобавитьСтроку("Если Диал.Выбрать()=ложь Тогда");
        Текст.ДобавитьСтроку("    Предупреждение(""Не выбран каталог!"");");
        Текст.ДобавитьСтроку("    Возврат;");
        Текст.ДобавитьСтроку("КонецЕсли;");
        Текст.ДобавитьСтроку("КаталогВыгрузкиXML=Диал.Каталог+""\""+ИмяФайла;");
        Текст.ДобавитьСтроку("");
       
        Чтение=Новый ЧтениеXML;
        Чтение.ОткрытьФайл(КаталогЗагрузкиXMLфайла);
       
        Текст.ДобавитьСтроку("XML=Новый ЗаписьXML;");
        Текст.ДобавитьСтроку("XML.ОткрытьФайл(КаталогВыгрузкиXML,""Windows-1251"");");
        Текст.ДобавитьСтроку("XML.ЗаписатьОбъявлениеXML();");
        Текст.ДобавитьСтроку("");
        СчетчикСтрок=16;
    
        Пока Чтение.Прочитать() Цикл
            // Прочитать "структурные части" элементов.
            // Проверить, какая часть элемента - текущая.
            Если Чтение.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда
                ИмяУзла=Чтение.Имя;
               
                Текст.ДобавитьСтроку("XML.ЗаписатьНачалоЭлемента("""+ИмяУзла+""");");
                СчетчикСтрок=СчетчикСтрок+1;
                // Атрибуты элементов можно читать только если текущая часть -
                // начало элемента
                Пока Чтение.ПрочитатьАтрибут() Цикл
    
                    // Прочитать данные узла атрибута.
                    ТипУзла=Чтение.ТипУзла;
                    Имя=Чтение.Имя;
                    ЗначениеАт=Чтение.Значение;
                   
                    //С учетом того что в xml могут быть элементы и атрибуты с одинаковыми именами в разных узлах,
                    //сформируем уникальные имена (например, для дальнейшего создания реквизитов формы документа)
                    //_Ат - префикс атрибута, _Эл - элемента
                   
                    СчИдентиф=СчИдентиф+1;
                    ТекстВАтрибуте=Имя+"_Ат"+СчИдентиф;
                    Текст.ДобавитьСтроку("Если "+ТекстВАтрибуте+"<>"""" "+"Тогда");
                    Текст.ДобавитьСтроку("    XML.ЗаписатьНачалоАтрибута("""+Имя+""");");
                    Текст.ДобавитьСтроку("    XML.ЗаписатьТекст("+ТекстВАтрибуте+");");
                    Текст.ДобавитьСтроку("    XML.ЗаписатьКонецАтрибута();");
                    Текст.ДобавитьСтроку("КонецЕсли;");
                    Текст.ДобавитьСтроку("");
                    СчетчикСтрок=СчетчикСтрок+6;
                    стр=АтрибутыИЭлементы.Добавить();
                    стр.НаименованиеАтрибЭлем=Имя+"_Ат"+СчИдентиф;
                    стр.ЗначениеАтрибЭлем=""""+ЗначениеАт+"""";
                КонецЦикла;
               
            ИначеЕсли Чтение.ТипУзла=ТипУзлаXML.Текст Тогда
                СчИдентиф2=СчИдентиф2+1;
                ЗначениеЭл=Чтение.Значение;
                Имя2=ИмяУзла;
               
                ТекстВУзле=Имя2+"_Эл"+СчИдентиф2;
                Текст.УдалитьСтроку(СчетчикСтрок);
                СчетчикСтрок=СчетчикСтрок-1;
                Текст.ДобавитьСтроку("Если "+ТекстВУзле+"<>"""" "+"Тогда");
                Текст.ДобавитьСтроку("    XML.ЗаписатьНачалоЭлемента("""+ИмяУзла+""");");
                Текст.ДобавитьСтроку("    XML.ЗаписатьТекст("+ТекстВУзле+");");
                Текст.ДобавитьСтроку("    XML.ЗаписатьКонецЭлемента();");
                Текст.ДобавитьСтроку("КонецЕсли;");
                НадоУдалить=истина;
                СчетчикСтрок=СчетчикСтрок+5;
                стр=АтрибутыИЭлементы.Добавить();
                стр.НаименованиеАтрибЭлем=Имя2+"_Эл"+СчИдентиф2;
                стр.ЗначениеАтрибЭлем=""""+ЗначениеЭл+"""";
            ИначеЕсли Чтение.ТипУзла=ТипУзлаXML.КонецЭлемента Тогда
                Текст.ДобавитьСтроку("XML.ЗаписатьКонецЭлемента();");
                СчетчикСтрок=СчетчикСтрок+1;
                Если НадоУдалить=истина Тогда
                    Текст.УдалитьСтроку(СчетчикСтрок);
                    СчетчикСтрок=СчетчикСтрок-1;
                    НадоУдалить=ложь;
                КонецЕсли;
                Текст.ДобавитьСтроку("");
                СчетчикСтрок=СчетчикСтрок+1;
            ИначеЕсли
            //Инструкция обработки
                Чтение.ТипУзла=ТипУзлаXML.ИнструкцияОбработки Тогда
                ИнстОбрИмя=Чтение.Имя;
                ИнстОбрТекст=Чтение.Значение;
                ИнстОбрИмя1=""""+ИнстОбрИмя+"""";
                ИнстОбрТекст1=""""+ИнстОбрТекст+"""";
                Текст.ДобавитьСтроку("XML.ЗаписатьИнструкциюОбработки("+ИнстОбрИмя1+","+ИнстОбрТекст1+");");
                Текст.ДобавитьСтроку("");
                СчетчикСтрок=СчетчикСтрок+2;
            КонецЕсли;
        КонецЦикла;
       
        Текст.ДобавитьСтроку("XML.Закрыть();");
        Текст.ДобавитьСтроку("КонецПроцедуры");
        СчетчикСтрок=СчетчикСтрок+2;
        //выводим результат в строку
        КодВКонфигуратор1С=Текст.ПолучитьТекст();
    От такого кода остаются пустые узлы. Надо дополнить код, чтобы удалялись пустые узлы. Для этого надо узнать, как это сделать в записанном xml-файле. Поэтому в данной теме я привожу пример на простом файле.
    --- Объединение сообщений, 14 окт 2015 ---
    shurikvz, просто в Вашем примере надо самому расшаривать структуру под каждый элемент, вот в чем дело.
    Последнее редактирование: 14 окт 2015
  5. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Ну тогда гоздавайте документ DOM после формирования файла, и работайте с ним.
    В #2 начало уже подсказали.

    Находите элемент ФайлПФР (ПолучитьЭлементыПоИмени())
    Смотрите пустой он или нет (Количество())
    Если Пустой удаляете его (родитель -> УдалитьДочерний())
    Записываете.
    Samouchka нравится это.
  6. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Нужно сделать следующее:
    1) Записать файл xml.
    Файл следующей структуры (в упрощенном виде):

    <ФайлПФР Окружение="1">
    <ИмяФайла>2</ИмяФайла>
    </ФайлПФР>

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

    2) Обработать записанный файл, удалив пустые узлы

    3) Сохранить результат обработки 2) в новый файл xml.

    А если получится сразу в п. 1) узнать, что узел составного типа данных будет пуст ("ФайлПФР" в моем примере), то будет вашпе замечательно.
    С п. 1) только и справляюсь, в остальном вопросы (в комментариях к коду):

    Код:
    //Диалог сохранения файла, вывод полных имен исходного и обработанного файлов
        Диал=Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
        Диал.ПолноеИмяФайла="ИсходныйФайл.xml";
        Диал.Заголовок="Выберите каталог для выгрузки файла";
       
        Если Диал.Выбрать() Тогда
            ВыбранФайл=Диал.ВыбранныеФайлы;
            Для Каждого ИмяВыбранногоФайла Из ВыбранФайл Цикл
                ВыбранныйФайл=Новый Файл(ИмяВыбранногоФайла);
                КаталогВыгрузкиXML=ВыбранныйФайл.ПолноеИмя;
                КаталогВыгрузкиXML2=Диал.Каталог+"ОбработанныйФайл.xml";
            КонецЦикла;
        Иначе
            Предупреждение("Не выбран каталог!");
            Возврат;
        КонецЕсли;
       
       
        //Запись XML-файла. Не записываются конечные узлы, если их значения пусты
        //Для проверки работы примера я определил пустые узлы.
        //Но они могут быть разными: как пустыми, так и нет
       
        Окружение_Ат1="";
        ИмяФайла_Эл1="";
       
        XML=Новый ЗаписьXML;
        XML.ОткрытьФайл(КаталогВыгрузкиXML,"Windows-1251");
        XML.ЗаписатьОбъявлениеXML();
                   
        XML.ЗаписатьНачалоЭлемента("ФайлПФР");
       
        Если Окружение_Ат1<>"" Тогда
            XML.ЗаписатьНачалоАтрибута("Окружение");
            XML.ЗаписатьТекст(Окружение_Ат1);
            XML.ЗаписатьКонецАтрибута();
        КонецЕсли;
       
        Если ИмяФайла_Эл1<>"" Тогда
            XML.ЗаписатьНачалоЭлемента("ИмяФайла");
            XML.ЗаписатьТекст(ИмяФайла_Эл1);
            XML.ЗаписатьКонецЭлемента();
        КонецЕсли;
       
        XML.ЗаписатьКонецЭлемента();
        XML.Закрыть();
       
       
       
        //Обработка исходного файла. Все пустые узлы надо удалить
        ЧтениеXML=Новый ЧтениеXML;
        ЧтениеXML.ОткрытьФайл(КаталогВыгрузкиXML);
        ПостроительДОМ=Новый ПостроительDOM;
        ДокументДОМ=ПостроительДОМ.Прочитать(ЧтениеXML);
        Док=ДокументДОМ.ПолучитьЭлементыПоИмени(ДокументДОМ.ИмяУзла);
        КолВо=Док.Количество();
        Если КолВо=0 Тогда
            //Как здесь удалить узел "Док"?
        КонецЕсли;
       
       
       
        //Запись обработки в другой файл
        КопироватьФайл(КаталогВыгрузкиXML,КаталогВыгрузкиXML2);
        XML2=Новый ЗаписьXML;
        XML2.ОткрытьФайл(КаталогВыгрузкиXML2,"Windows-1251");
        //Как записать результат после применения DOM?
        //XML2.Записать(); - такого метода нет!
        //Да и как определить то, что надо записать?
        XML2.Закрыть();
  7. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    что такое ДокументДОМ.ИмяУзла?
    Вы знаете какие элементы вам надо проконтролировать? Их и ищите по имени.
    Т.е. для вашего конкретного примера что то вроде:
    Код:
    ЭлементыПФР = ДокументДОМ.ПолучитьЭлементыПоИмени("ФайлПФР");
    Если ЭлементыПФР[0].ДочерниеУзлы.Количество() = 0 Тогда
    ДокументДОМ.УдалитьДочерний(ЭлементыПФР[0]);
    КонецЕсли;
    
    Для реального файла может быть по другому, надо структуру файла видеть.



    Пример:
    Код:
      ЗаписьXML = Новый ЗаписьXML;
       ЗаписьXML.ОткрытьФайл(ИмяФайла, "windows-1251");
       ЗаписьDOM = Новый ЗаписьDOM;
       ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
       ЗаписьXML.Закрыть();
    
  8. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Я дико перед всеми извиняюсь за неправильное определение пустого узла. Щас понял: я имею ввиду под пустым узлом тот узел, который не содержит в себе ни одного узла текстового типа. Т.е. если в узле (вместе со всеми его дочерними узлами) нет ни одного узла текстового типа, то надо удалить такой узел. Если где-либо в узле есть узел текствого типа, то оставить. Например, есть файл:

    Код:
    <ФайлПФР>
        <ИмяФайла>
            <НазваниеФормата/>
            <НазваниеПрограммы/>
        </ИмяФайла>
        <ТипФайла>
            <ОписаниеТиповФайла>Внешний</ОписаниеТиповФайла>
            <Запрос/>
        </ТипФайла>
    </ФайлПФР>
    Получить нужно:

    Код:
    <ФайлПФР>
        <ТипФайла>
            <ОписаниеТиповФайла>Внешний</ОписаниеТиповФайла>
        </ТипФайла>
    </ФайлПФР>
  9. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Ну обходите тогда дерево рекурсивно и смотрите, если количество дочерних узлов у ветки = 0, тогда удаляйте эту ветку.
  10. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Не катит здесь метод УдалитьДочерний(). Взгляните еще раз на файл:

    Код:
    <ФайлПФР>
        <ИмяФайла>
            <НазваниеФормата/>
            <НазваниеПрограммы/>
        </ИмяФайла>
        <ТипФайла>
            <ОписаниеТиповФайла>Внешний</ОписаниеТиповФайла>
            <Запрос/>
        </ТипФайла>
    </ФайлПФР>
    Эти методом удалятся <НазваниеФормата/>, <НазваниеПрограммы/>, Внешний, <Запрос/>, но не удалится <ИмяФайла>. Что произойдет если как-то зациклить метод? Да удаляться все узлы! Для данного примера удаляются узлы:
    при 1-м цикле: <НазваниеФормата/>, <НазваниеПрограммы/>, Внешний, <Запрос/>
    при 2-м цикле: <ИмяФайла>, <ОписаниеТиповФайла>
    при 3-м цикле: <ТипФайла>
    при 4-м цикле: <ФайлПФР>.

    Вывод: если не распознать текстовый узел внутри узла, то ничего не получится. Текстовые узлы не удалять в любом случае, остальные узлы удалять по условию, что внутри них нет ни одного текстового узла. Как посчитать число узлов текстового типа внутри узла? Тогда всё можно сделать.
  11. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Вы что-то не так делаете.

    З.Ы.
    Удалять надо узел, если он имеет тип Элемент.
  12. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Вот так 1С пишет ошибку "Узел не найден". Возможно из-за того, что у меня ТекУзел может содержать один из нескольких типов данных: АтрибутDOM, ДокументDOM, ЭлементDOM, ОпределениеТипаДокументаDOM, НотацияDOM, СущностьDOM, ФрагментДокументаDOM, ТекстDOM, КомментарийDOM, СекцияCDATADOM, ИнструкцияОбработкиDOM, СсылкаНаСущностьDOM, ПространствоИменXPath (так указано в СП). А нужен определенный тип: ЭлементDOM. Но так я и пишу условие на тип "элемент". Что не так, подскажите, плиз?

    Код:
    ЧтениеXML=Новый ЧтениеXML;
        ЧтениеXML.ОткрытьФайл(КаталогВыгрузкиXML);
          
        УдалУзел=ложь;
        ПостроительДОМ=Новый ПостроительDOM;
        ДокументДОМ=ПостроительДОМ.Прочитать(ЧтениеXML);
        ДревоXML=ДокументДОМ.СоздатьОбходДерева(ДокументДОМ);
        Пока ДревоXML.СледующийУзел()<>Неопределено Цикл
            ТекУзел=ДревоXML.ТекущийУзел;
            СписАтриб=ТекУзел.Атрибуты;
            Если ТекУзел.ТипУзла=ТипУзлаDOM.Элемент Тогда
                КолАтриб=СписАтриб.Количество();
                Если КолАтриб=0 Тогда
                    УдалУзел=истина;
                КонецЕсли;
              
                Если УдалУзел=истина Тогда
                    Если ТекУзел.ЕстьДочерниеУзлы()=ложь Тогда
                        ТекУзел.УдалитьДочерний(ТекУзел);
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
    Последнее редактирование модератором: 26 окт 2015
  13. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Щас удаляется только один узел, и дальше цикл останавливается. Что я пишу не так?

    Код:
    ЧтениеXML=Новый ЧтениеXML;
        ЧтениеXML.ОткрытьФайл(КаталогВыгрузкиXML2);
           
        УдалУзел=ложь;
        ПостроительДОМ=Новый ПостроительDOM;
        ДокументДОМ=ПостроительДОМ.Прочитать(ЧтениеXML);
        ДревоXML=ДокументДОМ.СоздатьОбходДерева(ДокументДОМ);
        Пока ДревоXML.СледующийУзел()<>Неопределено Цикл
            ТекУзел=ДревоXML.ТекущийУзел;
            СписАтриб=ТекУзел.Атрибуты;
            Если ТекУзел.ТипУзла=ТипУзлаDOM.Элемент Тогда
                КолАтриб=СписАтриб.Количество();
                Если КолАтриб=0 Тогда
                    УдалУзел=истина;
                КонецЕсли;
               
                Если УдалУзел=истина Тогда
                    Если ТекУзел.ЕстьДочерниеУзлы()=ложь Тогда
                        ТекУзел.РодительскийУзел.УдалитьДочерний(ТекУзел);
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
       
        //Запись обработки в другой файл
        ЧтениеXML.Закрыть();
        XML2=Новый ЗаписьXML;
        XML2.ОткрытьФайл(КаталогВыгрузкиXML2,"Windows-1251");
        ЗаписьДом=Новый ЗаписьDOM;
        ЗаписьДом.Записать(ДокументДОМ,XML2);
        XML2.Закрыть();
  14. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Вот рабочий код. А можно как-то обойтись без перезаписи файла каждый раз? Просто у меня удалив узлы в одном цикле, могут получится новые пустые узлы. Поэтому зацикливаю и перезаписываю файл до тех по пока каждый узел будет иметь дочерние узлы (т.е. оставляю таким образом узлы, содержащие информацию - текстовые элементы и атрибуты.

    Код:
    //Обработка исходного файла. Все пустые узлы надо удалить       
        УдалУзел=ложь;
        ПродолжУдален=истина;
        ТабУзлов=Новый ТаблицаЗначений;
        ТабУзлов.Колонки.Добавить("Пахан");
        ТабУзлов.Колонки.Добавить("Сын");
       
        Пока ПродолжУдален=истина Цикл
            ЧтениеXML=Новый ЧтениеXML;
            ЧтениеXML.ОткрытьФайл(КаталогВыгрузкиXML);
       
            ПостроительДОМ=Новый ПостроительDOM;
            ДокументДОМ=ПостроительДОМ.Прочитать(ЧтениеXML);
            ДревоXML=ДокументДОМ.СоздатьОбходДерева(ДокументДОМ);
           
            Пока ДревоXML.СледующийУзел()<>Неопределено Цикл
                ТекУзел=ДревоXML.ТекущийУзел;
                СписАтриб=ТекУзел.Атрибуты;
                Если ТекУзел.ТипУзла=ТипУзлаDOM.Элемент Тогда
                    КолАтриб=СписАтриб.Количество();
                    Если КолАтриб=0 Тогда
                        УдалУзел=истина;
                    КонецЕсли;
                    Если КолАтриб>0 Тогда
                        УдалУзел=ложь;
                    КонецЕсли;
                   
                    Если УдалУзел=истина Тогда
                        Если ТекУзел.ЕстьДочерниеУзлы()=ложь Тогда
                            СтрУзлов=ТабУзлов.Добавить();
                            СтрУзлов.Пахан=ТекУзел.РодительскийУзел;
                            СтрУзлов.Сын=ТекУзел;
                        КонецЕсли;
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
           
            Если ТабУзлов.Количество()>0 Тогда
                ПродолжУдален=истина;
                Для сч=0 по ТабУзлов.Количество()-1 Цикл
                    УзелКУдал=ТабУзлов.Получить(сч);
                    УзелКУдал.Пахан.УдалитьДочерний(УзелКУдал.Сын);
                КонецЦикла;
            КонецЕсли;
            Если ТабУзлов.Количество()=0 Тогда
                ПродолжУдален=ложь;
            КонецЕсли;
           
            //Запись обработки
            ЧтениеXML.Закрыть();
            XML2=Новый ЗаписьXML;
            XML2.ОткрытьФайл(КаталогВыгрузкиXML,"Windows-1251");
            ЗаписьДом=Новый ЗаписьDOM;
            ЗаписьДом.Записать(ДокументДОМ,XML2);
            XML2.Закрыть();
       
            ТабУзлов.Очистить();
        КонецЦикла;
  15. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Что вы делаете? Что делает весь ваш этот код? Все удаление производится короткой процедурой типа такой:
    Код:
    Процедура ОбходДереваДокумента(Узел)
      
        КоличествоУзлов = Узел.ДочерниеУзлы.Количество();
        Для Счетчик = 1 По КоличествоУзлов Цикл
          
            ДочернийУзел = Узел.ДочерниеУзлы[КоличествоУзлов - Счетчик];
          
            ОбходДереваДокумента(ДочернийУзел);
          
            Если (НЕ ДочернийУзел.ЕстьДочерниеУзлы()) И (ДочернийУзел.ТипУзла = ТипУзлаDOM.Элемент) Тогда
                Узел.УдалитьДочерний(ДочернийУзел);
            КонецЕсли;
          
        КонецЦикла;
      
    КонецПроцедуры
    

    Вложения:

    Samouchka нравится это.
  16. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Мой код делал то же самое, что и Ваш, только через ...опу и неоптимально абсолютно. Всем большое спасибо! С учетом поправки на наличие атрибутов в узле и возможностью выбора обрабатываемого файла, код выглядит так:

    Код:
    Процедура ОбходДереваДокумента(Узел)   
        КоличествоУзлов = Узел.ДочерниеУзлы.Количество();
        Для Счетчик = 1 По КоличествоУзлов Цикл
            ОбработкаПрерыванияПользователя();
           
            ДочернийУзел = Узел.ДочерниеУзлы[КоличествоУзлов - Счетчик];
           
            ОбходДереваДокумента(ДочернийУзел);
            КолАтриб=ДочернийУзел.Атрибуты.Количество();
           
            Если (НЕ ДочернийУзел.ЕстьДочерниеУзлы()) И (ДочернийУзел.ТипУзла = ТипУзлаDOM.Элемент) И (КолАтриб=0) Тогда
                Узел.УдалитьДочерний(ДочернийУзел);
            КонецЕсли;   
        КонецЦикла;   
    КонецПроцедуры
    
    Процедура УдалитьПустыеУзлыXML()
        Диал=Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
        Диал.Заголовок="Выберите каталог";
       
        Если Диал.Выбрать() Тогда
            КаталогВыгрузкиXML=Диал.Каталог+"\ИсходныйФайл.xml";
        Иначе
            Предупреждение("Не выбран каталог!");
            Возврат;
        КонецЕсли;
       
        ЧтениеXML = Новый ЧтениеXML;
        ЧтениеXML.ОткрытьФайл(КаталогВыгрузкиXML);
        ПостроительДОМ = Новый ПостроительDOM;
        ДокументДОМ = ПостроительДОМ.Прочитать(ЧтениеXML);
        ЧтениеXML.Закрыть();
       
        ОбходДереваДокумента(ДокументДОМ);
       
        ЗаписьXML = Новый ЗаписьXML;
        ЗаписьXML.ОткрытьФайл(КаталогВыгрузкиXML,"Windows-1251");
        ЗаписьDOM = Новый ЗаписьDOM;
        ЗаписьDOM.Записать(ДокументДОМ, ЗаписьXML);
        ЗаписьXML.Закрыть();   
    КонецПроцедуры
  17. TopicStarter Overlay
    Samouchka
    Offline

    Samouchka Опытный в 1С

    Регистрация:
    20 мар 2013
    Сообщения:
    214
    Симпатии:
    1
    Баллы:
    29
    Всё-таки нужна поправка кода для проверки отсутствия атрибутов. Необходимо считать количество атрибутов, если узел - элемент. Почему-то сразу 1С ошибку не указала, а выдала спустя несколько раз отработки кода.

    Код:
    Процедура ОбходДереваДокумента(Узел)   
        КоличествоУзлов = Узел.ДочерниеУзлы.Количество();
        Сообщить(КоличествоУзлов);
        Для Счетчик = 1 По КоличествоУзлов Цикл
            ОбработкаПрерыванияПользователя();
           
            ДочернийУзел = Узел.ДочерниеУзлы[КоличествоУзлов - Счетчик];
           
            ОбходДереваДокумента(ДочернийУзел);
           
            Если ДочернийУзел.ТипУзла=ТипУзлаDOM.Элемент Тогда
                СписАтриб=ДочернийУзел.Атрибуты;
                КолАтриб=СписАтриб.Количество();
            КонецЕсли;
           
            Если (НЕ ДочернийУзел.ЕстьДочерниеУзлы()) И (ДочернийУзел.ТипУзла = ТипУзлаDOM.Элемент) И (КолАтриб=0) Тогда
                Узел.УдалитьДочерний(ДочернийУзел);
            КонецЕсли;   
        КонецЦикла;   
    КонецПроцедуры

Поделиться этой страницей