Родительский элемент не закрывается после удаления элемента: XML Twig

Я пытаюсь найти элемент с атрибутом с определенным значением и удаляю его из документа.

В этом примере я ищу элемент File с атрибутом "RelativePath", значение которого "....\TS\ETestScenario.inc".

Проблема: последний элемент - </Files> отсутствует после запуска сценария. Кроме того, закрывающий тег VisualStudioProject печатается дважды. Не уверен, что я здесь делаю.

use strict;
use XML::Twig;
my $fileName = 'Z:\autotest\test.xml';
my $t= new XML::Twig( TwigRoots=> 
            { Files => \&upd_files_section
             },

              twig_print_outside_roots => 1,               # print the rest
              keep_spaces => 1,
              keep_atts_order=>1,
            );              

$t->parsefile("$fileName");
#$t->parsefile_inplace ("$fileName");


sub upd_files_section{
    my ($t, $inputFields)=@_;

    my $file_to_delete = $inputFields->get_xpath("./File[\@att='..\..\TS\ETestScenario.inc']");
    $inputFields->delete($file_to_delete);
    $t->flush;
}

Неверный вывод XML:

<VisualStudioProject
    ProjectType="Visual C++"
    Version="8.00"
    Name="xxx"
    ProjectGUID="{}"
    RootNamespace="xx"
    SccProjectName="x"
    SccLocalPath="."
    SccProvider="x"
    >
        <Files>
                <Filter Name="Source Files" Filter="cpp;bat">
                        <File RelativePath="..\..\TS\ADK_MacCommon_Test.cpp">
                        </File>
                        <File RelativePath="..\..\FSO\EADK.cpp">
                        </File>
                <Filter Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" Name="Resource Files">
                </Filter>
                <File RelativePath="..\..\TS\ETestScenario.inc">
                </File>
        </VisualStudioProject>
        <Globals>
        </Globals>
</VisualStudioProject>

1 ответ

Решение

Как уже упоминалось, XML не является допустимым, и код не компилируется.

Тем не менее, если я правильно понимаю, я думаю, что обработчик должен быть:

sub upd_files_section{
    my ($t, $inputFields)=@_;
    my @files_to_delete = $inputFields->get_xpath("./File[\@RelativePath='..\\..\\TS\\ETestScenario.inc']");
    foreach my $file (@files_to_delete) { $file->delete; }
    $t->flush;
}

Несколько заметок:

  • вам нужно избежать обратной косой черты в выражении XPath, или Perl думает, что они там, чтобы избежать следующего символа; в качестве альтернативы, используйте простые кавычки или q{} вокруг выражения: q{./File[@RelativePath='..\..\TS\ETestScenario.inc']}
  • в выражении XPath это должно быть @RelativePathне @att
  • get_xpath возвращает список элементов, которые вы должны удалить
  • удалить вызов элемента delete на этом, нет необходимости проходить через своего родителя, как с DOM
  • Вы также можете вырезать всех детей одновременно, используя... cut_children метод: $inputFields->cut_children( q{File[@RelativePath='..\..\TS\ETestScenario.inc']});
Другие вопросы по тегам