我有一個項目需要解析複雜的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