0

我正在尝试解析XML具有以下结构的类似文件:

编辑:我试图省略大部分巨大的 xml 文件以简化所有内容,但 c/p-ed 错误。这是实际存在此问题的完整文件(900kb!):https ://docs.google.com/file/d/0B3ustNI1qZh1UURrYWZJQk0wVlU/edit?usp=sharing

<CIM CIMVERSION="2.0" DTDVERSION="2.0">

  <DECLARATION>
    <DECLGROUP>
      <LOCALNAMESPACEPATH>
        <NAMESPACE NAME="signalingsystem"/>
      </LOCALNAMESPACEPATH>

      <VALUE.OBJECT>
        <INSTANCE CLASSNAME="SharedGtTranslator">
          <PROPERTY NAME="Name" TYPE="string">
            <VALUE>AUC$4,1,6,4,26202*-->AUC RemoteSPC: 300 SSN: 10</VALUE>
          </PROPERTY>
          <PROPERTY NAME="NatureOfAddress" TYPE="sint32">
            <VALUE>4</VALUE>
          </PROPERTY>
        </INSTANCE>
      </VALUE.OBJECT>

      <VALUE.OBJECT>
        <INSTANCE CLASSNAME="SharedGtTranslator">
          <PROPERTY NAME="Name" TYPE="string">
            <VALUE>AUC$4,2,6,4,26202*-->AUC AUC LocalSPC: 410 SSN: 10</VALUE>
          </PROPERTY>
          <PROPERTY NAME="NatureOfAddress" TYPE="sint32">
            <VALUE>4</VALUE>
          </PROPERTY>
            <VALUE>2</VALUE>
          </PROPERTY>
        </INSTANCE>
      </VALUE.OBJECT>
    </DECLGROUP>

  </DECLARATION>
</CIM>

我正在使用 XMLSimple 来解析该结构。NAME="Name"如果CLASSNAME="SharedGtTranslator". _

这就是我想要做的:

#!/usr/bin/perl
use strict;
use warnings;
# use module
use XML::Simple;
use Data::Dumper;

my $file1 = $ARGV[0];
# create object
my $xml = new XML::Simple;

# read XML file
my $data = $xml->XMLin($file1);
foreach my $object (@{$data->{DECLARATION}->{DECLGROUP}->{'VALUE.OBJECT'}}) {
        if ($object->{INSTANCE}->{CLASSNAME} eq 'SharedGtTranslator') {
                foreach my $property (@{$object->{INSTANCE}->{PROPERTY}}) {
                        if ($property->{NAME} eq 'Name') {
                                print $property->{VALUE} . "\n";
                        }
                }

        }
}

得到

“伪散列已弃用”

什么也没有发生。

高度赞赏帮助!

4

2 回答 2

1

你的代码对我来说很好用。那是完整的程序吗?该代码中没有使用伪散列。

我能看到的唯一问题是您的 XML 数据格式不正确。有一个假的

  <VALUE>2</VALUE>
</PROPERTY>

在最后一个INSTANCE元素的末尾。解决此问题后,您的程序运行良好。

XML::Simple似乎对你有用,所以坚持下去可能是合适的。但我一般不建议人们使用这个模块。开始工作可能远非简单,而且它构建的结​​构并不能完全反映 XML 数据,因此类似 XML::Twig or XML::LibXML 的东西通常要好得多。


更新

使用您的真实数据,生成的结构XML::Simple看起来与为简短示例生成的结构完全不同。有一些数组与以前不存在的散列混合在一起。

该程序似乎可以生成您需要的内容。它产生 170 行输出。

use strict;
use warnings;

use XML::Simple;

my $file1 = 'active_7v19.om.cim';

my $xml  = new XML::Simple;
my $data = $xml->XMLin($file1);

for my $declgroup (@{ $data->{DECLARATION}{DECLGROUP} }) {

    foreach my $object (@{ $declgroup->{'VALUE.OBJECT'} }) {

        my $instance   = $object->{INSTANCE};
        my $classname  = $instance->{CLASSNAME};
        my $properties = $instance->{PROPERTY};

        next unless $classname eq 'SharedGtTranslator';

        for my $property (@$properties) {

            my $name  = $property->{NAME};
            my $value = $property->{VALUE};

            print $value, "\n" if $name eq 'Name';
        }
    }
}

但是,我现在更加确定使用“真正的”XML 库会更好。此代码用于XML::LibXML产生相同的输出。

use strict;
use warnings;

use XML::LibXML;

my $doc = XML::LibXML->load_xml(location => $file1, no_blanks => 1);

my @properties = $doc->findnodes('//INSTANCE[@CLASSNAME = "SharedGtTranslator"]/PROPERTY[@NAME = "Name"]');

for my $property (@properties) {
    print $property->textContent('VALUE'), "\n";
}

所有工作都由 XPath 表达式完成,该表达式选择所有PROPERTY具有 属性的元素NAME,这些元素是文档中任何具有属性Name的元素的子级。随后的循环打印每个 中元素的值。它显然更加简洁,运行起来也更快,如果您需要提取不同的信息,它也更加灵活。INSTANCECLASSNAMESharedGtTranslatorforVALUEPROPERTY

于 2013-04-23T13:13:38.487 回答
0

您的 XML 格式不正确。我得到解析错误。您的最后一个属性,您关闭,但不打开(或名称,结果)。之后,在 Perl 5.16 中,它打印:

AUC$4,1,6,4,26202*-->AUC RemoteSPC: 300 SSN: 10
AUC$4,2,6,4,26202*-->AUC AUC LocalSPC: 410 SSN: 10

当然,这适用于 XML::Simple 2.20。

于 2013-04-23T13:13:41.940 回答