У меня есть хорошо сформированный XML, который я пытаюсь преобразовать в хеш с помощью модуля Perl XML :: Simple. В этом файле есть разделы, которые нельзя правильно проанализировать. Есть ли способ (или обходной путь) правильно проанализировать xml и получить желаемый результат?
D:\tmp>perl parse_dns2.pl dns_problem_public.xml
Warning: <dns_entry> element has non-unique value in 'domain' key attribute:
0 at parse_dns2.pl line 9.
Warning: <dns_entry> element has non-unique value in 'domain' key attribute:
example.com at parse_dns2.pl line 9.
Warning: <dns_entry> element has non-unique value in 'domain' key attribute:
test.com at parse_dns2.pl line 9.
$VAR1 = {
'dns_timeout' => '20',
'local_dns' => {
'dns_entry' => {
'0' => {
'content' => '192.168.120.32'
},
'domain.example.com' => {
'content' => '172.16.113.13'
},
'example.com' => {
'content' => '172.16.113.13'
},
'test.com' => {
'content' => '172.17.0.113'
}
}
}
};
Мой код прост:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use XML::Simple;
use Data::Dumper;
my $ref = XMLin(
$ARGV[0],
ForceArray => ['dns_entry'],
KeyAttr => { 'dns_entry' => 'priority' },
KeyAttr => { 'dns_entry' => 'domain' },
ForceContent => 0
);
print Dumper $ref;
Файл xml (соответствующий раздел) содержит атрибуты, которые мне нужно использовать в качестве ключа:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE config SYSTEM "config.dtd">
<dns>
<local_dns>
<dns_entry priority="0">192.168.120.31</dns_entry>
<dns_entry priority="0">192.168.120.32</dns_entry>
<dns_entry domain="example.com">172.16.103.20</dns_entry>
<dns_entry domain="example.com">172.16.113.13</dns_entry>
<dns_entry domain="test.com">172.17.0.111</dns_entry>
<dns_entry domain="test.com">172.17.0.113</dns_entry>
<dns_entry domain="domain.example.com">172.16.103.20</dns_entry>
<dns_entry domain="domain.example.com">172.16.113.13</dns_entry>
</local_dns>
<dns_timeout>20</dns_timeout>
</dns>
Первая проблема в том, что XML :: Simple не может принимать аналогичные элементы с одинаковыми атрибутами (хотя и разными значениями). И вторая проблема заключается в том, что я могу использовать только один атрибут в качестве ключевого атрибута в том же блоке XML.
Желаемый результат:
$VAR1 = {
'local_dns' => {
'dns_entry' => {
'domain' => {
'domain.example.com' => {
'content' => [
'172.16.113.20',
'172.16.113.13'
]
},
'example.com' => {
'content' => [
'172.16.113.20',
'172.16.113.13'
]
},
'test.com' => {
'content' => [
'172.17.0.111',
'172.17.0.111'
]
}
},
'priority' => {
'0' => {
'content' => [
'192.168.120.31',
'192.168.120.32'
]
}
}
}
},
'dns_timeout' => '20'
};
1 ответ
Узлы не могут иметь многократного содержимого, поэтому необходимо некоторое преобразование.
Вам следует воспользоваться этой возможностью, чтобы избежать использования наиболее сложных анализаторов XML. Так сложно использовать собственную документацию, в которой не рекомендуется использовать его.
Вот решение XML :: LibXML:
use XML::LibXML qw( );
my $doc = XML::LibXML->new->parse_file('dns.xml');
my %data;
{
$data{dns_timeout} = $doc->findvalue('/dns/dns_timeout/text()');
for my $dns_entry_node ($doc->findnodes('/dns/local_dns/dns_entry')) {
my $addr = $dns_entry_node->textContent();
if (defined( my $priority = $dns_entry_node->getAttribute('priority') )) {
push @{ $data{local_dns}{dns_entry}{priority}{$priority} }, $addr;
}
if (defined( my $domain = $dns_entry_node->getAttribute('domain') )) {
push @{ $data{local_dns}{dns_entry}{domain}{$domain} }, $addr;
}
}
}
Похожие вопросы
Связанные вопросы
Новые вопросы
xml
XML (Extensible Markup Language) - это формат структурированного документа, определяющий правила кодирования текста. При использовании этого тега включайте дополнительные теги, такие как язык программирования, наборы инструментов, используемые технологии XML и другие теги, описывающие среду, в которой опубликована проблема. Гибкость XML обеспечивает широкий спектр применений для передачи человеческих и машинных данных, в том числе конкретных инструментов и библиотек.