Как получить значение из глубины хэша в Perl
Я читаю в XML-файле,
$myxml = XMLin("$configfile");
И когда я печатаю его с помощью Dumper (print Dumper($myxml);), я получаю это...
$VAR1 = {
'Timeout' => 5,
'Roots' => {
'Root' => [
{
'Name' => 'Sales',
'Level' => 'Indeterminate',
'Profiles' => {
'Profile' => [
{
'Name' => 'Bill',
'Age' => '50',
'Status' => Active
},
{
'Name' => 'Bob',
'Age' => '24',
'Status' => Inactive
}
]
},
'Interval' => 'Order',
'Action' => 'Reject'
},
{
'Name' => 'User',
'Level' => 'Indeterminate',
'Profiles' => {
'Profile' => [
{
'Name' => 'User',
'Action' => 'Reject',
'User' => 'acount'
},
{
'Name' => 'Admin',
'Action' => 'Accept',
'User' => 'acount'
},
]
}
};
Я хотел бы прочитать этот хэш и получить значение всех неактивных "Статус" или или получить "Статус Боба".
{
'Name' => 'Bob',
'Age' => '24',
'Status' => Inactive
}
Начать редактирование:
Таким образом, чтобы получить информацию профиля для одного человека..
Dumper($myxml->{'Roots'}->{'Root'}[0]{'Profiles'}{'Profile'}[2]);
Например, чтобы получить статус для Боба
if ($myxml->{'Roots'}->{'Root'}[0]{'Profiles'}{'Profile'}[1]{'Name'} eq "Bob") {
$status = $myxml->{'Roots'}->{'Root'}[0]{'Profiles'}{'Profile'}[1]{'Status'};
}
Тем не менее, как мне пройти через этот xml, чтобы он продолжал проверять {'Roots'}->{'Root'} и {'Profiles'}{'Profile'}, если Боб не находится в местоположении [0] и [1]. Двойной цикл foreach?
Конец Править
Я включил пример XML..
<Root Name="Sales" Level="Indeterminate" Profile="Order" Interval="Order" Action="Reject">
<Profiles>
<Profile Name="Bill" Age="50" Status=Active />
<Profile Name="Bob" Age="24" Status=InActive />
<Profile Name="Ben" Age="45" Status=Active />
</Profiles>
</Root>
Который производит это:
$VAR1 = {
'Name' => 'Sales',
'Type' => 'Indeterminate',
'Profiles' => {
'Profile' => [
{
'Name' => 'Bill',
'Age' => '50',
'Status' => Active
},
{
'Name' => 'Bob',
'Age' => '24',
'Status' => InActive
},
{
'Name' => 'Ben',
'Age' => '45',
'Status' => Active
}
]
},
'Interval' => 'Order',
'Action' => 'Reject'
};
Спасибо,
Джон.
3 ответа
У вас есть ответ, как это сделать с XML::Simple уже. Но я бы предложил, а не использовать XML::Twig
вместо этого, который НАМНОГО менее противен.
Почему XML::Simple "не рекомендуется"?
Я собираюсь предположить, что ваш XML выглядит примерно так:
<opt Timeout="5">
<Roots>
<Root Action="Reject" Interval="Order" Level="Indeterminate" Name="Sales">
<Profiles>
<Profile Age="50" Name="Bill" Status="Active" />
<Profile Age="24" Name="Bob" Status="Inactive" />
</Profiles>
</Root>
</Roots>
</opt>
Я не могу сказать наверняка, потому что это радость XML::Simple
, Но:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig -> new -> parsefile ( $configfile );
print $twig -> get_xpath ( '//Profile[@Name="Bob"]',0 ) -> att('Status')
Это использует xpath
найти атрибут, который вы хотите - //
обозначает поиск в любом месте дерева.
Но вы могли бы вместо этого:
print $twig -> get_xpath ( '/opt/Roots/Root/Profiles/Profile[@Name="Bob"]',0 ) -> att('Status')
Гораздо проще, вы не согласны?
Или повторить все "Профили":
foreach my $profile ( $twig -> get_xpath ('//Profile' ) ) {
print $profile -> att('Name'), " => ", $profile -> att('Status'),"\n";
}
Это одна из причин того, что XML:: Simple настоятельно не рекомендуется - иногда он будет выдавать ссылку на массив, когда вы ожидаете ссылку на хеш.
Вы можете видеть, что значение $rulesxml->{'Roots'}->{'Root'}
ссылка на массив, а не ссылка на хеш, так как она начинается с [
не {
,
Если данные именно то, что вы показываете здесь, то все, что вам нужно сделать, это вставить в ваш код поиск по массиву.
Dumper($myxml->{'Roots'}->{'Root'}->[0]->{'Profiles'}->{'Profile'});
Я использовал 0, так как есть (в настоящее время?) Только один элемент в этом массиве. Если ваши данные более сложны и у вас есть несколько элементов в массиве, то вам нужно будет использовать цикл.
Для такой работы я настоятельно рекомендую потратить время на изучение XPath и использовать модуль, который это поддерживает (мне нравится XML:: LibXML).
Несколько других способов упростить ваш код:
Вы цитируете переменную в
XMLin()
звонить без необходимости.$myxml = XMLin($configfile); # Works fine without quotes
Вы можете опустить промежуточные стрелки в многоуровневых поисках.
$myxml->{'Roots'}{'Root'}[0]{'Profiles'}{'Profile'}
Вы также можете опустить большинство кавычек вокруг имен ключей хеша.
$myxml->{Roots}{Root}[0]{Profiles}{Profile}
Обновление: я не хочу дать вам решение вашего добавленного вопроса, потому что (как мы не устаем здесь указывать) XML::Simple - ужасное решение большинства проблем XML.
Но, учитывая вашу структуру данных (или, вернее, версию вашей структуры данных, которую я очистил, чтобы она на самом деле компилировалась!), Это то, как вы должны проходить ее (да, это вложенный цикл).
for my $root (@{ $myxml->{Roots}{Root} }) {
for my $profile (@{ $root->{Profiles}{Profile} }) {
if ($profile->{Name} eq 'Bob') {
say $profile->{Status};
}
}
}
Но, пожалуйста, не используйте этот подход. Подход XML::Twig, предложенный Sobrique, является гораздо лучшим ответом. И подход XPath, основанный на XML:: LibXML, будет аналогичным.
Всякий раз, когда вы извлекаете данные из XML-документа, XPath, вероятно, будет лучшим решением. Если вы имеете дело с XML, то вам действительно нужно иметь XPath в своем наборе инструментов.
Значение Root является ArrayRef. Вы игнорируете массив и рассматриваете его так, как если бы он был одним из HashRef, которые находятся внутри него. Вам нужно перебрать массив или получить к нему доступ с определенным индексом.