1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
package Open311::Endpoint::Spark;
use Moo;
=head1 NAME
Open311::Endpoint::Spark - transform from canonical data-structure to XML or JSON
=head1 SUMMARY
The Open311 docs discuss the Spark convention, to transform between XML and JSON.
http://wiki.open311.org/JSON_and_XML_Conversion#The_Spark_Convention
These options seem fragile, and require starting with the verbose XML form,
which isn't really natural in Perl. Instead, we'll start with a standard
Perl data structure, with a single extra hash wrapper, and will:
* for JSON, remove the outside hash wrapper
* for XML, for arrays, insert an extra layer with the singular name:
(this is the way XML::Simple knows how to do this nesting)
So:
# FROM
{
foo => {
bars => [ 1, 2, 3 ]
}
}
# JSON (note the 'foo' has been removed
{
bars: [
1,
2,
3
]
}
# XML intermediate
{
foo => {
bars => {
bar => [ 1, 2, 3 ]
}
}
}
# XML result
<foo>
<bars>
<bar>1</bar>
<bar>2</bar>
<bar>3</bar>
</bars>
</foo>
=cut
sub process_for_json {
my ($self, $data) = @_;
if (ref $data eq 'HASH' and scalar keys %$data == 1) {
my $inner = $data->{ (keys %$data)[0] };
$data = $inner if ref $inner;
}
return $data;
}
sub process_for_xml {
my ($self, $data) = @_;
# NB: in place mutation
_process_for_xml($data);
return $data;
}
# NB: in place mutation
sub _process_for_xml {
my $data = shift;
return unless ref $data;
if (ref $data eq 'HASH') {
while ( my ($k, $v) = each %$data) {
if (ref $v eq 'ARRAY') {
my $singular = _singularize($k);
# add extra layer
$data->{$k} = {
$singular => $v,
};
}
_process_for_xml($v);
}
}
elsif (ref $data eq 'ARRAY') {
for my $item (@$data) {
_process_for_xml($item);
}
}
}
my %singular_map = (
service_requests => 'request',
service_request_updates => 'request_update',
);
sub _singularize {
my $name = shift;
return $singular_map{ $name }
|| do {
# strip final 's' if present
$name =~ s/s$//;
return $name;
};
}
1;
|