2013-04-23 3 views
0

Я пытаюсь разобрать файл XML -like со следующей структурой:Разбор XML-файл с Perl XMLSimple

Edit: я попытался опустить большую часть огромного файла XML, чтобы упростить все, но с/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"; 
         } 
       } 

     } 
} 

Получение

"Псевдо-хэши являются устаревшими"

и ничего не происходит.

Справка высоко оценена!

+0

В вашем XML отсутствует тег PROPERTY. Когда я исправил это, код, который вы предоставили, работает, за исключением неинициализированного предупреждения. – TLP

+0

На самом деле это была ошибка с моей стороны. Я попытался пропустить большую часть огромного xml-файла, чтобы упростить все, кроме c/p-ed, неправильно. Вот полный файл (900kb!): Https://docs.google.com/file/d/0B3ustNI1qZh1UURrYWZJQk0wVlU/edit?usp=sharing – vobelic

+0

Криптографическое сообщение «Псевдо-хеши устарело» возникает, когда вы пытаетесь индексировать массив arrayref как будто это был хэш. Я рекомендую краткий, но информативный [Справочник по ссылкам Perl] (http://perldoc.perl.org/perlreftut.html). Я также согласен с рекомендацией @ Borodin использовать XML :: LibXML. –

ответ

1

Ваш код отлично подходит для меня в его нынешнем виде. Это полная программа? В этом коде нет псевдо-хэшей.

Единственная проблема, которую я вижу, заключается в том, что ваши XML-данные не являются корректными. Существует ложный

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

в конце последнего INSTANCE элемента. Как только это исправлено, ваша программа работает нормально.

XML::Simple, похоже, работает на вас, поэтому, вероятно, подходит для этого. Но я вообще не рекомендую, чтобы люди использовали этот модуль. Это может быть далеко не просто для работы, и структура, которую он создает, не полностью отражает данные XML, поэтому что-то вроде XML::Twig или XML::LibXML часто намного лучше.


Update

Работа с реальными данными, структура, порожденная 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 элементы с атрибутом NAMEName, которые являются дети с INSTANCE элемента в любом месте в документе, который имеет CLASSNAME атрибут SharedGtTranslator. Последующая петля for печатает значение элемента VALUE в каждом PROPERTY. Это, безусловно, намного более кратким, а также быстрее работать и более гибко, если вам нужно извлечь различную информацию.

+0

На самом деле это была ошибка с моей стороны. Я попытался опустить большую часть огромного xml-файла, чтобы упростить все, кроме c/p-ed, неправильно. Вот полный файл (900kb!): Https://docs.google.com/file/d/0B3ustNI1qZh1UURrYWZJQk0wVlU/edit?usp=sharing – vobelic

+0

Благодарим вас за показ полных данных. Я добавил обновление для моего анализатора, в котором показана рабочая программа, которая использует 'XML :: Simple', а также версию с XML :: LibXML, которую я рекомендую вам использовать. – Borodin

+0

Спасибо, LibXML кажется действительно более чистым решением. Я застрял в LibXML 1.58, поэтому не мог использовать load_xml. – vobelic

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.

Смежные вопросы