2011-12-21 3 views
1

У меня есть много файлов XML в каталоге, который нужно сортировать и объединять в один файл. Файлы в следующем формате:Сортировка и слияние XML-документов с Perl/XML :: Twig

File1.xml:

<?xml version="1.0" encoding="utf-8"?> 
<doctypea> 
    <header someattr="1"> 
    <docnumber>111</docnumber> 
    </header> 
</doctypea> 

File2.xml:

<?xml version="1.0" encoding="utf-8"?> 
<doctypea> 
    <header someattr="1"> 
    <docnumber>112</docnumber> 
    </header> 
</doctypea> 

File3.xml:

<?xml version="1.0" encoding="utf-8"?> 
<doctypeb> 
    <header someattr="1"> 
    <docnumber>111</docnumber> 
    </header> 
</doctypeb> 

File4.xml:

<?xml version="1.0" encoding="utf-8"?> 
<doctypeb> 
    <header someattr="1"> 
    <docnumber>112</docnumber> 
    </header> 
</doctypeb> 

Все файлы в этом каталоге должны быть отсортированы по следующим критериям:

  1. НомерДокумента
  2. DOCTYPE (а или б)

Затем их нужно объединить, поэтому выходной файл должен выглядеть так:

<?xml version="1.0" encoding="utf-8"?> 
<doctypea> 
    <header someattr="1"> 
    <docnumber>111</docnumber> 
    </header> 
</doctypea> 
<doctypeb> 
    <header someattr="1"> 
    <docnumber>111</docnumber> 
    </header> 
</doctypeb> 
<doctypea> 
    <header someattr="1"> 
    <docnumber>112</docnumber> 
    </header> 
</doctypea> 
<doctypeb> 
    <header someattr="1"> 
    <docnumber>112</docnumber> 
    </header> 
</doctypeb> 

Для этого я пытаюсь использовать XML: Twig in Perl. У меня есть следующий код до сих пор:

use XML::Twig; 

my $xmldir = "/xmlfiles"; 
my $parser = XML::Twig->new(pretty_print => 'indented'); 

opendir(DIR, "$xmldir"); 
my @FILES= readdir(DIR); 
closedir(DIR); 

foreach (@FILES) { 
     if ($_ ne "." && $_ ne "..") { 
       print "reading file: $xmldir/$_\n"; 
       $parser->parsefile("$xmldir/$_"); 
     } 
} 

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

1. Как получить значение корневого элемента ("doctypea" или "doctypeb")?

2. Я предполагаю, что мне нужно, чтобы (1), чтобы parsenode до поля docnumber?

Мой план заключается в том, чтобы построить какой-то из них с номером doctype%, чтобы сортировать, я не уверен, что самый простой способ объединить их с этим.

Цените любые рекомендации!

+1

Это не файлы XML.Они отклоняются XML-Twig и любым другим процессором XML, и это справедливо. Значения атрибутов должны быть указаны, а имена начального и конечного тегов каждого корневого элемента должны совпадать. – daxim

+0

Извините, что это было мое ручное издевательство над простым примером, который сделал их недействительными. Они являются действительными файлами XML. Я исправил пример. – ChuckMac

ответ

5

Ниже приведен небольшой пример, который должен вас начать. В нем показано, как получить данные из XML-файла, аналогичного вашему (я исправил теги для соответствия и дал значение someattr, чтобы получить действительный XML). Вы можете использовать подобный подход для сбора необходимых данных и получения результатов.

use XML::Twig; 

XML::Twig->new(twig_handlers => { 
    '/*'  => sub { print $_->gi;   },  # doctypea 
    'docnumber' => sub { print $_->trimmed_text; },  # 111 
})->parse(\*DATA); # use parsefile('xxx.xml') to parse a file 

__DATA__ 
<?xml version="1.0" encoding="utf-8"?> 
<doctypea> 
    <header someattr="1"> 
    <docnumber>111</docnumber> 
    </header> 
</doctypea> 
+0

Когда я пытаюсь это сделать, я получаю: 'нераспознанное выражение в обработчике: '/ *'' – ChuckMac

+0

@ChuckMac: Я не получаю это сообщение. Код работает для меня как есть. Вы копировали и вставляли правильно? – toolic

+0

@toolic: Да, это была прямая копия/вставка. Просто повторил это и получил одно и то же сообщение. – ChuckMac

1

Как заметил daxim, ваши файлы недействительны XML, но вы можете обрабатывать их с помощью регулярных выражений. Если файлы не слишком большие, вы можете разделить файлы на отдельные строки, которые вы сортируете, основываясь на их содержимом.

use File::Slurp qw(read_dir) ; 
my $xmldir="."; 
my %files = map { 
     s/^.*$//m; 
     /<doctype([ab])>/; my $x=ord($1) - ord('a'); 
     /<docnumber>(\d+)</docnumber>/; $x += 10*$2; 
     $x => $_ 
    } read_dir($xmldir); 
print join("", map { $files{$_} } sort keys %files); 

Я не отладил этот код. Также print join("", values %files); может работать.

+1

Извините, что это был мой ручной процесс издевательства над более простым примером, который сделал их недействительными. Они являются действительными файлами XML. Я исправил пример. Они намного больше этого, я просто упростил цель. – ChuckMac

Смежные вопросы