2015-10-20 4 views
-3

data.xmlPerl, удаление XML узлу

<people> 
    <person name="John"> 
    <param name="age" value="21" /> 
    </person> 
    <person name="Jane"> 
    <param name="age" value="25" /> 
    </person> 
</people> 

У меня есть этот кусок XML. Я работаю над скриптом для добавления <person> узлов к узлу <people>. Я использую XML :: Simple

(Пожалуйста, воздержитесь от предложения использовать другую библиотеку, я знаю о ее трудностях).

my $remove_person = "Jane"; 

my $xml = XMLin('data.xml', ForceArray => 1, KeepRoot => 1, KeyAttr => []); 
if(exists $xml->{people}[0]{person}){ 
     my $var = $xml->{people}[0]{person}; 
     my $count = @$var; 
     my $person_index = 0; 
     for(my $i = 0; $i < $count; $i++){ 
       if($xml->{people}[0]{person}[$i]->{name} eq $remove_person){ 
         print "Person found at " . $person_index . " index"; 
         $person_index = $i; 
         $person_to_remove = $xml->{people}[0]{person}[$i]; 
       } 
     } 
} else { 
     print "Person not found in data.xml\r"; 
} 

выше фрагмент кода даст мне индекс узла я требуется удалить. С этого момента у меня возникли проблемы. Я не могу определить правильный способ удаления этого индекса из данных.
До сих пор я пробовал метод использования splice, который возвратил раздел XML, который я хочу удалить, затем я использовал XMLout() для преобразования массива в XML. Используя =~ s///g, я смог редактировать изменения узла (<person> стал <opt>). После того, как я создал XMLout()'ed исходную структуру data.xml, я попытался сменить замену переменной сместимого раздела XML с пустой строкой исходной структуры.

Очевидно, что это не сработало.

my $new_xml = XMLout($xml, KeepRoot => 1); 
my $remove_xml = XMLout($person_to_remove, KeepRoot => 1); 

$remove_xml =~ s/opt/person/g; 
$new_xml =~ s/($remove_xml)//g; # facepalm, i know 

Как бы я удалить этот раздел XML, либо путем удаления массива данных или простого удаления текстового файла так, чтобы записать обратно в исходный файл data.xml новую структуру?

ответ

0

Как вы уже told, точка XML::Simple является использование структур данных Perl вместо манипуляций со строками. Итак, забудьте s/// и попробовать

my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1); 
my $remove = 'Jane'; 
delete $xml->{people}[0]{person}{$remove}; 
print XMLout($xml, KeepRoot => 1); 

или с пустой KeyAttr

my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1, KeyAttr => []); 
@{ $xml->{people}[0]{person} } = grep $_->{name} ne $remove, 
           @{ $xml->{people}[0]{person} }; 
print XMLout($xml, KeepRoot => 1); 

Для сравнения, та же задача в XML::XSH2:

open data.xml ; 
my $remove = 'Jane' ; 
delete /people/person[@name=$remove] ; 
save :b ; 
+0

Функция удаления не рекомендуется использовать (иронично в моем случае, поскольку она написана в камне, я использую :: Simple). Конечным продуктом моего вопроса является скрипт системы телефонии, который без системы не может работать. Если бы была проведена правильная проверка индекса, могу ли я предположить, что использование delete не приведет к каким-либо «неожиданным поведением», как предупреждалось в документации perl? (У меня уже достаточно проблем с :: Simple, поэтому я бы предпочел уменьшить любую дополнительную сложность/риск) –

+1

@Simon. 'delete' не следует использовать для массивов. Я использовал его для хэша, который в порядке. – choroba

1

Редактировать: ниже было опубликовано до «Пожалуйста, не предлагайте использовать другие библиотеки». Я оставляю это, потому что я все еще думаю, что правильный ответ: «Не используйте XML::Simple». Вы можете использовать молоток, чтобы поместить винты в стену все, что вам нравится, но это не меняет того факта, что, насколько бы вы ни попали, результаты будут беспорядочными.

Не используйте XML::Simple, и это очень просто. Даже XML::Simple говорит:

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

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

Как об использовании XML::Twig вместо:

#!/urs/bin/env perl 
use strict; 
use warnings; 

use XML::Twig; 

my $twig = XML::Twig -> new ('pretty_print' => 'indented_a') -> parsefile ('your_xml'); 
foreach my $element ($twig -> get_xpath('person[@name="Jane"]')) { 
    $element -> delete; 
} 

$twig -> print; 

Вы можете - если хотите - и сделать это с помощью INPLACE редактирования с помощью parsefile_inplace. В противном случае откройте новый файл и выведите новый XML-код через $twig -> sprint.

например.:

XML::Twig->new(
    'pretty_print' => 'indented_a', 
    'twig_handlers' => { 
     'person[@name="Jane"]' => sub { $_->delete } 
    } 
)->parsefile_inplace('xml_filename.xml'); 

Если вы намерены использовать молоток для винтов - это должно делать это с вашим исходным кодом и XML::Simple:

$xml->{people}[0]{person} = 
    [ grep { not $_->{name} eq $remove_person } 
         @{ $xml->{people}[0]{person} } ]; 

Заменяет массив в вопросе с отфильтрованной матрицей на name атрибут.

Выходы:

<people> 
    <person name="John"> 
    <param name="age" value="21" /> 
    </person> 
</people> 
0

К сожалению, я оказался в roughtly том же номере , Мне пришлось редактировать некоторые XML-файлы в AIX без дополнительных библиотек. Я закончил удаление таких вещей

perl -0777 -p -i -e "s;(<HARDWARE>.*)<DESCRIPTION>.*<\/DESCRIPTION>(.*<\/HARDWARE>);\$1\$2;s" my.xml 

Это некрасиво. Мне это не нравится. Но тогда это сработало, и если вы знаете, как писать regexpr, который должен делать то и дело.