Ссылка на верхний уровень объекта xml с использованием xml::simple в perl
Я бился головой об стену, пытаясь понять это. Просто пытаюсь собрать скрипт, который в конечном итоге свяжет вместе различные компоненты этих игровых файлов (например, для вики). Я уверен, что это простой вопрос - не правильно делать защиту, но я не могу понять это ради своей жизни.
Вот пример XML:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<!-- ??????????????????????????????????????????????????????????????????????????????? -->
<!-- ?????????? Die Till Day 7 ?????????? Guns (Gun Parts) ????????????????????????? -->
<!-- ??????????????????????????????????????????????????????????????????????????????? -->
<item id="1" name="pistol">
<property name="Meshfile" value="Items/Weapons/Ranged/Pistol/PistolPrefab" />
<property name="Material" value="metal" />
<property name="HoldType" value="1" />
<property name="Stacknumber" value="1" />
<property name="RepairTools" value="repairKit,repairKit2ndGeneration,repairKit3rdGeneration" />
<property name="Degradation" value="175" param1="false" />
<property name="DegradationBreaksAfter" value="false" />
<property name="SoundJammed" value="Weapons/weapon_jam" />
<property name="Attachments" value="flashlight02" />
<property class="Parts">
<property name="Stock" value="pistol_grip" />
<property name="Receiver" value="pistol_receiver" />
<property name="Pump" value="pistol_parts" />
<property name="Barrel" value="pistol_barrel" />
</property>
<property class="Action0">
<property name="Class" value="Ranged" />
<property name="Delay" value="0.15" />
<property name="Range" value="120" />
<property name="DamageBlock" value="1" />
<property name="Magazine_size" value="15" />
<property name="Magazine_items" value="9mmBullet, incendiary9mmBullet" />
<property name="Reload_time" value="2" />
<property name="Bullet_icon" value="pistol" />
<property name="Sound_start" value="Weapons/Ranged/Pistol/pistol_fire" />
<property name="Sound_repeat" value="" />
<property name="Sound_end" value="" />
<property name="Sound_empty" value="Weapons/weapon_empty" />
<property name="Sound_reload" value="Weapons/Ranged/Pistol/pistol_reload" />
<property name="Particles_muzzle_fire" value="nozzleflash" />
<property name="Particles_muzzle_smoke" value="nozzlesmoke" />
<property name="DamageBonus.head" value="6" />
<property name="DamageBonus.glass" value="25" />
</property>
<property class="Action1">
<property name="Class" value="Zoom" />
<property name="Zoom_max_out" value="35" />
<property name="Zoom_max_in" value="35" />
</property>
<property name="LightSource" value="lightSource" />
<property name="ActivateObject" value="Attachments/flashlight/lightSource" />
<property name="AttachmentFlashlight" value="flashlight02" />
<property name="Group" value="Ammo/Weapons" />
<property class="Preview">
<property name="Zoom" value="14" />
<property name="Pos" value="0.1,-0.1" />
<property name="Rot" value="0,-45,0" />
</property>
</item>
</items>
Вот актуальная программа
#!/usr/local/bin/perl
use warnings;
#use strict;
use XML::Simple qw(:strict);
use Data::Dumper;
my $xml = new XML::Simple;
my $data = $xml->XMLin(undef, KeyAttr => { item => 'name' }, ForceArray => ['item', 'property', 'property']);
#my $data = XMLin ($xml, forcearray => [ qw (item property property) ], keyattr = +> [] );
#print Dumper($data);
#my @itemlist = @{$data->{name}};
#print Dumper( \@itemlist );
my $items = $data->{item};
for my $item_name (keys %$items) {
my $item = $items->{$item_name};
my $item_id = $item->{id};
my $props = $item->{property};
print "Name: " . $item_name . " ID: " . $item_id;
for my $prop (@$props)
{
my $prop_name = $prop->{name};
my $prop_value = $prop->{value};
print $prop_name ": " . $prop_value . "\n";
}
}
На самом деле просто ищу несколько вещей, например, как мне получить доступ к реальному названию элемента (в этом случае pistol
) от foreach и как бы я перешел к собственности или собственности собственности. Я почти уверен, что просто напортачу, что такое хэш против массива, или неправильно настраиваю элементы, но я не нашел примеров, достаточно близких к моим XML-данным, чтобы понять это.
(Data Dumper дает мне это)
$VAR1 = {
'item' => {
'pistol' => {
'id' => '1',
'property' => [
{
'value' => 'Items/Weapons/Ranged/Pistol/PistolPrefab',
'name' => 'Meshfile'
},
{
'value' => 'metal',
'name' => 'Material'
},
{
'value' => '1',
'name' => 'HoldType'
},
{
'value' => '1',
'name' => 'Stacknumber'
},
{
'value' => 'repairKit,repairKit2ndGeneration,repairKit3rdGeneration',
'name' => 'RepairTools'
},
{
'value' => '175',
'name' => 'Degradation',
'param1' => 'false'
},
etc
Ошибки:
Больше ошибок нет!
2 ответа
my $items = $data->{item};
for my $item_name (keys %$items) {
my $item = $items->{$item_name};
my $item_id = $item->{id};
my $props = $item->{property};
for my $prop (@$props) {
my $prop_name = $prop->{name};
my $prop_value = $prop->{value};
...
}
}
С тех пор вы обновили, чтобы показать, что некоторые свойства выглядят так:
{
'name' => '...'
'value' => '...',
}
а некоторые выглядят как
{
'class' => '...',
'property' => [ ... ],
}
но ваш код обрабатывает только первый вид. Вы, вероятно, хотите что-то вроде if ($prop->{class})
,
print $prop_name ": " . $prop_value . "\n";
лечит $prop_name
в качестве дескриптора файла. Так должно быть
print $prop_name . ": " . $prop_value . "\n";
Это не дает прямого ответа на ваш вопрос, но я надеюсь показать альтернативный подход - я твердо убежден, что XML::Simple
... нет. Это делает ваш код намного сложнее, чем нужно. Итак, несколько примеров разбора вашего XML:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
#parse the file
my $twig = XML::Twig -> new();
$twig -> parsefile ( 'sample.xml' );
#iterate 'item' elements - note '//' means anywhere in document.
#you can use './' to denote only things under the current node.
foreach my $item ( $twig -> get_xpath ('//item') ) {
#item attributes:
print "ID: ", $item -> att('id'),"\n";
print "name: ", $item -> att('name'),"\n";
#subelement with a specific attribute name:
print "Material: ", $item -> get_xpath("./property[\@name='Material']", 0) -> att('value'),"\n";
#grab a nested property:
print "Action0 Range:";
#nb - errors on item 2, because it doesn't exist. This is illustrative.
print $item -> get_xpath(q{./property[@class='Action0']/property[@name='Range']},0) -> att('value'),"\n";
#iterate children:
print "Properties:\n";
#note - children only iterates beneath current node.
foreach my $property ( $item -> children('property') ) {
print $property -> att('name'),"\n" if defined $property->att('name');
}
}