Już widziałem kilka odpowiedzi w różnych miejscach, w odniesieniu do ustawiania kolejności elementów XML zwracanych przez XMLout
. Jednak nie jestem w stanie rozwiązać problemu za pomocą tych odpowiedzi/przykładów.XML :: Prosta kolejność elementów wyjściowych ze złożonego skrótu
Mam skrypt, który wymaga wyprowadzenia niektórych danych XML, a niektóre elementy muszą zostać wydrukowane w określonej kolejności. Hash jest dość skomplikowany i nie udało mi się uzyskać żadnych wyników przez przesłonięcie obiektu sorted_keys
w obiekcie XML::Simple
. Cóż, zrobiłem, ale nie tak, jak chciałem.
Przykładowy kod znajduje się poniżej, szczegóły problemu znajdują się poniżej kodu.
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple;
package MyXMLSimple;
use base 'XML::Simple';
sub sorted_keys
{
my ($self, $name, $hashref) = @_;
# ...
return $self->SUPER::sorted_keys($name, $hashref);
}
package main;
my $xmlParser = MyXMLSimple->new;
my $items = {
'status' => 'OK',
'fields' => {
'i1' => {
'header' => 'Header 1',
'max_size' => '3'
},
'i2' => {
'header' => 'Header 2',
'max_size' => '8'
}
},
'item_list' => {
'GGG' => {
'index' => '3',
'i' => 3,
'points' => {
'p5' => {
'data' => '10',
}
},
},
'AAA' => {
'index' => '1',
'i' => 2,
'points' => {
'p7' => {
'data' => '22',
}
},
},
'ZZZ' => {
'index' => '2',
'i' => 1,
'points' => {
'p6' => {
'data' => '15',
}
},
}
}
};
my $xml = $xmlParser->XMLout($items);
print "$xml";
więc wyjście z tego skryptu będzie to:
<opt status="OK">
<fields name="i1" header="Header 1" max_size="3" />
<fields name="i2" header="Header 2" max_size="8" />
<item_list name="AAA" i="2" index="1">
<points name="p7" data="22" />
</item_list>
<item_list name="GGG" i="3" index="3">
<points name="p5" data="10" />
</item_list>
<item_list name="ZZZ" i="1" index="2">
<points name="p6" data="15" />
</item_list>
</opt>
item_list
elementy są drukowane, a kolejność wyjścia jest alfabetycznie, sortując na atrybucie name
. Kolejność wyjściowa to AAA, GGG, ZZZ.
Jednak potrzebowałbym mieć wyjście podczas sortowania (numerycznie, od najniższego do najwyższego) elementu i
. Tak więc wyjście będzie w kolejności ZZZ, AAA, GGG.
Nie mam żadnej kontroli nad zamówieniem w haśle (nie bez użycia modułu Tie::...
), więc nie mogę tego zrobić w ten sposób. Jeśli użyję NoSort => 1
, dane wyjściowe nie zostaną posortowane według niczego, więc otrzymam losowe dane wyjściowe.
Jestem prawie pewny, że musi istnieć sposób, aby rozwiązać problem tak, jak tego chcę, przesuwając podprogram sorted_keys
. Jednak nie mogłem uzyskać pożądanych wyników, ponieważ wywoływana jest sorted_keys
dla każdego wystąpienia item_list
. Kiedy sorted_keys
jest wywoływany dla elementu opt
, to po prostu mam dostęp do całego hashu, ale znowu nie oznacza to zagwarantowania kolejności wyjściowej bez polegania na module Tie::
.
Teraz udało mi się uzyskać to działa tak, jak chcesz, za pomocą modułu Tie::IxHash
, następnie przesłanianie sorted_keys
i (re) tworząc SUBHASH item_list
poprzez wsunięcie wartości z oryginalnego hash do nowego (zamówione) jeden, a następnie usuwanie subhash w oryginalnym haszu i zastępowanie go nowym uporządkowanym hashem.
coś takiego:
sub sorted_keys
{
my ($self, $name, $hashref) = @_;
if ($name eq "opt")
{
my $clist = { };
tie %{$clist}, "Tie::IxHash";
my @sorted_keys = sort { $hashref->{item_list}->{$a}->{i} <=> $hashref->{item_list}->{$b}->{i} } keys %{$hashref->{item_list}};
foreach my $sorted_key (@sorted_keys)
{
$clist->{$sorted_key} = $hashref->{item_list}->{$sorted_key};
}
delete $hashref->{item_list};
$hashref->{item_list} = $clist;
}
return $self->SUPER::sorted_keys($name, $hashref);
}
Chociaż to działa (i jak dotąd wydaje się działać niezawodnie), wierzę, że musi być jakiś sposób, aby to osiągnąć bez użycia modułu Tie::IxHash
i robi wszystko, hash rekreacji/zmiana kolejności i tylko w jakiś sposób sortowanie/zwracanie pewnych danych z poziomu sorted_keys
.
Po prostu nie mogę tego rozgryźć i naprawdę nie rozumiem, jak powinien działać sorted_keys
(szczególnie, gdy uzyskuje się różne wyniki z różnymi/złożonymi zestawami danych wejściowych;), ale mam nadzieję, że jest ktoś tam, kto to wie.
Mam na myśli, próbowałem modyfikować sam XML/Simple.pm
i zmieniając kolejność sortowania w ostatniej linii zwrotnej z podprogramu sorted_keys
, ale wciąż otrzymywałem alfanumerycznie posortowane dane wyjściowe. Obawiam się, że nie mogę wymyślić, jak to zmodyfikować, aby nie sortować na name
, ale na i
.
Każda pomoc jest mile widziane :)
TLDR, bit +1 za dokładność (IMHO, bezowocny) wysiłek - zrobiłbym +2, gdybym mógł :) – DVK