Perl将xml解码为hash

时间:2016-04-05 11:44:57

标签: xml perl xpath hash

我需要解码复杂的XML结构。 XML看起来像这样:

use XML::LibXML;
use Data::Dumper;
use strict;
use warnings;
my $parser=XML::LibXML->new();
my $file="c:\\joro\\Data.xml";
my $xmldoc=$parser->parse_file($file);

sub buildHash{
my $mainParentNode=$_[0];
my $mainHash=\%{$_[1]};
my ($waitNextNode,$isArray,$arrayNode);
$waitNextNode=0;
$isArray=0;
sub xmlStructure{
my $parentNode=$_[0];
my $href=\%{$_[1]};
my ($name, %tmp);
my $parentType=$parentNode->nodeName();
$name=$parentNode->findnodes('@name');
foreach my $currentNode($parentNode->findnodes('child::*')){
my $type=$currentNode->nodeName();
if ($type&&$type eq 'List'){
$isArray=1;
}
elsif($type&&$type ne 'List'&&$parentType ne 'List'){
$isArray=0;
$arrayNode=undef;
}
if ($type&&!$currentNode->findnodes('@name')&&$type eq 'Struct'){
$waitNextNode=1;
}
else{
$waitNextNode=0;
}
if ($type&&$type ne 'List'&&$type ne 'Struct'&&!$currentNode->findnodes('@name')){
#$href->{$currentNode->nodeName()}={};
xmlStructure($currentNode,$href->{$currentNode->nodeName()});
}
# elsif ($type&&$type eq 'List'&&$currentNode->findnodes('@name')){
# print "2\n";
# $href->{$currentNode->findnodes('@name')}=[];
# xmlStructure($currentNode,$href->{$currentNode->findnodes('@name')});
# }
elsif ($type&&$type ne 'List'&&$currentNode->findnodes('@name')&&$parentType eq 'List'){
push(@{$href->{$currentNode->findnodes('@name')}},$currentNode->findnodes('@name'));
xmlStructure($currentNode,$href->{$currentNode->findnodes('@name')});

}
# elsif ($type&&$type ne 'List'&&!$currentNode->findnodes('@name')&&$parentType eq 'List'){
# print "4\n";
# push(@{$$href->{$currentNode->findnodes('@name')}},{});
##print Dumper %{$arrayNode};
# xmlStructure($currentNode,$href->{$currentNode->findnodes('@name')});
# }
else{
xmlStructure($currentNode,$href->{$currentNode->findnodes('@name')});
}
}

}
xmlStructure($mainParentNode,$mainHash);
}
my %href;
buildHash($xmldoc->findnodes('*'),\%href);
print "Printing the real HASH\n";
print Dumper %href;

我认为最合适的容器是哈希(如果您的意见不同,请告诉我)。 我发现很难解码它,因为:

  1. 主节点没有" name"属性,但它们应该存在于最终结构中

  2. 只有存在"名称"才能读取子节点。属性,但它们的数据类型(结构)取决于未解码的父元素。

  3. 其中一些父元素有" name"属性 - 在这种情况下,它们应该存在于最终结构中。

  4. 我不关心整数,长整数,日期时间等数据类型,它们将被读作字符串。这里的主要问题是列表和结构类型

  5. 这是我愚蠢地尝试应对任务:

    $VAR1 = 'FirstMainBranch';
    $VAR2 = {
              '' => {
                      'aList' => {
                                 '' => {
                                         'third' => {},
                                         'second' => {},
                                         'first' => {}
                                       }
                               },
                      'namedStruct' => {
                                       'thirdList' => {
                                                      '' => {
                                                              'first' => {}
                                                            }
                                                    }
                                     },
                      'anotherStringValueUnderMainBranch' => {},
                      'secondList' => {
                                      '' => {
                                              'second' => {},
                                              'first' => {}
                                            }
                                    },
                      'aStringValueUnderMainBranch' => {},
                      'anIntegerValueUnderMainBranch' => {}
                    }
            };
    $VAR3 = 'SecondMainBranch';
    $VAR4 = {
              '' => {
                      'namedStructAgain' => {
                                            'First' => {},
                                            'Second' => {}
                                          }
                    }
            };
    

    但还有很长的路要走,因为: 1.钥匙和价值之间有一个寄生虫,可能是未定义的元素。 2.我找不到在需要的地方将数据类型从哈希更改为子数组的方法。

    这是输出:

    (1,2,"N/A",-1,"foo","bar",NULL,3,2016-03-18 08:12:00.000,2016-03-18 08:12:00.559,2016-03-18 08:12:00.520,0,0,NULL,"foo","123456789",{NULL,NULL,NULL,NULL,NULL,NULL,2016-04-17 11:59:59.999,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,null,NULL,NULL,NULL,NULL,3,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,T,0,NULL,NULL,NULL,"9876543210",NULL,"foo","0","bar","foo","a1820000264d979c","0,0",NULL,"foo","192.168.1.82","SOAP",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},{INPUT="bar"},{aStringValueUnderMainBranch="ET", aList[{"first", "second", "third"}, {"first", "second", "third"}], secondList[{"first", "second"}, {"first", "second"}],namedStruct{thirdList[{first},{first}]}},{namedStructAgain{"first", "second"}},NULL,NULL,NULL,NULL,NULL)
    

    任何帮助将不胜感激。 提前谢谢。

    编辑: 关于Sobrique的评论 - X Y问题:

    以下是我要解析的示例字符串:

    {aStringValueUnderMainBranch="ET", aList[{"first", "second", "third"}, {"first", "second", "third"}], secondList[{"first", "second"}, {"first", "second"}],namedStruct{thirdList[{first},{first}]}}
    

    不知何故,我应该将所有值分开,然后确定这一部分:

    {namedStructAgain{"first", "second"}}
    

    作为FirstMainBranch并解析XML中显示的相应值。 之后我应该确定:

    {{1}}

    作为SecondMainBranch并获取相应的值。 主要数据分离还存在一个额外的问题,当它们在括号之间时我不应该记住逗号。

1 个答案:

答案 0 :(得分:0)

我会使用不同的方法。我不是将XML转换为哈希,而是使用XML::Rabbit将其映射到对象。我写了一篇关于如何使用完整工作示例的小article

XML :: Rabbit有一系列优势:

  • 使用简单的Moose对象。
  • 使用XPath以声明方式定义要获取的对象。
  • 解析/定义您想要的内容。无需从XML中获取所有信息。

如果您的XML文件足够小以便使用XPath和DOM,我发现这种方法非常干净且易于维护。