【问题标题】:Parsing a XML file with Perl XMLSimple使用 Perl XMLSimple 解析 XML 文件
【发布时间】:2013-04-16 16:04:11
【问题描述】:

我正在尝试解析具有以下结构的类似 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 来解析该结构。 如果CLASSNAME="SharedGtTranslator",我需要获取属性NAME="Name" 的所有值。

这就是我想要做的:

#!/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";
                        }
                }

        }
}

得到

“伪散列已弃用”

什么都没有发生。

非常感谢您的帮助!

【问题讨论】:

  • 您的 XML 缺少 PROPERTY 标记。当我修复它时,您提供的代码可以正常工作,但未初始化的警告除外。
  • 实际上这是我的错误。我试图省略大部分巨大的 xml 文件以简化所有内容,但 c/p-ed 错误。这是完整的文件(900kb!):docs.google.com/file/d/0B3ustNI1qZh1UURrYWZJQk0wVlU/…
  • 当您尝试像一个 hashref 一样对 arrayref 进行索引时,会出现神秘的“不推荐使用伪哈希”消息。我推荐简短但内容丰富的Perl references tutorial 我也同意@Borodin 的建议,改为使用 XML::LibXML。

标签: xml perl hash xml-simple


【解决方案1】:

您的代码对我来说可以正常工作。那是完整的程序吗?该代码中没有使用伪散列。

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

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

在最后一个INSTANCE 元素的末尾。解决此问题后,您的程序就可以正常运行了。

XML::Simple 似乎对你有用,所以坚持下去可能是合适的。但我一般不建议人们使用这个模块。开始工作可能远非简单,而且它构建的结​​构并不能完全反映 XML 数据,所以像 XML::Twig 要么 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 表达式完成,它选择所有具有 NAME 属性的 PROPERTY 元素 Name 是文档中任何具有 CLASSNAME 属性的 INSTANCE 元素的子元素的SharedGtTranslator。随后的for 循环打印每个PROPERTYVALUE 元素的值。它显然更加简洁,运行起来也更快,如果您需要提取不同的信息,它也更加灵活。

【讨论】:

  • 实际上这是我的错误。我试图省略大部分巨大的 xml 文件以简化所有内容,但 c/p-ed 错误。这是完整的文件(900kb!):docs.google.com/file/d/0B3ustNI1qZh1UURrYWZJQk0wVlU/…
  • 感谢您提供完整数据。我在我的回答中添加了一个更新,它显示了一个使用 XML::Simple 的工作程序以及一个带有 XML::LibXML 的版本,我建议您改用它。
  • 谢谢,LibXML 似乎确实是一个更清洁的解决方案。我被困在 LibXML 1.58 所以不能使用 load_xml。
  • 呃,也许我问的太多了,但是您将如何输出匹配并保留其 XML 格式的整个 VALUE.OBJECT 元素?
【解决方案2】:

您的 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。

【讨论】:

    猜你喜欢
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2013-07-17
    • 1970-01-01
    • 2011-04-13
    相关资源
    最近更新 更多