1 package Net::Z3950::GRS1;
10 my ($class, $href, $map) = @_;
13 $self->{ELEMENTS} = [];
14 $self->{FH} = *STDOUT; ## Default output handle is STDOUT
17 if (defined($href) && ref($href) eq 'HASH') {
19 croak "Usage: new Net::Z3950::GRS1($href, $map);";
21 $self->Hash2grs($href);
29 my ($self, $href, $mapping) = @_;
34 $mapping = defined($mapping) ? $mapping : $self->{MAP};
35 foreach $key (keys %$href) {
36 $content = $href->{$key};
37 if (!defined($aref = $mapping->{$key})) {
38 print STDERR "Hash2grs: Unmapped key: '$key'\n";
41 if (ref($content) eq 'HASH') { ## Subtree?
42 my $subtree = new Net::Z3950::GRS1($content);
43 $self->AddElement($aref->[0], $aref->[1], &Net::Z3950::GRS1::ElementData::Subtree, $subtree);
44 } elsif (ref($content) eq '') { ## Regular string?
45 $self->AddElement($aref->[0], $aref->[1], &Net::Z3950::GRS1::ElementData::String, $content);
47 print STDERR "Hash2grs: Unsupported content type\n";
55 return $self->{ELEMENTS};
59 sub CreateTaggedElement {
60 my ($self, $type, $value, $element_data) = @_;
63 $tagged->{TYPE} = $type;
64 $tagged->{VALUE} = $value;
65 $tagged->{OCCURANCE} = undef;
66 $tagged->{META} = undef;
67 $tagged->{VARIANT} = undef;
68 $tagged->{ELEMENTDATA} = $element_data;
75 my ($self, $TaggedElement) = @_;
77 return ($TaggedElement->{TYPE}, $TaggedElement->{VALUE});
82 my ($self, $TaggedElement) = @_;
84 return $TaggedElement->{ELEMENTDATA};
89 my ($self, $which, $content) = @_;
91 if ($which == &Net::Z3950::GRS1::ElementData::String) {
92 if (ref($content) eq '') {
95 croak "Wrong content type, expected a scalar";
97 } elsif ($which == &Net::Z3950::GRS1::ElementData::Subtree) {
98 if (ref($content) eq __PACKAGE__) {
101 croak "Wrong content type, expected a blessed reference";
104 croak "Content type currently not supported";
109 sub CreateElementData {
110 my ($self, $which, $content) = @_;
111 my $ElementData = {};
113 $self->CheckTypes($which, $content);
114 $ElementData->{WHICH} = $which;
115 $ElementData->{CONTENT} = $content;
122 my ($self, $type, $value, $which, $content) = @_;
123 my $Elements = $self->GetElementList;
124 my $ElmData = $self->CreateElementData($which, $content);
125 my $TaggedElm = $self->CreateTaggedElement($type, $value, $ElmData);
127 push(@$Elements, $TaggedElm);
132 my ($self, $level) = @_;
135 foreach (1..$level - 1) {
144 my ($self, $level, $pool, @args) = @_;
145 my $fh = $self->{FH};
146 my $str = sprintf($self->_Indent($level) . shift(@args), @args);
149 if (defined($pool)) {
158 FORMAT => &Net::Z3950::GRS1::Render::Plain,
164 my @Elements = @{$self->GetElementList};
166 my $fh = $args{HANDLE};
167 my $level = ++$args{LEVEL};
168 my $ref = $args{POOL};
170 if (!defined($fh) && defined($args{FILE})) {
171 open(FH, '> ' . $args{FILE}) or croak "Render: Unable to open file '$args{FILE}' for writing: $!";
175 $self->{FH} = defined($fh) ? $fh : $self->{FH};
177 foreach $TaggedElement (@Elements) {
178 my ($type, $value) = $self->GetTypeValue($TaggedElement);
179 if ($self->GetElementData($TaggedElement)->{WHICH} == &Net::Z3950::GRS1::ElementData::String) {
180 $self->_RecordLine($level, $ref, "(%s,%s) %s\n", $type, $value, $self->GetElementData($TaggedElement)->{CONTENT});
181 } elsif ($self->GetElementData($TaggedElement)->{WHICH} == &Net::Z3950::GRS1::ElementData::Subtree) {
182 $self->_RecordLine($level, $ref, "(%s,%s) {\n", $type, $value);
183 $self->GetElementData($TaggedElement)->{CONTENT}->Render(%args);
184 $self->_RecordLine($level, $ref, "}\n");
188 $self->_RecordLine($level, $ref, "(0,0)\n");
193 package Net::Z3950::GRS1::ElementData;
195 ## Define some constants according to the GRS-1 specification
202 sub TrueOrFalse { 6 }
205 sub ElementNotThere { 9 }
206 sub ElementEmpty { 10 }
207 sub NoDataRequested { 11 }
208 sub Diagnostic { 12 }
212 package Net::Z3950::GRS1::Render;
214 ## Define various types of rendering formats
228 Net::Z3950::Record::GRS1 - Perl package used to encode GRS-1 records.
232 use Net::Z3950::GRS1;
234 my $a_grs1_record = new Net::Z3950::Record::GRS1;
235 my $another_grs1_record = new Net::Z3950::Record::GRS1;
237 $a_grs1_record->AddElement($type, $value, $content);
238 $a_grs1_record->Render();
242 This Perl module helps you to create and manipulate GRS-1 records (generic record syntax).
243 So far, you have only access to three methods:
247 Creates a new GRS-1 object,
249 my $grs1 = new Net::Z3950::GRS1;
253 Lets you add entries to a GRS-1 object. The method should be called this way,
255 $grs1->AddElement($type, $value, $which, $content);
257 where $type should be an integer, and $value is free text. The $which argument should
258 contain one of the constants listed in Appendix A. Finally, $content contains the "thing"
259 that should be stored in this entry. The structure of $content should match the chosen
260 element data type. For
262 $which == Net::Z3950::GRS1::ElementData::String;
264 $content should be some kind of scalar. If on the other hand,
266 $which == Net::Z3950::GRS1::ElementData::Subtree;
268 $content should be a GRS1 object.
272 This method digs through the GRS-1 data structure and renders the record. You call it
277 If you want to access the rendered record through a variable, you can do it like this,
279 my $record_as_string;
280 $grs1->Render(POOL => \$record_as_string);
282 If you want it stored in a file, Render should be called this way,
284 $grs1->Render(FILE => 'record.grs1');
286 When no file name is specified, you can choose to stream the rendered record, for instance,
288 $grs1->Render(HANDLE => *STDOUT); ## or
289 $grs1->Render(HANDLE => *STDERR); ## or
290 $grs1->Render(HANDLE => *MY_HANDLE);
294 This method converts a hash into a GRS-1 object. Scalar entries within the hash are converted
295 into GRS-1 string elements. A hash entry can itself be a reference to another hash. In this case,
296 the new referenced hash will be converted into a GRS-1 subtree. The method is called this way,
298 $grs1->Hash2grs($href, $mapping);
300 where $href is the hash to be converted and $mapping is referenced hash specifying the mapping
301 between keys in $href and (type, value) pairs in the $grs1 object. The $mapping hash could
302 for instance look like this,
310 If the $grs1 object contains data prior to the invocation of Hash2grs, the new data represented
311 by the hash is simply added.
316 These element data types are specified in the Z39.50 protocol:
318 Net::Z3950::GRS1::ElementData::Octets
319 Net::Z3950::GRS1::ElementData::Numeric
320 Net::Z3950::GRS1::ElementData::Date
321 Net::Z3950::GRS1::ElementData::Ext
322 Net::Z3950::GRS1::ElementData::String <---
323 Net::Z3950::GRS1::ElementData::TrueOrFalse
324 Net::Z3950::GRS1::ElementData::OID
325 Net::Z3950::GRS1::ElementData::IntUnit
326 Net::Z3950::GRS1::ElementData::ElementNotThere
327 Net::Z3950::GRS1::ElementData::ElementEmpty
328 Net::Z3950::GRS1::ElementData::NoDataRequested
329 Net::Z3950::GRS1::ElementData::Diagnostic
330 Net::Z3950::GRS1::ElementData::Subtree <---
332 Only the '<---' marked types are so far supported in this package.
336 Anders Sønderberg Mortensen <sondberg@indexdata.dk>
337 Index Data ApS, Copenhagen, Denmark.
342 Specification of the GRS-1 standard, for instance in the Z39.50 protocol specification.
347 #Revision 1.4 2001-05-17 14:07:06 sondberg
348 #Added some documentation.
350 #Revision 1.3 2001/05/17 13:43:04 sondberg
351 #Added method Hash2grs into GRS1 module.
353 #Revision 1.2 2001/03/13 14:53:15 sondberg
354 #Added a few lines of documentation into GRS1.pm.
356 #Revision 1.1 2001/03/13 14:17:15 sondberg
357 #Added support for GRS-1.