1NAME
2 Data::URIEncode - Allow complex data structures to be encoded using flat
3 URIs.
4
5SYNOPSIS
6 use Data::URIEncode qw(flat_to_complex complex_to_flat);
7
8 my $data = {
9 foo => {
10 bar => 'bing',
11 },
12 baz => [123],
13 };
14
15 my $flat = complex_to_flat($data);
16 my $query = complex_to_query($data);
17
18 # $flat looks like:
19 $flat = {
20 'foo.bar' => 'bing',
21 'baz:0' => 123,
22 };
23
24 # $query looks like:
25 $query = "foo.bar=bing&baz:0=123"
26
27 ################################################
28
29 # put data back to how it was
30 $data = flat_to_complex($flat);
31
32 $data = query_to_complex($query);
33
34 ################################################
35
36 ### some html form somewhere
37 <form>
38 <input type="text" name="foo.bar.baz" value="brum">
39 <input type="text" name="bing:2" value="blang">
40 <input type="text" name="'key with :, ., and \''.red" value="blue">
41 </form>
42
43 ### when the form is submitted to the following code
44 use CGI;
45 use Data::URIEncode qw(query_to_complex);
46
47 my $q = CGI->new;
48 my $data = query_to_complex($q);
49
50 ### data will look like
51 $data = {
52 foo => {
53 bar => {
54 baz = "brum",
55 },
56 },
57 bing => [
58 undef,
59 undef,
60 "blang",
61 ],
62 "key with :, ., and '" => {
63 red = "blue",
64 },
65 };
66
67DESCRIPTION
68 The world of the web works off of URI's. The Query string portion of
69 URIs already support encoding of key/value paired data - they just don't
70 natively allow for for complex data structures.
71
72 There are modules or encodings that do support arbitrarily complex data
73 structures. JSON, YAML and Data::Dumper all have their own way of
74 encoding complex structures. But then to pass them across the web, you
75 usually still have to URL encode them and pass them via a form
76 parameter.
77
78 Data::URIEncode allows for encoding and decoding complex (multi level
79 datastructures) using native Query String manipulators (such as CGI.pm).
80 It takes complex data and turns it into a flat hashref which can then be
81 turned into a URI query string using URL encoding. It also takes a flat
82 hashref of data passed in and translates it back to a complex structure.
83
84 One benefit of using Data::URIEncode is that a standard submission from
85 a standard html form can automatically be translated into complex data
86 even though it arrived in a "flat" form. This somewhat mimics the
87 abilities of XForms without introducing the complexity of XForms.
88
89 Another benefit is that sparse data can be represented in a more compact
90 form than JSON or YAML are able to provide. However, complex data with
91 long key names will be more verbose as the full data hierarchy must be
92 repeated for each value.
93
94RULES
95 For each of the following rules, the $data can be translated to $flat
96 and $query by calling complex_to_flat and complex_to_query respectively.
97 The $flat and $query can be translated back into $data using
98 flat_to_complex and query_to_complex respectively.
99
100 Simple values stay simple
101 $data = {key => "val", key2 => "val2"};
102 $flat === {key => "val", key2 => "val2"};
103 $query eq "key=val&key2=val2"
104
105 Nested hashes use a dot to modify the key.
106 $data = {key => {key2 => "val"}};
107 $flat === {"key.key2" => "val"};
108 $query eq "key.key2=val
109
110 ########
111
112 $data = {foo => {bar => {baz => "bling"}}};
113 $flat === {"foo.bar.baz" = "bling"};
114 $query eq "foo.bar.baz=bling"
115
116 Nested arrays use a colon to modify the key.
117 $data = {key => ["val1", "val2"]};
118 $flat === {"key:0" => "val1", "key:1" => "val2"};
119 $query eq "key:0=val1&key:1=val2"
120
121 ########
122
123 $data = {key => [ [ ["val"] ] ]};
124 $flat === {"key:0:0" => "val"}
125 $query eq "key:0:0=val"
126
127 Data structures can have an arrayref as the top level
128 A leading colon is used to indicate the top level node is an
129 arrayref.
130
131 $data = ["val1", "val2"]
132 $flat === {":0" => "val1", ":1" => "val2"}
133 $query eq ":0=>val1&:1=>val2"
134
135 ########
136
137 $data = [ [ ["val"] ] ];
138 $flat === {":0:0:0" => "val"}
139 $query eq ":0:0:0=val"
140
141 Keys in flat hashrefs MAY begin with a leading dot
142 A leading dot may disambiguate some cases.
143
144 $query = ".foo=bar"
145 $flat = {".foo" => "bar"}
146 $data === {foo => "bar"}
147
148 Single quotes may be used to enclose complex strings.
149 Any key containing a colon ":", a dot ".", or a single quote "'"
150 must be quoted with single quotes and have enclosed single quotes
151 escaped.
152
153 $data = {"foo.bar" => "baz"}
154 $flat === {"'foo.bar'" => "baz"}
155 $query eq "'foo.bar'=baz" # the ' will be swapped with %27
156
157 ########
158
159 $data = {"foo:bar" => "baz"}
160 $flat === {"'foo:bar'" => "baz"}
161 $query eq "'foo:bar'=baz" # the ' will be swapped with %27
162
163 ########
164
165 $data = {"" => "baz"}
166 $flat === {"''" => "baz"}
167 $query eq "''=baz" # the ' will be swapped with %27
168
169 ########
170
171 $data = {"'" => "baz"}
172 $flat === {"'\\''" => "baz"}
173 $query eq "'\\''=baz" # the ' will be swapped with %27 and the \ will be replaced with %5C
174
175 Single quotes were chosen as double quotes are most commonly used in
176 HTML forms, thus allowing escaped single quotes more easily inside
177 the double quoted name.
178
179 Undefined values are not included in the flattened data
180 $data = {foo => undef, bar => 1}
181 $flat === {bar => 1}
182 $query eq "bar=1"
183
184 ########
185
186 $data = ["val1", undef, "val2"]
187 $flat === {":0" => "val1", ":2" => "val2"}
188 $query eq ":0=val1&:2=val2"
189
190 Blessed hashes and arrayrefs are dumped by default.
191 Changing the default value of the global $DUMP_BLESSED_DATA variable
192 changes the behavior.
193
194 $Data::URIEncode::DUMP_BLESSED_DATA = 1; # default
195 $data = {foo => bless({bar => "baz"}, "main"), one => "two"}
196 $flat === {"foo.bar" => "baz", one => "two"}
197 $query eq "foo.bar=baz&one=two"
198
199 ########
200
201 $Data::URIEncode::DUMP_BLESSED_DATA = 0;
202 $data = {foo => bless({bar => "baz"}, "main"), one => "two"}
203 $flat === {one => "two"}
204 $query eq "one=two"
205
206 Arrays created by flat_to_complex and query_to_complex must obey the
207 value of the $MAX_ARRAY_EXPAND variable.
208
209FUNCTIONS
210 flat_to_complex
211 Takes a hashref of simple key value pairs. Returns a data structure
212 based on the the parsed key value pairs. The parsing proceeds
213 according to the rules listed in RULES.
214
215 my $data = flat_to_complex({"foo.bar.baz:2" => "bling"});
216 # $data = {foo => {bar => {baz => [undef, undef, "bling"]}}};
217
218 complex_to_flat
219 Takes a complex data structure and turns it into a flat hashref
220 (single level key/value pairs only). The parsing proceeds according
221 to the rules listed in RULES.
222
223 my $flat = complex_to_flat({foo => ['a','b']});
224 # $flat = {"foo:0" => "a", "foo:1" => "b"});
225
226 complex_to_query
227 Similar to complex_to_flat, except that the flattened hashref is
228 then translated into query string suitable for use in a URI.
229
230 my $str = complex_to_query({foo => ['a','b']});
231 # $str eq "foo:0=a&foo:1=b"
232
233 query_to_complex
234 Takes one of a string, a reference to a string, a hash, or a CGI.pm
235 compatible object and translates it into a complex data structure.
236 Similar to flat_to_complex, exempt that a first step is taken to
237 access the query parameters from the CGI compatible object or
238 string. If a string or string ref is given, the CGI module is used
239 to parse the string into an initial flat hash of key value pairs
240 (using the param method). If another module is desired over, CGI.pm
241 you must initialize it with the data to be parsed prior to passing
242 the object to the query_to_complex function.
243
244 my $data = query_to_complex("foo.bar:0=baz");
245
246 my $data = query_to_complex(\ "foo.bar:0=baz");
247
248 my $data = query_to_complex({"foo.bar:0" => "baz"}); # same as flat_to_complex
249
250 my $cgi = CGI->new(\ "foo.bar:0=baz");
251 my $data = query_to_complex($cgi);
252
253 my $cgi = CGI->new; # use the values passed in from STDIN
254 my $data = query_to_complex($cgi);
255
256VARIABLES
257 $MAX_ARRAY_EXPAND
258 Default value is 100. This variable is used to determine how large
259 flat_to_complex will allow an array to be expanded beyond its
260 current size. An array can grow as large as you have memory, but
261 intermediate values must exist.
262
263 Without this value, somebody could specify foo:1000000000000=bar and
264 your server would attempt to set the 1000000000000th index of the
265 foo value to bar.
266
267 The string "foo:101=bar" would die, but the string
268 "foo:50=bar&foo:101=baz" would not die because the intermediate
269 foo->[50] increments the foo arrayref by 51 and the subsequent
270 foo->[101] call increments the foo arrayref by only 51.
271
272 $DUMP_BLESSED_DATA
273 Default is true. If true, blessed hashrefs and arrayrefs will also
274 be added to the flat data returned by complex_to_flat. If false,
275 bless hashrefs and arrayrefs will be skipped.
276
277BUGS
278 Circular refs are not detected. Any attempt to dump a struture with
279 cirular refs will result in an infinite loop. There is no immediate plan
280 to add circular ref tracking.
281
282SEE ALSO
283 All of the following have attempted to solve the same problem as
284 Data::URIEncode. All of them (including Data::URIEncode) suffer from the
285 problem of being hard to find for the specific purpose. Hash::Flatten is
286 probably the only suitable replacement for Data::URIEncode.
287
288 Hash::Flatten
289
290 CGI::Expand
291
292 HTTP::Rollup
293
294 CGI::State
295
296AUTHOR
297 Paul Seamons perlspam at seamons dot com
298
299LICENSE
300 This library may be distributed under the same terms as Perl itself.
301
302