返回已解析文档的哈希值(在 Perl 中使用 Twig)以用于在其他子程序中进行处理
Returning a hash of the Parsed document (using Twig in Perl) to be used for processing in other subs
我非常失败 return 使用 twig 的已解析 XML 文档的哈希 - 以便在其他 subs 中使用它来执行多项验证检查。目标是进行抽象并创建可重复使用的代码块。
XML 块:
<?xml version="1.0" encoding="utf-8"?>
<Accounts locale="en_US">
<Account>
<Id>abcd</Id>
<OwnerLastName>asd</OwnerLastName>
<OwnerFirstName>zxc</OwnerFirstName>
<Locked>false</Locked>
<Database>mail</Database>
<Customer>mail</Customer>
<CreationDate year="2011" month="8" month-name="fevrier" day-of-month="19" hour-of-day="15" minute="23" day-name="dimanche"/>
<LastLoginDate year="2015" month="04" month-name="avril" day-of-month="22" hour-of-day="11" minute="13" day-name="macredi"/>
<LoginsCount>10405</LoginsCount>
<Locale>nl</Locale>
<Country>NL</Country>
<SubscriptionType>free</SubscriptionType>
<ActiveSubscriptionType>free</ActiveSubscriptionType>
<SubscriptionExpiration year="1980" month="1" month-name="janvier" day-of-month="1" hour-of-day="0" minute="0" day-name="jeudi"/>
<SubscriptionMonthlyFee>0</SubscriptionMonthlyFee>
<PaymentMode>Undefined</PaymentMode>
<Provision>0</Provision>
<InternalMail>asdf@asdf.com</InternalMail>
<ExternalMail>fdsa@zxczxc.com</ExternalMail>
<GroupMemberships>
<Group>werkgroep X.Y.Z.</Group>
</GroupMemberships>
<SynchroCount>6</SynchroCount>
<LastSynchroDate year="2003" month="12" month-name="decembre" day-of-month="5" hour-of-day="12" minute="48" day-name="mardi"/>
<HasActiveSync>false</HasActiveSync>
<Company/>
</Account>
<Account>
<Id>mnbv</Id>
<OwnerLastName>cvbb</OwnerLastName>
<OwnerFirstName>bvcc</OwnerFirstName>
<Locked>true</Locked>
<Database>mail</Database>
<Customer>mail</Customer>
<CreationDate year="2012" month="10" month-name="octobre" day-of-month="10" hour-of-day="10" minute="18" day-name="jeudi"/>
<LastLoginDate/>
<LoginsCount>0</LoginsCount>
<Locale>fr</Locale>
<Country>BE</Country>
<SubscriptionType>free</SubscriptionType>
<ActiveSubscriptionType>free</ActiveSubscriptionType>
<SubscriptionExpiration year="1970" month="1" month-name="janvier" day-of-month="1" hour-of-day="1" minute="0" day-name="jeudi"/>
<SubscriptionMonthlyFee>0</SubscriptionMonthlyFee>
<PaymentMode>Undefined</PaymentMode>
<Provision>0</Provision>
<InternalMail/>
<ExternalMail>qweqwe@qwe.com</ExternalMail>
<GroupMemberships/>
<SynchroCount>0</SynchroCount>
<LastSynchroDate year="1970" month="1" month-name="janvier" day-of-month="1" hour-of-day="1" minute="0" day-name="jeudi"/>
<HasActiveSync>false</HasActiveSync>
<Company/>
</Account>
</Accounts>
Perl 块:
my $file = shift || (print "NOTE: \tYou didn't provide the name of the file to be checked.\n" and exit);
my $twig = XML::Twig -> new ( twig_roots => { 'Account' => \& parsing } ); #'twig_roots' mode builds only the required sub-trees from the document while ignoring everything outside that twig.
$twig -> parsefile ($file);
sub parsing {
my ( $twig, $accounts ) = @_;
my %hash = @_;
my $ref = \%hash; #because was getting an error of Odd number of hash elements
return $ref;
$twig -> purge;
它提供了一个哈希引用——我无法正确地尊重它(即使做了数千次尝试)。
再次 - 只需要一个干净的函数(子)来进行解析和 returning 所有元素的散列('Accounts' 在这种情况下) - 用于其他其他功能(valid_sub) 用于执行验证检查。
我真的被困在这一点上了 - 非常感谢您的帮助。
这样的哈希不是Twig创建的,你必须自己创建。
注意:return
之后的命令将永远无法执行。
#!/usr/bin/perl
use warnings;
use strict;
use XML::Twig;
use Data::Dumper;
my $twig = 'XML::Twig'->new(twig_roots => { Account => \&account });
$twig->parsefile(shift);
sub account {
my ($twig, $account) = @_;
my %hash;
for my $ch ($account->children) {
if (my $text = $ch->text) {
$hash{ $ch->name } = $text;
} else {
for my $attr (keys %{ $ch->atts }) {
$hash{ $ch->name }{$attr} = $ch->atts->{$attr};
}
}
}
print Dumper \%hash;
$twig -> purge;
validate(\%hash);
}
嵌套元素的处理(例如 GroupMemberships
)作为练习留给 reader。
并进行验证:
sub validate {
my $account = shift;
if ('abcd' eq $account->{Id}) {
...
}
}
将 XML
向下转换为散列的问题在于 XML
从根本上说是一个更复杂的数据结构。每个元素都有属性、子元素和内容 - 而且它是有序的 - 其中散列...没有。
所以我建议你不要做你正在做的事情,不要传递散列,而是使用 XML::Twig::Elt
并将 that 传递到你的验证中。
幸运的是,这正是 XML::Twig
传递给它的处理程序的内容:
## this is fine:
sub parsing {
my ( $twig, $accounts ) = @_;
但这是无稽之谈 - 想想此时 @_ 中的内容 - 它是对 XML::Twig
对象的引用 - 其中两个,您刚刚分配了它们。
my %hash = @_;
结果这没有意义
my $ref = \%hash; #because was getting an error of Odd number of hash elements
你在哪里 return 将它 发送到 ? (这是在 XML::Twig 解析时调用的)
return $ref;
#this doesn't happen, you've already returned
$twig -> purge;
但请记住 - 您正在 returning 它到正在解析的 twig 进程,那是......丢弃 return 代码。所以这无论如何都不会做任何事情。
我建议您 'save' 参考 $accounts
并将其用于您的验证 - 只需将其传递到您的子例程中进行验证。
或者更好的是,配置一组 twig_handlers
为您执行此操作:
my %validate = ( 'Account/Locked' => sub { die if $_ -> trimmed_text eq "true" },
'Account/CreationDate' => \&parsing,
'Account/ExternalMail' => sub { die unless $_ -> text =~ m/\w+\@\w+\.\w+ }
);
my $twig = XML::Twig -> new ( twig_roots => \%validate );
如果您想丢弃全部内容,您可以 die
,或者在解析时使用 cut
之类的东西从文档中删除无效条目。 (也许 paste
将其放入单独的文档中)。
但是,如果您确实必须将您的XML转换为 perl 数据结构 - 请先阅读此内容,了解为什么这是一个糟糕的想法:
然后,如果您真的想继续走这条路,请查看 XML::Twig
的 simplify
选项:
sub parsing {
my ( $twig, $accounts ) = @_;
my $horrible_hacky_hashref = $accounts->simplify(forcearray => 1, keyattr => [], forcecontent => 1 );
print Dumper $horrible_hacky_hashref;
$twig -> purge;
#do something with it.
}
编辑:
展开:
XML::Twig::Elt
是 XML::Twig
的子集 - 它是 XML::Twig
数据结构的 'building block' - 所以在上面的示例中,$accounts
是。
sub parsing {
my ( $twig, $accounts ) = @_;
print Dumper $accounts;
}
如果这样做,您将获得大量数据,因为您正在转储整个数据结构 - 这实际上是 XML::Twig::Elt
个对象的菊花链。
$VAR1 = \bless( {
'parent' => bless( {
'first_child' => ${$VAR1},
'flushed' => 1,
'att' => {
'locale' => 'en_US'
},
'gi' => 6,
.....
'att' => {},
'last_child' => ${$VAR1}->{'first_child'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'},
'gi' => 7
}, 'XML::Twig::Elt' );
但它已经 封装了您需要的信息以及您需要的结构——这就是 XML::Twig
使用它的原因。并且在很大程度上要说明为什么将您的数据强制放入 hash/array,您将丢失数据。
我非常失败 return 使用 twig 的已解析 XML 文档的哈希 - 以便在其他 subs 中使用它来执行多项验证检查。目标是进行抽象并创建可重复使用的代码块。
XML 块:
<?xml version="1.0" encoding="utf-8"?>
<Accounts locale="en_US">
<Account>
<Id>abcd</Id>
<OwnerLastName>asd</OwnerLastName>
<OwnerFirstName>zxc</OwnerFirstName>
<Locked>false</Locked>
<Database>mail</Database>
<Customer>mail</Customer>
<CreationDate year="2011" month="8" month-name="fevrier" day-of-month="19" hour-of-day="15" minute="23" day-name="dimanche"/>
<LastLoginDate year="2015" month="04" month-name="avril" day-of-month="22" hour-of-day="11" minute="13" day-name="macredi"/>
<LoginsCount>10405</LoginsCount>
<Locale>nl</Locale>
<Country>NL</Country>
<SubscriptionType>free</SubscriptionType>
<ActiveSubscriptionType>free</ActiveSubscriptionType>
<SubscriptionExpiration year="1980" month="1" month-name="janvier" day-of-month="1" hour-of-day="0" minute="0" day-name="jeudi"/>
<SubscriptionMonthlyFee>0</SubscriptionMonthlyFee>
<PaymentMode>Undefined</PaymentMode>
<Provision>0</Provision>
<InternalMail>asdf@asdf.com</InternalMail>
<ExternalMail>fdsa@zxczxc.com</ExternalMail>
<GroupMemberships>
<Group>werkgroep X.Y.Z.</Group>
</GroupMemberships>
<SynchroCount>6</SynchroCount>
<LastSynchroDate year="2003" month="12" month-name="decembre" day-of-month="5" hour-of-day="12" minute="48" day-name="mardi"/>
<HasActiveSync>false</HasActiveSync>
<Company/>
</Account>
<Account>
<Id>mnbv</Id>
<OwnerLastName>cvbb</OwnerLastName>
<OwnerFirstName>bvcc</OwnerFirstName>
<Locked>true</Locked>
<Database>mail</Database>
<Customer>mail</Customer>
<CreationDate year="2012" month="10" month-name="octobre" day-of-month="10" hour-of-day="10" minute="18" day-name="jeudi"/>
<LastLoginDate/>
<LoginsCount>0</LoginsCount>
<Locale>fr</Locale>
<Country>BE</Country>
<SubscriptionType>free</SubscriptionType>
<ActiveSubscriptionType>free</ActiveSubscriptionType>
<SubscriptionExpiration year="1970" month="1" month-name="janvier" day-of-month="1" hour-of-day="1" minute="0" day-name="jeudi"/>
<SubscriptionMonthlyFee>0</SubscriptionMonthlyFee>
<PaymentMode>Undefined</PaymentMode>
<Provision>0</Provision>
<InternalMail/>
<ExternalMail>qweqwe@qwe.com</ExternalMail>
<GroupMemberships/>
<SynchroCount>0</SynchroCount>
<LastSynchroDate year="1970" month="1" month-name="janvier" day-of-month="1" hour-of-day="1" minute="0" day-name="jeudi"/>
<HasActiveSync>false</HasActiveSync>
<Company/>
</Account>
</Accounts>
Perl 块:
my $file = shift || (print "NOTE: \tYou didn't provide the name of the file to be checked.\n" and exit);
my $twig = XML::Twig -> new ( twig_roots => { 'Account' => \& parsing } ); #'twig_roots' mode builds only the required sub-trees from the document while ignoring everything outside that twig.
$twig -> parsefile ($file);
sub parsing {
my ( $twig, $accounts ) = @_;
my %hash = @_;
my $ref = \%hash; #because was getting an error of Odd number of hash elements
return $ref;
$twig -> purge;
它提供了一个哈希引用——我无法正确地尊重它(即使做了数千次尝试)。
再次 - 只需要一个干净的函数(子)来进行解析和 returning 所有元素的散列('Accounts' 在这种情况下) - 用于其他其他功能(valid_sub) 用于执行验证检查。
我真的被困在这一点上了 - 非常感谢您的帮助。
这样的哈希不是Twig创建的,你必须自己创建。
注意:return
之后的命令将永远无法执行。
#!/usr/bin/perl
use warnings;
use strict;
use XML::Twig;
use Data::Dumper;
my $twig = 'XML::Twig'->new(twig_roots => { Account => \&account });
$twig->parsefile(shift);
sub account {
my ($twig, $account) = @_;
my %hash;
for my $ch ($account->children) {
if (my $text = $ch->text) {
$hash{ $ch->name } = $text;
} else {
for my $attr (keys %{ $ch->atts }) {
$hash{ $ch->name }{$attr} = $ch->atts->{$attr};
}
}
}
print Dumper \%hash;
$twig -> purge;
validate(\%hash);
}
嵌套元素的处理(例如 GroupMemberships
)作为练习留给 reader。
并进行验证:
sub validate {
my $account = shift;
if ('abcd' eq $account->{Id}) {
...
}
}
将 XML
向下转换为散列的问题在于 XML
从根本上说是一个更复杂的数据结构。每个元素都有属性、子元素和内容 - 而且它是有序的 - 其中散列...没有。
所以我建议你不要做你正在做的事情,不要传递散列,而是使用 XML::Twig::Elt
并将 that 传递到你的验证中。
幸运的是,这正是 XML::Twig
传递给它的处理程序的内容:
## this is fine:
sub parsing {
my ( $twig, $accounts ) = @_;
但这是无稽之谈 - 想想此时 @_ 中的内容 - 它是对 XML::Twig
对象的引用 - 其中两个,您刚刚分配了它们。
my %hash = @_;
结果这没有意义
my $ref = \%hash; #because was getting an error of Odd number of hash elements
你在哪里 return 将它 发送到 ? (这是在 XML::Twig 解析时调用的)
return $ref;
#this doesn't happen, you've already returned
$twig -> purge;
但请记住 - 您正在 returning 它到正在解析的 twig 进程,那是......丢弃 return 代码。所以这无论如何都不会做任何事情。
我建议您 'save' 参考 $accounts
并将其用于您的验证 - 只需将其传递到您的子例程中进行验证。
或者更好的是,配置一组 twig_handlers
为您执行此操作:
my %validate = ( 'Account/Locked' => sub { die if $_ -> trimmed_text eq "true" },
'Account/CreationDate' => \&parsing,
'Account/ExternalMail' => sub { die unless $_ -> text =~ m/\w+\@\w+\.\w+ }
);
my $twig = XML::Twig -> new ( twig_roots => \%validate );
如果您想丢弃全部内容,您可以 die
,或者在解析时使用 cut
之类的东西从文档中删除无效条目。 (也许 paste
将其放入单独的文档中)。
但是,如果您确实必须将您的XML转换为 perl 数据结构 - 请先阅读此内容,了解为什么这是一个糟糕的想法:
然后,如果您真的想继续走这条路,请查看 XML::Twig
的 simplify
选项:
sub parsing {
my ( $twig, $accounts ) = @_;
my $horrible_hacky_hashref = $accounts->simplify(forcearray => 1, keyattr => [], forcecontent => 1 );
print Dumper $horrible_hacky_hashref;
$twig -> purge;
#do something with it.
}
编辑:
展开:
XML::Twig::Elt
是 XML::Twig
的子集 - 它是 XML::Twig
数据结构的 'building block' - 所以在上面的示例中,$accounts
是。
sub parsing {
my ( $twig, $accounts ) = @_;
print Dumper $accounts;
}
如果这样做,您将获得大量数据,因为您正在转储整个数据结构 - 这实际上是 XML::Twig::Elt
个对象的菊花链。
$VAR1 = \bless( {
'parent' => bless( {
'first_child' => ${$VAR1},
'flushed' => 1,
'att' => {
'locale' => 'en_US'
},
'gi' => 6,
.....
'att' => {},
'last_child' => ${$VAR1}->{'first_child'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'}->{'next_sibling'},
'gi' => 7
}, 'XML::Twig::Elt' );
但它已经 封装了您需要的信息以及您需要的结构——这就是 XML::Twig
使用它的原因。并且在很大程度上要说明为什么将您的数据强制放入 hash/array,您将丢失数据。