我有一个项目需要解析复杂的XML数据。我决定和XML::Twig
一起去,大部分都能很好地工作。我遇到了一个问题,其中不同的信息具有相同的标签名称,但处于不同的路径。像下面的那样,DateOfBirth
用于两个不同的领域。XML :: Twig - 管理具有相同标记的字段
<doc:DForm xmlns:doc="urn:xml-gov-au:...">
<doc:PersonsDetails>
<doc:GivenName LanguageIdentifier="" LanguageLocaleIdentifier="">
John
</doc:GivenName>
<doc:Surname LanguageIdentifier="" LanguageLocaleIdentifier="">
Citizen
</doc:Surname>
<doc:DateOfBirth LanguageIdentifier="" LanguageLocaleIdentifier="">
2012-06-14
</doc:DateOfBirth>
</doc:PersonsDetails>
<doc:SupportingInformation>
<doc:NumberOfSiblings>
5.00
</doc:NumberOfSiblings>
<doc:SiblingsDetails>
<doc:DateOfBirth LanguageIdentifier="" LanguageLocaleIdentifier="">
2009-03-18
</doc:DateOfBirth>
<doc:Name LanguageIdentifier="" LanguageLocaleIdentifier="">
James Citizen</doc:Name>
</doc:SiblingsDetails>
<doc:SiblingsDetails>
<doc:DateOfBirth LanguageIdentifier="" LanguageLocaleIdentifier="">
2006-08-17
</doc:DateOfBirth>
<doc:Name LanguageIdentifier="" LanguageLocaleIdentifier="">
Jane Citizen
</doc:Name>
</doc:SiblingsDetails>
<doc:Address>
<doc:Street>25 test street<doc:Street>
<doc:City>Melbourne <doc:City>
<doc:PostalCode>3000<doc:PostalCode>
<doc:Address>
</doc:SupportingInformation>
</doc:MCCPDForm>
我有安装多个处理程序来处理不同的信息,但我们并不需要的兄弟姐妹的细节,它被以基于这些字段映射到XML元素一个2级哈希端部处理。
样品:
my %field = (
"DetDateOfBirth" => {
"type" => "Date",
"value" => undef,
"dbfield" => "DetDateOfBirth",
},
)
所以,当兄弟姐妹的出生日期正在处理,它将使用上述哈希元素来进行设置,但是当人的出生日期进行处理,因为已经有一个值,它会转移到下一个元素。
所以我建立了另一个处理程序,并确保信息之前处理。
现在,问题是,想象有多种情况下,同一名称用于多个元素,但使用不同的路径。我只是写更多的处理程序,还是有另一种更好的管理这种情况的方式。
的代码,培训相关:
my $namespace = "doc";
my $formname = "DForm";
enter code here
my $twig = XML::Twig->new(
pretty_print => 'indented',
twig_handlers => {
"$namespace:${formname}/$namespace:PersonsDetails/$namespace:Address" =>
\&ProcessAddress,
"$namespace:${formname}/$namespace:SupportingInformation" =>
\&ProcessSupportingInformation,
"bie1:PdfFile" => \&DecodePDF,
"$namespace:${formname}" => \&ProcessRecord,
}
);
sub ProcessRecord {
my $twg = shift;
my $record = shift;
my $fld;
my $value;
my $irn;
my $elt = $record;
while ($elt = $elt->next_elt($record)) {
$fld = $elt->tag();
$fld =~ s/^$namespace\://;
if (defined $fields{$fld}{"type"} && $elt->text) {
if ($fld =~ /NameOfPlaceInstitution|HospitalNameOfBirth/i) {
next if $elt->text =~ /Other location/i;
}
if (!defined $fields{$fld}{"value"}) {
$fields{$fld}{"value"} = $elt->text;
}
}
}
}
sub ProcessSupportingInformation {
my $twg = shift;
my $record = shift;
my $fld;
my $value;
my $parent;
my $elt = $record;
while ($elt = $elt->next_elt($record)) {
$fld = $elt->tag();
$fld =~ s/^$namespace\://;
$parent = $elt->parent();
next if ($fld =~ /PCDATA/);
if (defined $fields{$fld}{"type"} && $elt->text) {
if ($fld =~ /PlaceOfDeathHospital/i) {
if ($elt->text =~ /Other location/i) {
next;
}
}
if ($fld =~ /StreetAddress/i) {
$fields{"StreetAddressOfPerson"} = $elt->text;
}
else {
if (!defined $fields{$fld}{"value"}) {
$fields{$fld}{"value"} = $elt->text;
}
}
}
else {
$record->delete;
}
}
}
只是一个供参考,实际的XML文件是大约700行,其包括编码PDF为好。
另一种选择是在散列中设置另一个标记,将标记映射到数据库字段并在第一次处理信息时进行设置。
谢谢
PS:抱歉太多的编辑。我想我现在就知道了。
PPS:有代码中的一个敏感的信息,以及XML,我无法展现,所以我不得不修改它的部分......
谢谢!太棒了。表单名称只是我的错误。它应该是'DForm',是的,忽略DecodePDF位。我试图省略不相关的信息,并在这个过程中填入了一些细节。对于那个很抱歉。尽管如此,你给了我一个很好的起点,我相信我可以从这里拿走它。谢谢:) – Hameed 2012-08-06 13:29:26
我很高兴它有帮助。你的XML是什么样的?每个文件都是单个人,还是文件中有多个“”元素?这些人的细节和支持信息以某种方式结合在一起? –
Borodin
2012-08-06 13:32:59
每个文件都是一个记录,并且是一个文件中的所有内容都捆绑在一起。但是,我确实有另一个项目,它将在一个巨大的XML文件中有多个记录。类似的信息,不同的来源。 – Hameed 2012-08-06 13:49:02