File Coverage

blib/lib/Syndication/NITF.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


elements in the main table
line stmt bran cond sub pod time code
1             # $Id: NITF.pm,v 0.2 2001/12/19 05:30:13 brendan Exp $
2             # Syndication::NITF.pm
3              
4             $VERSION = sprintf("%d.%02d", q$Revision: 0.2 $ =~ /(\d+)\.(\d+)/);
5             $VERSION_DATE= sprintf("%s", q$Date: 2001/12/19 05:30:13 $ =~ m# (.*) $# );
6              
7             $DEBUG = 0;
8              
9             #
10             # Syndication::NITF -- initial parser. Maybe this should be Syndication::NITF::Parser or something?
11             # also grabs the first NITF element to save time, is that a good idea?
12             # does it mean that you can't grab extra namespace/DTD declarations etc?
13             #
14             package Syndication::NITF;
15 2     2   26642 use Carp;
  2         6  
  2         201  
16 2     2   7487 use XML::DOM;
  0            
  0            
17             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
18              
19             sub _init {
20             my ($self, $filename) = @_;
21              
22             $self->{parser} = new XML::DOM::Parser;
23             $self->{doc} = $self->{parser}->parsefile($filename);
24             $self->{node} = $self->{doc}->getElementsByTagName("nitf", 0)->item(0);
25              
26             $self->{_singleElements}{head} = OPTIONAL;
27             $self->{_singleElements}{body} = REQUIRED;
28              
29             $self->{_attributes}{uno} = IMPLIED; # unique identifier for this document
30             $self->{_attributes}{baselang} = IMPLIED;
31             $self->{_attributes}{class} = IMPLIED;
32              
33             return $self;
34             }
35              
36             =pod
37              
38             =head1 NAME
39              
40             Syndication::NITF -- Parser for NITF v3.0 documents
41              
42             =head1 VERSION
43              
44             Version $Revision: 0.2 $, released $Date: 2001/12/19 05:30:13 $
45              
46             =head1 SYNOPSIS
47              
48             use Syndication::NITF;
49              
50             my $nitf = new Syndication::NITF("myNITFfile.xml");
51             my $head = $nitf->gethead;
52              
53             my $title = $head->gettitle->getText;
54              
55             my $tobject = $head->gettobject;
56             if ($tobject->gettobjecttype eq "news") {
57             my $items = $tobject->gettobjectsubjectList;
58             foreach my $item (@$items) {
59             # process each subject header
60             ...
61             }
62             }
63             ... etc ...
64              
65             =head1 DESCRIPTION
66              
67             B is an object-oriented Perl interface to NITF documents, allowing
68             you to manage (and one day create) NITF documents without any specialised NITF
69             or XML knowledge.
70              
71             NITF is a standard format for the markup of textual news content (eg newspaper and
72             magazine articles), ratified by the International Press Telecommunications
73             Council (http://www.iptc.org).
74              
75             This module supports the version 3.0 DTD of NITF. It makes no attempt to support eariler
76             versions of the DTD.
77              
78             The module code is based on my B module, and much of the functionality
79             is shared between the two (well actually it's copied from the NewsML module rather than
80             "shared" properly in the form of a separate module of shared classes -- this may be remedied
81             in the future).
82              
83             =head2 Initialization
84              
85             At the moment the constructor can only take a filename as an argument, as follows:
86              
87             my $nitf = new Syndication::NITF("file-to-parse.xml");
88              
89             This attaches a parser to the file (using XML::DOM), and returns a reference to the first NITF
90             tag. (I may decide that this is a bad idea and change it soon)
91              
92             =head2 Reading objects
93              
94             There are five main types of calls:
95              
96             =over 4
97              
98             =item *
99              
100             Get an individual element:
101              
102             my $head = $nitf->gethead;
103              
104             =item *
105              
106             Return a reference to an array of elements:
107              
108             my $identifiedcontentlist = $head->getdocdata->getidentifiedcontentList;
109              
110             The array can be referenced as @$identifiedcontentlist, or an individual element can be
111             referenced as $identifiedcontentlist->[N].
112              
113             =item *
114              
115             Return the size of a list of elements:
116              
117             my $iclcount = $head->getdocdata->getidentifiedcontentCount;
118              
119             =item *
120              
121              
122             Get an attribute of an element (as text):
123              
124             my $href = $catalog->getHref;
125              
126             =item *
127              
128             Get the contents of an element (ie the text between the opening and closing tags):
129              
130             my $urlnode = $catalog->getResourceList->[0]->getUrlList->[0];
131             my $urltext = $urlnode->getText;
132              
133             =back
134              
135             Not all of these calls work for all elements: for example, if an element is defined in the NITF DTD
136             as having zero or one instances in its parent element, and you try to call getXXXList, B
137             will "croak" an error. (The error handling will be improved in the future so that it won't croak
138             fatally unless you want that to happen)
139              
140             The NITF standard contains some "business rules" also written into the DTD: for example, a NewsItem
141             may contain nothing, a NewsComponent, one or more Update elements, or a TopicSet. For some of these
142             rules, the module is smart enough to detect errors and provide a warning. Again, these warnings will
143             be improved and extended in future versions of this module.
144              
145             =head2 Documentation for all the classes
146              
147             Each NITF element is represented as a class. This means that you can traverse documents as Perl
148             objects, as seen above.
149              
150             Full documentation of which classes can be used in which documents is beyond me right now (with over
151             120 classes to document), so for now you'll have to work with the examples in the B and
152             B directories to see what's going on. You should be able to get a handle on it fairly quickly.
153              
154             The real problem is that it's hard to know when to use B and when to use B
155             -- that is, when an element can have more than one entry and when it is a singleton. Quite often it
156             isn't obvious from looking at a NITF document. For now, two ways to work this out are to try it and see
157             if you get an error, or to have a copy of the DTD in front of you. Obviously neither of these is
158             optimal, but documenting all 127 classes just so people can tell this difference is pretty scary as
159             well, and so much documentation would put lots of people off using the module. So I'll probably come
160             up with a reference document listing all the classes and methods, rather than docs for each class, in
161             a future release. If anyone has any better ideas, please let me know.
162              
163             =head1 BUGS
164              
165             None that I know of, but there are probably many. The test suite isn't complete, so not every method
166             is tested, but the major ones (seem to) work fine. Of course, if you find bugs, I'd be very keen to
167             hear about them at B.
168              
169             =head1 SEE ALSO
170              
171             L, L, L
172              
173             =head1 AUTHOR
174              
175             Brendan Quinn, Clueful Consulting Pty Ltd
176             (brendan@clueful.com.au)
177              
178             =head1 COPYRIGHT
179              
180             Copyright (c) 2001, Brendan Quinn. All Rights Reserved.
181             This module is free software. It may be used, redistributed
182             and/or modified under the same terms as Perl itself.
183              
184             =cut
185              
186             #
187             # Syndication::NITF::DOMUtils -- a few helpful routines
188             #
189             package Syndication::NITF::DOMUtils;
190             use Carp;
191             $DEBUG = 0;
192              
193             # walk the tree of descendents of $node to look for an attribute $attr with value $value.
194             # returns the matching node, or undef.
195             sub findElementByAttribute {
196             my ($node, $attr, $value) = @_;
197             my $tstattr = $node->getAttributeNode($attr);
198             return $node if defined($tstattr) && ($tstattr->getValue eq $value);
199             my $iternode;
200             if ($node->hasChildNodes) {
201             for my $child ($node->getChildNodes) {
202             if ($child->getNodeType == XML::DOM::ELEMENT_NODE) {
203             $iternode = findElementByAttribute($child, $attr, $value);
204             }
205             return $iternode if defined($iternode);
206             }
207             }
208             return undef;
209             }
210              
211             # return a reference to the NITF element at the top level of the document.
212             # will croak if not NITF element exists in the parent path of the given node.
213             sub getRootNode {
214             my ($node) = @_;
215             if (!defined($node)) {
216             croak "Invalid document! getRootNode couldn't find a NITF element in parent path";
217             } elsif ($node->getNodeName eq "NITF") {
218             return $node;
219             } else {
220             return getRootNode($node->getParentNode);
221             }
222             }
223              
224             #
225             # Syndication::NITF::References -- routines to follow references
226             # (any ideas for a better name?)
227             package Syndication::NITF::References;
228             use Carp;
229             $DEBUG = 0;
230              
231             # find reference (based on NITF Toolkit Java version)
232             # get referenced data from within this document or possibly an external URL.
233             # parameter useExternal, if true, means we can look outside this document if necessary.
234             sub findReference {
235             my ($node, $reference, $useExternal) = @_;
236             # if reference starts with # it's in the local document (or should be)
237             if ($reference =~ /^#/) {
238             return $node->getElementByDuid(substr($reference, 1));
239             } elsif ($useExternal) {
240             # use LWP module to get the external document
241             use LWP::UserAgent;
242             my $ua = new LWP::UserAgent;
243             $ua->agent("Syndication::NITF/0.04" . $ua->agent);
244             my $req = new HTTP::Request GET => substr($reference, 1);
245             my $response = $ua->request($req);
246             if ($response->is_success) {
247             return $response->content;
248             }
249             }
250             # document is external but we're not allowed to go outside
251             # or an error occured with the retrieval
252             # maybe should flag error better than this??
253             return undef;
254             }
255              
256             #
257             # Syndication::NITF::Node -- superclass defining a few functions all these will need
258             #
259             package Syndication::NITF::Node;
260             use Carp;
261             @ISA = qw( XML::DOM::Node );
262             $DEBUG = 0;
263              
264             sub new {
265             my ($class, $node) = @_;
266             my $self = bless {}, $class;
267              
268             use constant REQUIRED => 1;
269             use constant IMPLIED => 2;
270             use constant OPTIONAL => 3;
271             use constant ZEROORMORE => 4;
272             use constant ONEORMORE => 5;
273              
274             $self->{node} = $node;
275             $self->{text} = undef;
276             $self->{_tagname} = undef;
277              
278             # child elements we may want to access
279             $self->{_singleElements} = {};
280             $self->{_multiElements} = {};
281             $self->{_attributes} = {};
282             $self->{_hasText} = 0;
283              
284             $self->_init($node); # init will vary for different subclasses
285              
286             # call _init of ALL parent classes as well
287             # thanks to Duncan Cameron for suggesting how to get this to work!
288             $_->($self, $node) for ( map {$_->can("_init")||()} @{"${class}::ISA"} );
289              
290             return $self;
291             }
292              
293             sub _init { } # undef init, subclasses may want to use it
294              
295             # get the contents of an element as as XML string (wrapper around XML::DOM::Node::toString)
296             # this *includes* the container tag of the current element.
297             sub getXML {
298             my ($self) = @_;
299             $self->{xml} = $self->{node}->toString;
300             }
301              
302             # get the text of the element, if any
303             # now includes get text of all children, including elements, recursively!
304             sub getText {
305             my ($self, $stripwhitespace) = @_;
306             croak "Can't use getText on this element" unless $self->{_hasText};
307             $self->{text} = "";
308             $self->{text} = getTextRecursive($self->{node}, $stripwhitespace);
309             }
310              
311             # special "cheat" method to get ALL text in ALL child elements, ignoring any markup tags.
312             # can use on any element, anywhere (if there's no text, it will just return an empty string
313             # or all whitespace)
314             sub getAllText {
315             my ($self, $stripwhitespace) = @_;
316             $self->{text} = "";
317             $self->{text} = getTextRecursive($self->{node}, $stripwhitespace);
318             }
319              
320             sub getTextRecursive {
321             my ($node, $stripwhitespace) = @_;
322             my $textstring;
323             for my $child ($node->getChildNodes()) {
324             if ( $child->getNodeType == XML::DOM::ELEMENT_NODE ) {
325             $textstring .= getTextRecursive($child, $stripwhitespace);
326             } else {
327             my $tmpstring = $child->getData();
328             if ($stripwhitespace && ($stripwhitespace eq "strip")) {
329             $tmpstring =~ s/^\s+/ /; #replace with single space -- is this ok?
330             $tmpstring =~ s/\s+$/ /; #replace with single space -- is this ok?
331             }
332             $textstring .= $tmpstring;
333             }
334             }
335             $textstring =~ s/\s+/ /g if $stripwhitespace; #replace with single space -- is this ok?
336             return $textstring;
337             }
338              
339             # get the tag name of this element
340             sub getTagName {
341             my ($self) = @_;
342             $self->{_tagname} = $self->{node}->getTagName;
343             }
344              
345             # get the path up to and including this element
346             sub getPath {
347             my ($self) = @_;
348             $self->getParentPath($self->{node});
349             }
350              
351             # get the path of this node including all parent nodes (called by getPath)
352             sub getParentPath {
353             my ($self, $parent) = @_;
354             # have to look two levels up because XML::DOM treats "#document" as a level in the tree
355             return $parent->getNodeName if !defined($parent->getParentNode->getParentNode);
356             return $self->getParentPath($parent->getParentNode) . "->" . $parent->getNodeName;
357             }
358              
359             # attempt to return an array of all children, in order, as instantiated nodes
360             sub getChildrenList {
361             my ($self) = @_;
362             my @childarray;
363             foreach my $child ($self->{node}->getChildNodes) {
364             if ($child->getNodeType == XML::DOM::ELEMENT_NODE) {
365             my $nodename = $child->getNodeName;
366             $nodename =~ s/[\-\.]//g; # remove dots and dashes from element names
367             my $elementObject = "Syndication::NITF::$nodename"->new($child);
368             push(@childarray, $elementObject);
369             }
370             }
371             return @childarray;
372             }
373              
374             use vars '$AUTOLOAD';
375              
376             # Generic routine to extract child elements from node.
377             # handles "getParamaterName", "getParameterNameList" and "getParameterNameCount"
378             sub AUTOLOAD {
379             my ($self) = @_;
380              
381             if ($AUTOLOAD =~ /DESTROY$/) {
382             return;
383             }
384              
385             # extract attribute name
386             $AUTOLOAD =~ /.*::get(\w+)/
387             or croak "No such method: $AUTOLOAD";
388              
389             print "AUTOLOAD: method is $AUTOLOAD\n" if $DEBUG;
390             my $call = $1;
391              
392             # we can't have method names with dots and dashes in them, but we need them for the
393             # element/attribute names. So We use the kludge "_realname" hash to store the name inclusive
394             # of dots and dashes
395             my $oldname = $call;
396             my $realname = $self->{_realname}->{$call};
397             $realname = $call unless $realname;
398            
399             if ($call =~ /(\w+)Count$/) {
400              
401             # handle getXXXCount method
402             my $oldvar = $1;
403             $var = $self->{_realname}->{$oldvar} || $oldvar;
404             if (!$self->{_multiElements}->{$var}) {
405             croak "Can't use getCount on $var";
406             }
407             my $method = "get".$oldvar."List";
408             $self->$method unless defined($self->{$var."Count"});
409             return $self->{$var."Count"};
410             } elsif ($call =~ /(\w+)List$/) {
411              
412             # handle getXXXList method for multi-element tags
413             my $oldname = $1;
414             my $elem = $self->{_realname}->{$oldname} || $oldname;
415              
416             if (!$self->{_multiElements}->{$elem}) {
417             croak "No such method: $AUTOLOAD";
418             }
419             my $list = $self->{node}->getElementsByTagName($elem, 0);
420             if (!$list && $self->{_multiElements}->{$elem} eq ONEORMORE) {
421             croak "Error: required element $elem is missing";
422             }
423             # set elemCount while we know what it is
424             $self->{$elem."Count"} = $list->getLength;
425             my @elementObjects;
426             my $elementObject;
427             for (my $i = 0; $i < $self->{$elem."Count"}; $i++) {
428             $elementObject = "Syndication::NITF::$oldname"->new($list->item($i))
429             if defined($list->item($i)); # if item is undef, push an undef to the array
430             push(@elementObjects, $elementObject);
431             }
432             $self->{$elem} = \@elementObjects;
433             return wantarray ? @elementObjects : $self->{$elem};
434             } elsif ($self->{_singleElements}->{$realname}) {
435              
436             # handle getXXX method for single-element tags
437             my $element = $self->{node}->getElementsByTagName($realname, 0);
438             if (!$element && $self->{_singleElements}->{$realname} eq REQUIRED) {
439             croak "Error: required element $realname is missing";
440             }
441             # BQ altered 2001-12-05 so a non-existing element returns undef rather than an empty node
442             $self->{$realname} = "Syndication::NITF::$oldname"->new($element->item(0));
443             return $element->item(0)
444             ? $self->{$realname} = "Syndication::NITF::$oldname"->new($element->item(0))
445             : undef;
446             } elsif ($self->{_attributes}->{$realname}) {
447             # return undef if self->node doesn't exist
448             return undef unless defined($self->{node});
449             return undef unless defined($self->{node}->getAttributeNode($realname));
450             $self->{$realname} = $self->{node}->getAttributeNode($realname)->getValue;
451             if (!$self->{$realname} && $self->{_attributes}->{$realname} eq REQUIRED) {
452             croak "Error: $realname attribute is required";
453             }
454             return $self->{$realname};
455             } elsif ($self->{_multiElements}->{$realname}) {
456             # flag error because multiElement needs to be called with "getBlahList"
457             croak "$call can occur more than once: must call get".$call."List";
458             } else {
459             croak "No such method: $AUTOLOAD";
460             }
461             }
462              
463             #
464             # Syndication::NITF::GlobalAttributesNode -- standard attributes used in most elements
465             #
466             package Syndication::NITF::GlobalAttributesNode;
467             use Carp;
468             @ISA = qw( Syndication::NITF::Node );
469              
470             sub _init {
471             my ($self, $node) = @_;
472             $self->{_attributes}->{id} = IMPLIED;
473             }
474              
475             # id must me unique to the entire document.
476             sub getElementById {
477             my ($self, $searchID) = @_;
478              
479             my $rootNode = Syndication::NITF::DOMUtils::getRootNode($self->{node});
480             Syndication::NITF::DOMUtils::findElementByAttribute($rootNode, "Duid", $searchID);
481             }
482              
483             #
484             # Syndication::NITF::CommonAttributesNode -- standard attributes used in most elements
485             #
486             package Syndication::NITF::CommonAttributesNode;
487             use Carp;
488             @ISA = qw( Syndication::NITF::Node );
489              
490             sub _init {
491             my ($self, $node) = @_;
492             $self->{_attributes}->{id} = IMPLIED;
493             $self->{_attributes}->{class} = IMPLIED;
494             $self->{_attributes}->{style} = IMPLIED;
495             }
496              
497             #
498             # Syndication::NITF::EnrichedTextNode -- standard "rich text" type node, has lots of possibilities
499             #
500             package Syndication::NITF::EnrichedTextNode;
501             use Carp;
502             @ISA = qw( Syndication::NITF::Node );
503              
504             sub _init {
505             my ($self, $node) = @_;
506             $self->{_multiElements}->{chron} = ZEROORMORE;
507             $self->{_multiElements}->{classifier} = ZEROORMORE;
508             $self->{_multiElements}->{copyrite} = ZEROORMORE;
509             $self->{_multiElements}->{event} = ZEROORMORE;
510             $self->{_multiElements}->{function} = ZEROORMORE;
511             $self->{_multiElements}->{location} = ZEROORMORE;
512             $self->{_multiElements}->{money} = ZEROORMORE;
513             $self->{_multiElements}->{num} = ZEROORMORE;
514             $self->{_realname}->{objecttitle} = "object.title";
515             $self->{_multiElements}->{"object.title"} = ZEROORMORE;
516             $self->{_multiElements}->{org} = ZEROORMORE;
517             $self->{_multiElements}->{person} = ZEROORMORE;
518             $self->{_multiElements}->{postaddr} = ZEROORMORE;
519             $self->{_multiElements}->{virtloc} = ZEROORMORE;
520             $self->{_multiElements}->{a} = ZEROORMORE;
521             $self->{_multiElements}->{br} = ZEROORMORE;
522             $self->{_multiElements}->{em} = ZEROORMORE;
523             $self->{_multiElements}->{lang} = ZEROORMORE;
524             $self->{_multiElements}->{pronounce} = ZEROORMORE;
525             $self->{_multiElements}->{q} = ZEROORMORE;
526             $self->{_hasText} = 1;
527             }
528              
529             #
530             # Syndication::NITF::BlockContentNode -- nodes that include marked up content
531             #
532             package Syndication::NITF::BlockContentNode;
533             use Carp;
534             @ISA = qw( Syndication::NITF::Node );
535              
536             sub _init {
537             my ($self, $node) = @_;
538             $self->{_multiElements}->{p} = ZEROORMORE;
539             $self->{_multiElements}->{hl2} = ZEROORMORE;
540             $self->{_multiElements}->{table} = ZEROORMORE;
541             $self->{_realname}->{nitftable} = "nitf-table";
542             $self->{_multiElements}->{"nitf-table"} = ZEROORMORE;
543             $self->{_multiElements}->{media} = ZEROORMORE;
544             $self->{_multiElements}->{ol} = ZEROORMORE;
545             $self->{_multiElements}->{uk} = ZEROORMORE;
546             $self->{_multiElements}->{dl} = ZEROORMORE;
547             $self->{_multiElements}->{bq} = ZEROORMORE;
548             $self->{_multiElements}->{fn} = ZEROORMORE;
549             $self->{_multiElements}->{note} = ZEROORMORE;
550             $self->{_multiElements}->{pre} = ZEROORMORE;
551             $self->{_multiElements}->{hr} = ZEROORMORE;
552             }
553              
554             #
555             # Syndication::NITF::DateNode -- superclass defining an extra method for elements
556             # that contain ISO8601 formatted dates
557             # NEEDS TO BE CHANGED because most ISO8601 date "nodes" are actually attributes in NITF
558             package Syndication::NITF::DateNode;
559             use Carp;
560              
561             # convert ISO8601 date/time into Perl internal date/time.
562             # always returns perl internal date, in UTC timezone.
563             sub getDatePerl {
564             my ($self, $timezone) = @_;
565             use Time::Local;
566             my $dateISO8601 = $self->getText;
567             my ($yyyy, $mm, $dd, $hh, $mi, $ss, $tzsign, $tzhh, $tzmi) = ($dateISO8601 =~ qr/(\d\d\d\d)(\d\d)(\d\d)T?(\d\d)?(\d\d)?(\d\d)?([+-])?(\d\d)?(\d\d)?/);
568             my $perltime = timegm($ss, $mi, $hh, $dd, $mm-1, $yyyy);
569             if ($tzhh) {
570             my $deltasecs = 60 * ($tzsign eq "-") ? -1*($tzhh * 60 + $tzmi) : ($tzhh * 60 + $tzmi);
571             $perltime += $deltasecs;
572             }
573             return $perltime;
574             }
575              
576             #
577             # Syndication::NITF::head -- header of a document
578             #
579             package Syndication::NITF::head;
580             use Carp;
581             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
582              
583             sub _init {
584             my ($self, $node) = @_;
585             $self->{_singleElements}->{title} = OPTIONAL;
586             $self->{_multiElements}->{meta} = ZEROORMORE;
587             $self->{_singleElements}->{tobject} = OPTIONAL;
588             $self->{_singleElements}->{iim} = OPTIONAL;
589             $self->{_singleElements}->{docdata} = OPTIONAL;
590             $self->{_multiElements}->{pubdata} = ZEROORMORE;
591             $self->{_realname}->{revisionhistory} = "revision-history";
592             $self->{_multiElements}->{"revision-history"} = ZEROORMORE;
593             }
594              
595             #
596             # Syndication::NITF::title -- document title
597             #
598             package Syndication::NITF::title;
599             use Carp;
600             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
601              
602             sub _init {
603             my ($self, $node) = @_;
604             $self->{_hasText} = 1;
605             }
606              
607             # attribute is an enumeration so we must handle separately
608             sub gettype { # type of title
609             my ($self) = @_;
610             my @possiblevalues = qw(main subtitle parttitle alternate abbrev other);
611             my $attr = $self->{node}->getAttributeNode("type");
612             $self->{"type"} = $attr ? $attr->getValue : "";
613             if ($self->{type} && grep !/$self->{type}/, "@possiblevalues") {
614             croak "Illegal value ".$self->{type}." for attribute type";
615             }
616             return $self->{type};
617             }
618              
619             #
620             # Syndication::NITF::meta -- generic metadata
621             #
622             package Syndication::NITF::meta;
623             use Carp;
624             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
625              
626             sub _init {
627             my ($self, $node) = @_;
628             $self->{_realname}->{httpequiv} = "http-equiv";
629             $self->{_attributes}->{"http-equiv"} = IMPLIED; # HTTP response header name
630             $self->{_attributes}->{name} = IMPLIED; # Name of this piece of metadata
631             $self->{_attributes}->{content} = REQUIRED; # Name of this piece of metadata
632             }
633              
634             #
635             # Syndication::NITF::tobject -- subject code
636             #
637             package Syndication::NITF::tobject;
638             use Carp;
639             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
640              
641             sub _init {
642             my ($self, $node) = @_;
643             $self->{_realname}->{tobjectproperty} = "tobject.property";
644             $self->{_multiElements}->{"tobject.property"} = ZEROORMORE;
645             $self->{_realname}->{tobjectsubject} = "tobject.subject";
646             $self->{_multiElements}->{"tobject.subject"} = ZEROORMORE;
647             $self->{_realname}->{tobjecttype} = "tobject.type";
648             $self->{_attributes}->{"tobject.type"} = IMPLIED;
649             }
650              
651             # this attribute has a default so we have to handle it separately
652             sub gettobjecttype {
653             my ($self) = @_;
654             my $attr = $self->{node}->getAttributeNode("tobject.type");
655             $self->{"tobjecttype"} = $attr ? $attr->getValue : "news";
656             }
657              
658             #
659             # Syndication::NITF::tobject.property -- subject code
660             # we introduced a hack to handle this: these class names leave out the dot from the element name
661             #
662             package Syndication::NITF::tobjectproperty;
663             use Carp;
664             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
665              
666             sub _init {
667             my ($self, $node) = @_;
668             $self->{_realname}->{tobjectpropertytype} = "tobject.property.type";
669             $self->{_attributes}->{"tobject.property.type"} = IMPLIED;
670             }
671              
672             # this attribute has a default so we have to handle it separately
673             sub gettobjectpropertytype {
674             my ($self) = @_;
675             my $attr = $self->{node}->getAttributeNode("tobject.property.type");
676             $self->{"tobjectpropertytype"} = $attr ? $attr->getValue : "current";
677             }
678              
679             #
680             # Syndication::NITF::tobject.subject -- subject classification
681             # we introduced a hack to handle this: these class names leave out the dot from the element name
682             #
683             package Syndication::NITF::tobjectsubject;
684             use Carp;
685             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
686              
687             sub _init {
688             my ($self, $node) = @_;
689             $self->{_realname}->{tobjectsubjectipr} = "tobject.subject.ipr";
690             $self->{_attributes}->{"tobject.subject.ipr"} = IMPLIED;
691             $self->{_realname}->{tobjectsubjectrefnum} = "tobject.subject.refnum";
692             $self->{_attributes}->{"tobject.subject.refnum"} = REQUIRED;
693             $self->{_realname}->{tobjectsubjectcode} = "tobject.subject.code";
694             $self->{_attributes}->{"tobject.subject.code"} = IMPLIED;
695             $self->{_realname}->{tobjectsubjecttype} = "tobject.subject.type";
696             $self->{_attributes}->{"tobject.subject.type"} = IMPLIED;
697             $self->{_realname}->{tobjectsubjectmatter} = "tobject.subject.matter";
698             $self->{_attributes}->{"tobject.subject.matter"} = IMPLIED;
699             $self->{_realname}->{tobjectsubjectdetail} = "tobject.subject.detail";
700             $self->{_attributes}->{"tobject.subject.detail"} = IMPLIED;
701             }
702              
703             # this attribute has a default so we have to handle it separately
704             sub gettobjectsubjectipr {
705             my ($self) = @_;
706             my $attr = $self->{node}->getAttributeNode("tobject.subject.ipr");
707             $self->{"tobjectsubjectipr"} = $attr ? $attr->getValue : "IPTC";
708             }
709              
710             #
711             # Syndication::NITF::iim -- IIM Record 2 Data Container
712             #
713             package Syndication::NITF::iim;
714             use Carp;
715             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
716              
717             sub _init {
718             my ($self, $node) = @_;
719             $self->{_multiElements}->{ds} = ZEROORMORE;
720             $self->{_attributes}->{ver} = IMPLIED; # IIM version number
721             }
722              
723             #
724             # Syndication::NITF::ds -- IIM Record 2 dataset information
725             #
726             package Syndication::NITF::ds;
727             use Carp;
728             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
729              
730             sub _init {
731             my ($self, $node) = @_;
732             $self->{_multiElements}->{ds} = ZEROORMORE;
733             $self->{_attributes}->{num} = REQUIRED; # IIM field number
734             $self->{_attributes}->{value} = IMPLIED; # IIM field value
735             }
736              
737             #
738             # Syndication::NITF::docdata -- Document metadata
739             #
740             package Syndication::NITF::docdata;
741             use Carp;
742             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
743              
744             sub _init {
745             my ($self, $node) = @_;
746             $self->{_multiElements}->{correction} = ZEROORMORE;
747             $self->{_multiElements}->{evloc} = ZEROORMORE;
748             $self->{_realname}->{docid} = "doc-id";
749             $self->{_multiElements}->{"doc-id"} = ZEROORMORE;
750             $self->{_realname}->{dellist} = "del-list";
751             $self->{_multiElements}->{"del-list"} = ZEROORMORE;
752             $self->{_multiElements}->{urgency} = ZEROORMORE;
753             $self->{_multiElements}->{fixture} = ZEROORMORE;
754             $self->{_realname}->{dateissue} = "date.issue";
755             $self->{_multiElements}->{"date.issue"} = ZEROORMORE;
756             $self->{_realname}->{daterelease} = "date.release";
757             $self->{_multiElements}->{"date.release"} = ZEROORMORE;
758             $self->{_realname}->{dateexpire} = "date.expire";
759             $self->{_multiElements}->{"date.expire"} = ZEROORMORE;
760             $self->{_realname}->{docscope} = "doc-scope";
761             $self->{_multiElements}->{"doc-scope"} = ZEROORMORE;
762             $self->{_multiElements}->{series} = ZEROORMORE;
763             $self->{_realname}->{edmsg} = "ed-msg";
764             $self->{_multiElements}->{"ed-msg"} = ZEROORMORE;
765             $self->{_realname}->{dukey} = "du-key";
766             $self->{_multiElements}->{"du-key"} = ZEROORMORE;
767             $self->{_realname}->{doccopyright} = "doc.copyright";
768             $self->{_multiElements}->{"doc.copyright"} = ZEROORMORE;
769             $self->{_realname}->{docrights} = "doc.rights";
770             $self->{_multiElements}->{"doc.rights"} = ZEROORMORE;
771             $self->{_realname}->{keylist} = "key-list";
772             $self->{_multiElements}->{"key-list"} = ZEROORMORE;
773             $self->{_realname}->{identifiedcontent} = "identified-content";
774             $self->{_multiElements}->{"identified-content"} = ZEROORMORE;
775             }
776              
777             #
778             # Syndication::NITF::correction -- Correction information
779             #
780             package Syndication::NITF::correction;
781             use Carp;
782             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
783              
784             sub _init {
785             my ($self, $node) = @_;
786             $self->{_attributes}->{info} = IMPLIED; # Message or instructions
787             $self->{_realname}->{idstring} = "id-string";
788             $self->{_attributes}->{"id-string"} = IMPLIED; # Document ID string
789             $self->{_attributes}->{regsrc} = IMPLIED; # Identifies source of correction
790             }
791              
792             #
793             # Syndication::NITF::evloc -- Event location (where an event took place, not where story was written)
794             #
795             package Syndication::NITF::evloc;
796             use Carp;
797             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
798              
799             sub _init {
800             my ($self, $node) = @_;
801             $self->{_realname}->{isocc} = "iso-cc";
802             $self->{_attributes}->{"iso-cc"} = IMPLIED; # Country code (ISO 3166)
803             $self->{_realname}->{stateprov} = "state-prov";
804             $self->{_attributes}->{"state-prov"} = IMPLIED; # State or province
805             $self->{_realname}->{countydist} = "county-dist";
806             $self->{_attributes}->{"county-dist"} = IMPLIED; # County or district
807             $self->{_attributes}->{city} = IMPLIED; # City or municipality
808             }
809              
810             #
811             # Syndication::NITF::doc-id -- Registered identification for document
812             #
813             package Syndication::NITF::docid;
814             use Carp;
815             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
816              
817             sub _init {
818             my ($self, $node) = @_;
819             $self->{_realname}->{idstring} = "id-string";
820             $self->{_attributes}->{"id-string"} = IMPLIED; # Document ID string
821             $self->{_attributes}->{regsrc} = IMPLIED; # Identifies source of correction
822             }
823              
824             #
825             # Syndication::NITF::del-list -- Delivery trail of delivery services
826             #
827             package Syndication::NITF::dellist;
828             use Carp;
829             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
830              
831             sub _init {
832             my ($self, $node) = @_;
833             $self->{_realname}->{fromsrc} = "from-src";
834             $self->{_multiElements}->{"from-src"} = IMPLIED; # Country code (ISO 3166)
835             }
836              
837             #
838             # Syndication::NITF::from-src -- Delivery service identifier
839             #
840             package Syndication::NITF::fromsrc;
841             use Carp;
842             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
843              
844             sub _init {
845             my ($self, $node) = @_;
846             $self->{_realname}->{srcname} = "src-name";
847             $self->{_attributes}->{"src-name"} = IMPLIED; # The entity moving the document
848             $self->{_realname}->{levelnumber} = "level-number";
849             $self->{_attributes}->{"level-number"} = IMPLIED; # position in the transmission path
850             }
851              
852             #
853             # Syndication::NITF::urgency -- News importance
854             #
855             package Syndication::NITF::urgency;
856             use Carp;
857             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
858              
859             sub _init {
860             my ($self, $node) = @_;
861             $self->{_realname}->{edurg} = "ed-urg";
862             $self->{_attributes}->{"ed-urg"} = IMPLIED; # 1=most, 5=normal, 8=least
863             }
864              
865             #
866             # Syndication::NITF::fixture -- Reference to a constant but regularly updated document
867             #
868             package Syndication::NITF::fixture;
869             use Carp;
870             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
871              
872             sub _init {
873             my ($self, $node) = @_;
874             $self->{_realname}->{fixid} = "fix-id";
875             $self->{_attributes}->{"fix-id"} = IMPLIED; # name of the fixture
876             }
877              
878             #
879             # Syndication::NITF::date.issue -- Date/time document was issued
880             #
881             package Syndication::NITF::dateissue;
882             use Carp;
883             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
884              
885             sub _init {
886             my ($self, $node) = @_;
887             $self->{_attributes}->{norm} = IMPLIED; # date normalised to ISO8601 format and UTC timezone
888             }
889              
890             #
891             # Syndication::NITF::date.release -- Date/time document can be released (in future => embargoed)
892             #
893             package Syndication::NITF::daterelease;
894             use Carp;
895             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
896              
897             sub _init {
898             my ($self, $node) = @_;
899             $self->{_attributes}->{norm} = IMPLIED; # date normalised to ISO8601 format and UTC timezone
900             }
901              
902             #
903             # Syndication::NITF::date.expire -- Date/time document has no validity (none == infinity)
904             #
905             package Syndication::NITF::dateexpire;
906             use Carp;
907             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
908              
909             sub _init {
910             my ($self, $node) = @_;
911             $self->{_attributes}->{norm} = IMPLIED; # date normalised to ISO8601 format and UTC timezone
912             }
913              
914             #
915             # Syndication::NITF::doc-scope -- Area where document may be of interest
916             #
917             package Syndication::NITF::docscope;
918             use Carp;
919             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
920              
921             sub _init {
922             my ($self, $node) = @_;
923             $self->{_attributes}->{scope} = IMPLIED; # "halfway between a Keyword and a Category"
924             }
925              
926             #
927             # Syndication::NITF::series -- Identifies article within a series
928             #
929             package Syndication::NITF::series;
930             use Carp;
931             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
932              
933             sub _init {
934             my ($self, $node) = @_;
935             $self->{_realname}->{seriesname} = "series.name";
936             $self->{_attributes}->{"series.name"} = IMPLIED; # "halfway between a Keyword and a Category"
937             }
938              
939             # this attribute has a default so we have to handle it separately
940             sub getseriespart { # number of this article in the series
941             my ($self) = @_;
942             my $attr = $self->{node}->getAttributeNode("series.part");
943             $self->{"seriespart"} = $attr ? $attr->getValue : "0";
944             }
945              
946             # this attribute has a default so we have to handle it separately
947             sub getseriestotalpart { # expected number of articles in series (0 = unknown/infinite)
948             my ($self) = @_;
949             my $attr = $self->{node}->getAttributeNode("series.totalpart");
950             $self->{"seriestotalpart"} = $attr ? $attr->getValue : "0";
951             }
952              
953             #
954             # Syndication::NITF::ed-msg -- Non-publishable editorial message
955             #
956             package Syndication::NITF::edmsg;
957             use Carp;
958             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
959              
960             sub _init {
961             my ($self, $node) = @_;
962             $self->{_realname}->{msgtype} = "msg-type";
963             $self->{_attributes}->{"msg-type"} = IMPLIED; # message type
964             $self->{_attributes}->{info} = IMPLIED; # actual message
965             }
966              
967             #
968             # Syndication::NITF::du-key -- Dynamic Use key groups and updates versions of stories
969             #
970             package Syndication::NITF::dukey;
971             use Carp;
972             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
973              
974             sub _init {
975             my ($self, $node) = @_;
976             $self->{_attributes}->{generation} = IMPLIED; # du-key generation level. Increments each send.
977             $self->{_attributes}->{part} = IMPLIED; # part within the du-key structure.
978             $self->{_attributes}->{version} = IMPLIED; # version of a particular use of the du-key.
979             $self->{_attributes}->{key} = IMPLIED; # actual key value.
980             }
981              
982             #
983             # Syndication::NITF::doc.copyright -- Copyright info for doc header.
984             #
985             package Syndication::NITF::doccopyright;
986             use Carp;
987             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
988              
989             sub _init {
990             my ($self, $node) = @_;
991             $self->{_attributes}->{year} = IMPLIED; # year of doc copyright
992             $self->{_attributes}->{holder} = IMPLIED; # copyright holder.
993             }
994              
995             #
996             # Syndication::NITF::doc.rights -- Rights info for use of the document.
997             #
998             package Syndication::NITF::docrights;
999             use Carp;
1000             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1001              
1002             sub _init {
1003             my ($self, $node) = @_;
1004             $self->{_attributes}->{owner} = IMPLIED; # owner of specified rights
1005             $self->{_attributes}->{startdate} = IMPLIED; # start end date/time for asserted rights
1006             $self->{_attributes}->{enddate} = IMPLIED; # end date/time for asserted rights
1007             $self->{_attributes}->{agent} = IMPLIED; # rights agent
1008             $self->{_attributes}->{geography} = IMPLIED; # geographic area where rights are asserted
1009             $self->{_realname}->{locationcode} = "location-code";
1010             $self->{_attributes}->{"location-code"} = IMPLIED; # Coded location from standard list
1011             $self->{_realname}->{codesource} = "code-source";
1012             $self->{_attributes}->{"code-source"} = IMPLIED; # Source of coded list (location?) information
1013             $self->{_attributes}->{type} = IMPLIED; # Kind of rights being asserted
1014             $self->{_attributes}->{limitations} = IMPLIED; # Limitations associated with document rights.
1015             }
1016              
1017             #
1018             # Syndication::NITF::key-list -- List of keywords
1019             #
1020             package Syndication::NITF::keylist;
1021             use Carp;
1022             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1023              
1024             sub _init {
1025             my ($self, $node) = @_;
1026             $self->{_multiElements}->{keyword} = ZEROORMORE;
1027             }
1028              
1029             #
1030             # Syndication::NITF::keyword -- keyword/phrase
1031             #
1032             package Syndication::NITF::keyword;
1033             use Carp;
1034             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1035              
1036             sub _init {
1037             my ($self, $node) = @_;
1038             $self->{_attributes}->{key} = IMPLIED; # actual keyword
1039             }
1040              
1041             #
1042             # Syndication::NITF::identified-content -- Content identifiers that can apply to the whole document.
1043             #
1044             package Syndication::NITF::identifiedcontent;
1045             use Carp;
1046             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1047              
1048             sub _init {
1049             my ($self, $node) = @_;
1050             $self->{_multiElements}->{person} = ZEROORMORE;
1051             $self->{_multiElements}->{org} = ZEROORMORE;
1052             $self->{_multiElements}->{location} = ZEROORMORE;
1053             $self->{_multiElements}->{event} = ZEROORMORE;
1054             $self->{_multiElements}->{function} = ZEROORMORE;
1055             $self->{_realname}->{objecttitle} = "object.title";
1056             $self->{_multiElements}->{"object.title"} = ZEROORMORE;
1057             $self->{_multiElements}->{virtloc} = ZEROORMORE;
1058             $self->{_multiElements}->{classifier} = ZEROORMORE;
1059             }
1060              
1061             #
1062             # Syndication::NITF::pubdata -- Metadata about this news object
1063             #
1064             package Syndication::NITF::pubdata;
1065             use Carp;
1066             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1067              
1068             sub _init {
1069             my ($self, $node) = @_;
1070             $self->{_attributes}->{type} = IMPLIED; # see below
1071             $self->{_realname}->{itemlength} = "item-length";
1072             $self->{_attributes}->{"item-length"} = IMPLIED; # length of item (see also unit-of-measure)
1073             $self->{_realname}->{unitofmeasure} = "unit-of-measure";
1074             $self->{_attributes}->{"unit-of-measure"} = IMPLIED; # see below
1075             $self->{_realname}->{datepublication} = "date.publication";
1076             $self->{_attributes}->{"date.publication"} = IMPLIED; # normalised date/time object was used
1077             $self->{_attributes}->{name} = IMPLIED; # title of publication
1078             $self->{_attributes}->{issn} = IMPLIED; # issn of publication containing news item.
1079             $self->{_attributes}->{volume} = IMPLIED; # volume of above publication in which item occurred
1080             $self->{_attributes}->{number} = IMPLIED; # publication number (possibly assoc with volume number)
1081             $self->{_attributes}->{issue} = IMPLIED; # name of issue ("June", "Summer", "Olympic Special" etc)
1082             $self->{_realname}->{editionname} = "edition.name";
1083             $self->{_attributes}->{"edition.name"} = IMPLIED; # name of edition ("Metro", "Late" etc)
1084             $self->{_realname}->{editionarea} = "edition.area";
1085             $self->{_attributes}->{"edition.area"} = IMPLIED; # Area / zone in which news object was distributed
1086             $self->{_realname}->{positionsection} = "position.section";
1087             $self->{_attributes}->{"position.section"} = IMPLIED; # section where news object appeared (eg Business)
1088             $self->{_realname}->{positionsequence} = "position.sequence";
1089             $self->{_attributes}->{"position.sequence"} = IMPLIED; # where news object appeared (eg page number)
1090             $self->{_realname}->{exref} = "ex-ref";
1091             $self->{_attributes}->{"ex-ref"} = IMPLIED; # external reference to published news object (as a URN)
1092             }
1093              
1094             # attribute is an enumeration so we must handle separately
1095             sub gettype { # transport medium
1096             my ($self) = @_;
1097             my @possiblevalues = qw(print audio video web appliance other);
1098             my $attr = $self->{node}->getAttributeNode("type");
1099             $self->{"type"} = $attr ? $attr->getValue : "";
1100             if ($self->{type} && grep !/$self->{type}/, "@possiblevalues") {
1101             croak "Illegal value ".$self->{type}." for attribute type";
1102             }
1103             return $self->{type};
1104             }
1105              
1106             # attribute is an enumeration so we must handle separately
1107             sub getunitofmeasure { # measure associated with item-length
1108             my ($self) = @_;
1109             my @possiblevalues = qw(word character byte inch pica cm hour minute second other);
1110             my $attr = $self->{node}->getAttributeNode("unit-of-measure");
1111             $self->{"unit-of-measure"} = $attr ? $attr->getValue : "";
1112             if ($self->{"unit-of-measure"} && grep !/$self->{"unit-of-measure"}/, "@possiblevalues") {
1113             croak "Illegal value ".$self->{"unit-of-measure"}." for attribute unit-of-measure";
1114             }
1115             return $self->{"unit-of-measure"};
1116             }
1117              
1118             #
1119             # Syndication::NITF::revision-history -- audit trail of document
1120             #
1121             package Syndication::NITF::revisionhistory;
1122             use Carp;
1123             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1124              
1125             sub _init {
1126             my ($self, $node) = @_;
1127             $self->{_attributes}->{name} = IMPLIED; # person who made the revision
1128             $self->{_attributes}->{function} = IMPLIED; # function of named person
1129             $self->{_attributes}->{norm} = IMPLIED; # normalised date/time of revision
1130             $self->{_attributes}->{comment} = IMPLIED; # reason for the revision
1131             }
1132              
1133             # attribute is an enumeration so we must handle separately
1134             sub getfunction { # function of person named in "name"
1135             my ($self) = @_;
1136             my @possiblevalues = qw( writer-author editor producer archivist videographer graphic-artist photographer statistician other);
1137             my $attr = $self->{"function"} = $self->{node}->getAttributeNode("function")->getValue;
1138             $self->{"function"} = $attr ? $attr->getValue : "";
1139             if ($self->{function} && grep !/$self->{function}/, "@possiblevalues") {
1140             croak "Illegal value ".$self->{function}." for attribute function";
1141             }
1142             return $self->{function};
1143             }
1144              
1145             ### END OF "head" ELEMENTS ###
1146            
1147             #
1148             # Syndication::NITF::body -- body of story
1149             #
1150             package Syndication::NITF::body;
1151             use Carp;
1152             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1153              
1154             sub _init {
1155             my ($self, $node) = @_;
1156             $self->{_realname}->{bodyhead} = "body.head";
1157             $self->{_singleElements}->{"body.head"} = OPTIONAL;
1158             $self->{_realname}->{bodycontent} = "body.content";
1159             $self->{_multiElements}->{"body.content"} = ZEROORMORE;
1160             $self->{_realname}->{bodyend} = "body.end";
1161             $self->{_singleElements}->{"body.end"} = OPTIONAL;
1162             }
1163              
1164             #
1165             # Syndication::NITF::body.head -- metadata to be displayed to the reader
1166             #
1167             package Syndication::NITF::bodyhead;
1168             use Carp;
1169             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1170              
1171             sub _init {
1172             my ($self, $node) = @_;
1173             $self->{_singleElements}->{hedline} = OPTIONAL; # this is not a typo!
1174             $self->{_multiElements}->{note} = ZEROORMORE;
1175             $self->{_singleElements}->{rights} = OPTIONAL;
1176             $self->{_multiElements}->{byline} = ZEROORMORE;
1177             $self->{_singleElements}->{distributor} = OPTIONAL;
1178             $self->{_multiElements}->{dateline} = ZEROORMORE;
1179             $self->{_singleElements}->{abstract} = OPTIONAL;
1180             $self->{_singleElements}->{series} = OPTIONAL;
1181             }
1182              
1183             #
1184             # Syndication::NITF::hedline [sic] -- encapsulates headline of story
1185             #
1186             package Syndication::NITF::hedline;
1187             use Carp;
1188             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1189              
1190             sub _init {
1191             my ($self, $node) = @_;
1192             $self->{_singleElements}->{hl1} = REQUIRED;
1193             $self->{_multiElements}->{hl2} = ZEROORMORE;
1194             }
1195              
1196             #
1197             # Syndication::NITF::hl1 -- main headline of story
1198             #
1199             package Syndication::NITF::hl1;
1200             use Carp;
1201             @ISA = qw( Syndication::NITF::EnrichedTextNode Syndication::NITF::CommonAttributesNode );
1202              
1203             sub _init {
1204             my ($self, $node) = @_;
1205             }
1206              
1207             #
1208             # Syndication::NITF::hl2 -- "subordinate" headline of story
1209             #
1210             package Syndication::NITF::hl2;
1211             use Carp;
1212             @ISA = qw( Syndication::NITF::EnrichedTextNode Syndication::NITF::CommonAttributesNode );
1213              
1214             sub _init {
1215             my ($self, $node) = @_;
1216             }
1217              
1218             #
1219             # Syndication::NITF::note -- document cautionary note
1220             #
1221             package Syndication::NITF::note;
1222             use Carp;
1223             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1224              
1225             sub _init {
1226             my ($self, $node) = @_;
1227             $self->{_realname}->{bodycontent} = "body.content";
1228             $self->{_multiElements}->{"body.content"} = ONEORMORE;
1229             $self->{_attributes}->{noteclass} = IMPLIED; # see below
1230             $self->{_attributes}->{type} = IMPLIED; # see below
1231             }
1232              
1233             # attribute is an enumeration so we must handle separately
1234             sub getnoteclass { # category of note
1235             my ($self) = @_;
1236             my @possiblevalues = qw( cpyrt end hd editorsnote trademk undef );
1237             my $attr = $self->{node}->getAttributeNode("noteclass");
1238             return "" unless $attr;
1239             $self->{"noteclass"} = $attr->getValue;
1240             if ($self->{noteclass} && grep !/$self->{noteclass}/, "@possiblevalues") {
1241             croak "Illegal value ".$self->{noteclass}." for attribute noteclass";
1242             }
1243             return $self->{"noteclass"};
1244             }
1245              
1246             # attribute is an enumeration so we must handle separately
1247             sub gettype { # one of standards, publishable advisory, non-publishable advisory
1248             my ($self) = @_;
1249             my @possiblevalues = qw( std pa npa );
1250             my $attr = $self->{node}->getAttributeNode("type");
1251             return "" unless $attr;
1252             $self->{"type"} = $attr->getValue;
1253             if ($self->{type} && grep !/$self->{type}/, "@possiblevalues") {
1254             croak "Illegal value ".$self->{type}." for attribute type";
1255             }
1256             return $self->{"type"};
1257             }
1258              
1259             #
1260             # Syndication::NITF::rights -- information on rights holder
1261             #
1262             package Syndication::NITF::rights;
1263             use Carp;
1264             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1265              
1266             sub _init {
1267             my ($self, $node) = @_;
1268             $self->{_realname}->{rightsowner} = "rights.owner";
1269             $self->{_multiElements}->{"rights.owner"} = ZEROORMORE;
1270             $self->{_realname}->{rightsstartdate} = "rights.startdate";
1271             $self->{_multiElements}->{"rights.startdate"} = ZEROORMORE;
1272             $self->{_realname}->{rightsenddate} = "rights.enddate";
1273             $self->{_multiElements}->{"rights.enddate"} = ZEROORMORE;
1274             $self->{_realname}->{rightsagent} = "rights.agent";
1275             $self->{_multiElements}->{"rights.agent"} = ZEROORMORE;
1276             $self->{_realname}->{rightsgeography} = "rights.geography";
1277             $self->{_multiElements}->{"rights.geography"} = ZEROORMORE;
1278             $self->{_realname}->{rightstype} = "rights.type";
1279             $self->{_multiElements}->{"rights.type"} = ZEROORMORE;
1280             $self->{_realname}->{rightslimitations} = "rights.limitations";
1281             $self->{_multiElements}->{"rights.limitations"} = ZEROORMORE;
1282             $self->{_hasText} = 1;
1283             }
1284              
1285             #
1286             # Syndication::NITF::rights.owner -- owner of rights
1287             #
1288             package Syndication::NITF::rightsowner;
1289             use Carp;
1290             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1291              
1292             sub _init {
1293             my ($self, $node) = @_;
1294             $self->{_attributes}->{contact} = IMPLIED; # contact information for the owner
1295             $self->{_hasText} = 1;
1296             }
1297              
1298             #
1299             # Syndication::NITF::rights.startdate -- date that rights start
1300             #
1301             package Syndication::NITF::rightsstartdate;
1302             use Carp;
1303             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1304              
1305             sub _init {
1306             my ($self, $node) = @_;
1307             $self->{_attributes}->{norm} = IMPLIED; # normalised date
1308             $self->{_hasText} = 1;
1309             }
1310              
1311             #
1312             # Syndication::NITF::rights.enddate -- date that rights finish
1313             #
1314             package Syndication::NITF::rightsenddate;
1315             use Carp;
1316             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1317              
1318             sub _init {
1319             my ($self, $node) = @_;
1320             $self->{_attributes}->{norm} = IMPLIED; # normalised date
1321             $self->{_hasText} = 1;
1322             }
1323              
1324             #
1325             # Syndication::NITF::rights.agent -- agent that holds rights
1326             #
1327             package Syndication::NITF::rightsagent;
1328             use Carp;
1329             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1330              
1331             sub _init {
1332             my ($self, $node) = @_;
1333             $self->{_attributes}->{contact} = IMPLIED; # contact info for agent
1334             $self->{_hasText} = 1;
1335             }
1336              
1337             #
1338             # Syndication::NITF::rights.geography -- area to which rights apply
1339             #
1340             package Syndication::NITF::rightsgeography;
1341             use Carp;
1342             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1343              
1344             sub _init {
1345             my ($self, $node) = @_;
1346             $self->{_realname}->{locationcode} = "location-code";
1347             $self->{_attributes}->{"location-code"} = IMPLIED; # coded location from standard list
1348             $self->{_realname}->{codesource} = "code-source";
1349             $self->{_attributes}->{"code-source"} = IMPLIED; # source for the location code (URN?)
1350             $self->{_hasText} = 1;
1351             }
1352              
1353             #
1354             # Syndication::NITF::rights.type -- type of rights claimed
1355             #
1356             package Syndication::NITF::rightstype;
1357             use Carp;
1358             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1359              
1360             sub _init {
1361             my ($self, $node) = @_;
1362             $self->{_hasText} = 1;
1363             }
1364              
1365             #
1366             # Syndication::NITF::rights.limitations -- type of rights claimed
1367             #
1368             package Syndication::NITF::rightslimitations;
1369             use Carp;
1370             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1371              
1372             sub _init {
1373             my ($self, $node) = @_;
1374             $self->{_hasText} = 1;
1375             }
1376              
1377             #
1378             # Syndication::NITF::byline -- container for byline information
1379             #
1380             package Syndication::NITF::byline;
1381             use Carp;
1382             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1383              
1384             sub _init {
1385             my ($self, $node) = @_;
1386             $self->{_multiElements}->{person} = ZEROORMORE;
1387             $self->{_multiElements}->{byttl} = ZEROORMORE;
1388             $self->{_multiElements}->{location} = ZEROORMORE;
1389             $self->{_multiElements}->{virtloc} = ZEROORMORE;
1390             $self->{_hasText} = 1;
1391             }
1392              
1393             #
1394             # Syndication::NITF::byttl -- Byline title, perhaps with organisation
1395             #
1396             package Syndication::NITF::byttl;
1397             use Carp;
1398             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1399              
1400             sub _init {
1401             my ($self, $node) = @_;
1402             $self->{_multiElements}->{org} = ZEROORMORE;
1403             $self->{_hasText} = 1;
1404             }
1405              
1406             #
1407             # Syndication::NITF::distributor -- Information distributor
1408             #
1409             package Syndication::NITF::distributor;
1410             use Carp;
1411             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1412              
1413             sub _init {
1414             my ($self, $node) = @_;
1415             $self->{_multiElements}->{org} = ZEROORMORE;
1416             $self->{_hasText} = 1;
1417             }
1418              
1419             #
1420             # Syndication::NITF::dateline -- Container for dateline information
1421             #
1422             package Syndication::NITF::dateline;
1423             use Carp;
1424             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1425              
1426             sub _init {
1427             my ($self, $node) = @_;
1428             $self->{_multiElements}->{location} = ZEROORMORE;
1429             $self->{_realname}->{storydate} = "story.date";
1430             $self->{_multiElements}->{"story.date"} = ZEROORMORE;
1431             $self->{_hasText} = 1;
1432             }
1433              
1434             #
1435             # Syndication::NITF::story.date -- Date of story
1436             #
1437             package Syndication::NITF::storydate;
1438             use Carp;
1439             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1440              
1441             sub _init {
1442             my ($self, $node) = @_;
1443             $self->{_attributes}->{norm} = IMPLIED; # normalised date and time
1444             $self->{_hasText} = 1;
1445             }
1446              
1447             #
1448             # Syndication::NITF::abstract -- Story abstact/synopsis
1449             #
1450             package Syndication::NITF::abstract;
1451             use Carp;
1452             @ISA = qw( Syndication::NITF::GlobalAttributesNode Syndication::NITF::BlockContentNode );
1453              
1454             sub _init {
1455             my ($self, $node) = @_;
1456             }
1457              
1458             #
1459             # Syndication::NITF::copyrite [sic] -- Container for copyright information
1460             #
1461             package Syndication::NITF::copyrite;
1462             use Carp;
1463             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1464              
1465             sub _init {
1466             my ($self, $node) = @_;
1467             $self->{_realname}->{copyriteyear} = "copyrite.year";
1468             $self->{_multiElements}->{"copyrite.year"} = ZEROORMORE;
1469             $self->{_realname}->{copyriteholder} = "copyrite.holder";
1470             $self->{_multiElements}->{"copyrite.holder"} = ZEROORMORE;
1471             $self->{_hasText} = 1;
1472             }
1473              
1474             #
1475             # Syndication::NITF::copyrite.year [sic] -- Year of copyright
1476             #
1477             package Syndication::NITF::copyriteyear;
1478             use Carp;
1479             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1480              
1481             sub _init {
1482             my ($self, $node) = @_;
1483             $self->{_hasText} = 1;
1484             }
1485              
1486             #
1487             # Syndication::NITF::copyrite.holder [sic] -- Year of copyright
1488             #
1489             package Syndication::NITF::copyriteholder;
1490             use Carp;
1491             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1492              
1493             sub _init {
1494             my ($self, $node) = @_;
1495             $self->{_hasText} = 1;
1496             }
1497              
1498             #
1499             # Syndication::NITF::body.content -- Actual body content
1500             #
1501             package Syndication::NITF::bodycontent;
1502             use Carp;
1503             @ISA = qw( Syndication::NITF::GlobalAttributesNode Syndication::NITF::BlockContentNode );
1504              
1505             sub _init {
1506             my ($self, $node) = @_;
1507             $self->{_multiElements}->{block} = ZEROORMORE;
1508             }
1509              
1510             #
1511             # Syndication::NITF::block -- "A group of related containers"
1512             #
1513             package Syndication::NITF::block;
1514             use Carp;
1515             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::BlockContentNode );
1516              
1517             sub _init {
1518             my ($self, $node) = @_;
1519             # block.start entity (didn't make into a Node as it's only used once)
1520             $self->{_singleElements}->{tobject} = OPTIONAL;
1521             $self->{_realname}->{keylist} = "key-list";
1522             $self->{_singleElements}->{"key-list"} = OPTIONAL;
1523             $self->{_multiElements}->{classifier} = ZEROORMORE;
1524             $self->{_singleElements}->{byline} = OPTIONAL;
1525             $self->{_singleElements}->{dateline} = OPTIONAL;
1526             $self->{_singleElements}->{copyrite} = OPTIONAL;
1527             $self->{_singleElements}->{abstract} = OPTIONAL;
1528             $self->{_multiElements}->{block} = ZEROORMORE;
1529             # block.content entity included with BlockContentNode
1530             # block.end entity
1531             $self->{_singleElements}->{datasource} = OPTIONAL;
1532             }
1533              
1534             #
1535             # Syndication::NITF::p -- Paragraph
1536             #
1537             package Syndication::NITF::p;
1538             use Carp;
1539             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
1540              
1541             sub _init {
1542             my ($self, $node) = @_;
1543             $self->{_attributes}->{lede} = IMPLIED; # [sic] indicates "lead" paragraph
1544             $self->{_attributes}->{summary} = IMPLIED;
1545             $self->{_realname}->{optionaltext} = "optional-text";
1546             $self->{_attributes}->{"optional-text"} = IMPLIED;
1547             }
1548              
1549             # really need a "boolean" type, but...
1550             sub getlede {
1551             my ($self) = @_;
1552             my $attr = $self->{node}->getAttributeNode("lede");
1553             $self->{"lede"} = $attr ? $attr->getValue : 'no';
1554             }
1555              
1556             sub getsummary {
1557             my ($self) = @_;
1558             my $attr = $self->{node}->getAttributeNode("summary");
1559             $self->{"summary"} = $attr ? $attr->getValue : 'no';
1560             }
1561              
1562             sub getoptionaltext {
1563             my ($self) = @_;
1564             my $attr = $self->{node}->getAttributeNode("optional-text");
1565             $self->{"optional-text"} = $attr ? $attr->getValue : 'no';
1566             }
1567              
1568             #
1569             # Syndication::NITF::table -- table
1570             #
1571             package Syndication::NITF::table;
1572             use Carp;
1573             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1574              
1575             sub _init {
1576             my ($self, $node) = @_;
1577             $self->{_singleElements}->{caption} = OPTIONAL;
1578             $self->{_multiElements}->{col} = ZEROORMORE;
1579             $self->{_multiElements}->{colgroup} = ZEROORMORE;
1580             $self->{_singleElements}->{thead} = OPTIONAL;
1581             $self->{_singleElements}->{tfoot} = OPTIONAL;
1582             $self->{_multiElements}->{tbody} = ZEROORMORE;
1583             $self->{_multiElements}->{tr} = ZEROORMORE;
1584             $self->{_attributes}->{tabletype} = IMPLIED; # holds style information
1585             $self->{_attributes}->{align} = IMPLIED; # left | center | right
1586             $self->{_attributes}->{width} = IMPLIED; # width
1587             $self->{_attributes}->{cols} = IMPLIED; # number of columns
1588             $self->{_attributes}->{border} = IMPLIED; # style information
1589             $self->{_attributes}->{frame} = IMPLIED; # void | above | below | hsides | lhs | rhs | vsides | box | border
1590             $self->{_attributes}->{rules} = IMPLIED; # none | basic | rows | cols | all
1591             $self->{_attributes}->{cellspacing} = IMPLIED; # no of pixels between cells
1592             $self->{_attributes}->{cellpadding} = IMPLIED; # no of pixels between cell border and contents
1593             }
1594              
1595             #
1596             # Syndication::NITF::media -- Year of copyright
1597             #
1598             package Syndication::NITF::media;
1599             use Carp;
1600             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1601              
1602             sub _init {
1603             my ($self, $node) = @_;
1604             $self->{_realname}->{mediametadata} = "media-metadata";
1605             $self->{_multiElements}->{"media-metadata"} = ZEROORMORE;
1606             $self->{_realname}->{mediareference} = "media-reference";
1607             $self->{_multiElements}->{"media-reference"} = ONEORMORE;
1608             $self->{_realname}->{mediaobject} = "media-object";
1609             $self->{_multiElements}->{"media-object"} = ZEROORMORE;
1610             $self->{_realname}->{mediacaption} = "media-caption";
1611             $self->{_multiElements}->{"media-caption"} = ZEROORMORE;
1612             $self->{_realname}->{mediaproducer} = "media-producer";
1613             $self->{_singleElements}->{"media-producer"} = OPTIONAL;
1614             $self->{_realname}->{mediatype} = "media-type";
1615             $self->{_attributes}->{"media-type"} = IMPLIED; # see below
1616             }
1617              
1618             # attribute is an enumeration so we must handle separately
1619             sub getmediatype {
1620             my ($self) = @_;
1621             my @possiblevalues = qw( text audio image video data application other );
1622             my $attr = $self->{node}->getAttributeNode("media-type");
1623             $self->{"media-type"} = $attr ? $attr->getValue : "";
1624             if ($self->{"media-type"} && (grep !/$self->{"media-type"}/, "@possiblevalues")) {
1625             croak "Illegal value ".$self->{"media-type"}." for attribute media-type";
1626             }
1627             return $self->{"media-type"};
1628             }
1629              
1630             #
1631             # Syndication::NITF::media-reference -- Media reference
1632             #
1633             package Syndication::NITF::mediareference;
1634             use Carp;
1635             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1636              
1637             sub _init {
1638             my ($self, $node) = @_;
1639             $self->{_hasText} = 1;
1640             $self->{_attributes}->{source} = IMPLIED; # URL of external media file
1641             $self->{_attributes}->{name} = IMPLIED; # Alternate name or description
1642             $self->{_realname}->{mimetype} = "mime-type";
1643             $self->{_attributes}->{"mime-type"} = REQUIRED; # Mime type of external file
1644             $self->{_attributes}->{coding} = IMPLIED; # How info is coded
1645             $self->{_attributes}->{time} = IMPLIED; # length of media
1646             $self->{_realname}->{timeunitofmeasure} = "time-unit-of-measure";
1647             $self->{_attributes}->{"time-unit-of-measure"} = IMPLIED; # unit of length
1648             $self->{_attributes}->{outcue} = IMPLIED; # spoken information that ends an audio clip
1649             $self->{_realname}->{sourcecredit} = "source-credit";
1650             $self->{_attributes}->{"source-credit"} = IMPLIED; # source-credit
1651             $self->{_attributes}->{copyright} = IMPLIED; # copyright owner
1652             $self->{_realname}->{alternatetext} = "alternate-text";
1653             $self->{_attributes}->{"alternate-text"} = IMPLIED; # Plain-text substitute text
1654             $self->{_attributes}->{height} = IMPLIED; # height of media object
1655             $self->{_attributes}->{width} = IMPLIED; # width of media object
1656             $self->{_attributes}->{units} = IMPLIED; # units of height and width (default pixels)
1657             $self->{_attributes}->{imagemap} = IMPLIED; # whether object has an imagemap
1658             $self->{_attributes}->{noflow} = IMPLIED; # can informatino flow around figure
1659             }
1660              
1661             sub getunits {
1662             my ($self) = @_;
1663             my $attr = $self->{node}->getAttributeNode("units");
1664             $self->{"units"} = $attr ? $attr->getValue : 'pixels';
1665             }
1666              
1667             sub getnoflow {
1668             my ($self) = @_;
1669             my $attr = $self->{node}->getAttributeNode("noflow");
1670             $self->{"noflow"} = $attr ? $attr->getValue : 'no';
1671             }
1672              
1673             #
1674             # Syndication::NITF::media-metadata -- Media reference
1675             #
1676             package Syndication::NITF::mediametadata;
1677             use Carp;
1678             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1679              
1680             sub _init {
1681             my ($self, $node) = @_;
1682             $self->{_attributes}->{name} = REQUIRED; # name of meta item
1683             $self->{_attributes}->{value} = IMPLIED; # value of meta item
1684             }
1685              
1686             #
1687             # Syndication::NITF::media-object -- Media object (eg clip) may be encoded binary.
1688             #
1689             package Syndication::NITF::mediaobject;
1690             use Carp;
1691             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1692              
1693             sub _init {
1694             my ($self, $node) = @_;
1695             $self->{_hasText} = 1;
1696             $self->{_attributes}->{encoding} = REQUIRED; # format of encoded data
1697             }
1698              
1699             #
1700             # Syndication::NITF::media-caption -- (Publishable) Text describing media
1701             #
1702             package Syndication::NITF::mediacaption;
1703             use Carp;
1704             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode Syndication::NITF::BlockContentNode );
1705              
1706             sub _init {
1707             my ($self, $node) = @_;
1708             }
1709              
1710             #
1711             # Syndication::NITF::media-producer -- Byline of media producer
1712             #
1713             package Syndication::NITF::mediaproducer;
1714             use Carp;
1715             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
1716              
1717             sub _init {
1718             my ($self, $node) = @_;
1719             }
1720              
1721             #
1722             # Syndication::NITF::ol -- HTML-style ordered list
1723             #
1724             package Syndication::NITF::ol;
1725             use Carp;
1726             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1727              
1728             sub _init {
1729             my ($self, $node) = @_;
1730             $self->{_multiElements}->{li} = ONEORMORE; # list elements
1731             $self->{_attributes}->{seqnum} = IMPLIED; # sequence number
1732             }
1733              
1734             #
1735             # Syndication::NITF::ul -- HTML-style unordered list
1736             #
1737             package Syndication::NITF::ul;
1738             use Carp;
1739             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1740              
1741             sub _init {
1742             my ($self, $node) = @_;
1743             $self->{_multiElements}->{li} = ONEORMORE; # list elements
1744             }
1745              
1746             #
1747             # Syndication::NITF::li -- list item
1748             #
1749             package Syndication::NITF::li;
1750             use Carp;
1751             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode Syndication::NITF::BlockContentNode );
1752              
1753             sub _init {
1754             my ($self, $node) = @_;
1755             }
1756              
1757             #
1758             # Syndication::NITF::dl -- definition list
1759             #
1760             package Syndication::NITF::dl;
1761             use Carp;
1762             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1763              
1764             sub _init {
1765             my ($self, $node) = @_;
1766             $self->{_multiElements}->{dt} = ZEROORMORE; # definition term
1767             $self->{_multiElements}->{dd} = ZEROORMORE; # definition data
1768             }
1769              
1770             #
1771             # Syndication::NITF::dt -- definition term
1772             #
1773             package Syndication::NITF::dt;
1774             use Carp;
1775             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
1776              
1777             sub _init {
1778             my ($self, $node) = @_;
1779             }
1780              
1781             #
1782             # Syndication::NITF::dd -- definition data
1783             #
1784             package Syndication::NITF::dd;
1785             use Carp;
1786             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1787              
1788             sub _init {
1789             my ($self, $node) = @_;
1790             $self->{_multiElements}->{block} = ZEROORMORE; # content
1791             }
1792              
1793             #
1794             # Syndication::NITF::bq -- blockquote
1795             #
1796             package Syndication::NITF::bq;
1797             use Carp;
1798             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1799              
1800             sub _init {
1801             my ($self, $node) = @_;
1802             $self->{_multiElements}->{block} = ZEROORMORE; #
1803             $self->{_multiElements}->{credit} = ZEROORMORE; #
1804             $self->{_attributes}->{nowrap} = IMPLIED; # content
1805             $self->{_realname}->{quotesource} = "quote-source";
1806             $self->{_attributes}->{"quote-source"} = IMPLIED; # content
1807             }
1808              
1809             # hmm this is actually supposed to be "if this attr exists, the value must be "nowrap"
1810             # which isn't quite what this code does
1811             sub getnowrap {
1812             my ($self) = @_;
1813             my $attr = $self->{node}->getAttributeNode("nowrap");
1814             $self->{"nowrap"} = $attr ? $attr->getValue : 'nowrap';
1815             }
1816              
1817             #
1818             # Syndication::NITF::credit -- source of a block quote
1819             #
1820             package Syndication::NITF::credit;
1821             use Carp;
1822             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
1823              
1824             sub _init {
1825             my ($self, $node) = @_;
1826             }
1827              
1828             #
1829             # Syndication::NITF::fn -- footnote
1830             #
1831             package Syndication::NITF::fn;
1832             use Carp;
1833             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::BodyContentNode );
1834              
1835             sub _init {
1836             my ($self, $node) = @_;
1837             }
1838              
1839             #
1840             # Syndication::NITF::pre -- HTML-style preformatted text
1841             #
1842             package Syndication::NITF::pre;
1843             use Carp;
1844             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1845              
1846             sub _init {
1847             my ($self, $node) = @_;
1848             $self->{_hasText} = 1;
1849             }
1850              
1851             #
1852             # Syndication::NITF::hr -- HTML-style horizontal rule
1853             #
1854             package Syndication::NITF::hr;
1855             use Carp;
1856             @ISA = qw( Syndication::NITF::CommonAttributesNode );
1857              
1858             sub _init {
1859             my ($self, $node) = @_;
1860             }
1861              
1862             #
1863             # Syndication::NITF::datasource -- Source of info in a block element
1864             #
1865             package Syndication::NITF::datasource;
1866             use Carp;
1867             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
1868              
1869             sub _init {
1870             my ($self, $node) = @_;
1871             $self->{_hasText} = 1;
1872             }
1873              
1874             ### table elements ###
1875              
1876             # nodes for table elements, used several times
1877              
1878             #
1879             # Syndication::NITF::CellAlignNode -- attributes for cell alignment
1880             #
1881             package Syndication::NITF::CellAlignNode;
1882             use Carp;
1883             @ISA = qw( Syndication::NITF::Node );
1884              
1885             sub _init {
1886             my ($self, $node) = @_;
1887             $self->{_attributes}->{align} = IMPLIED;
1888             $self->{_attributes}->{char} = IMPLIED;
1889             $self->{_attributes}->{charoff} = IMPLIED;
1890             }
1891              
1892             # attribute is an enumeration so we must handle separately
1893             sub getalign {
1894             my ($self) = @_;
1895             my @possiblevalues = qw( left center right justify char );
1896             my $attr = $self->{node}->getAttributeNode("align");
1897             $self->{"align"} = $attr ? $attr->getValue : "";
1898             if ($self->{align} && grep !/$self->{align}/, "@possiblevalues") {
1899             croak "Illegal value ".$self->{align}." for attribute align";
1900             }
1901             return $self->{"align"};
1902             }
1903              
1904             #
1905             # Syndication::NITF::CellVAlignNode -- attributes for vertical cell alignment
1906             #
1907             package Syndication::NITF::CellVAlignNode;
1908             use Carp;
1909             @ISA = qw( Syndication::NITF::Node );
1910              
1911             sub _init {
1912             my ($self, $node) = @_;
1913             $self->{_attributes}->{valign} = IMPLIED;
1914             }
1915              
1916             # attribute is an enumeration so we must handle separately
1917             sub getvalign {
1918             my ($self) = @_;
1919             my @possiblevalues = qw( top middle bottom baseline );
1920             my $attr = $self->{node}->getAttributeNode("valign");
1921             $self->{"valign"} = $attr ? $attr->getValue : "";
1922             if ($self->{valign} && grep !/$self->{valign}/, "@possiblevalues") {
1923             croak "Illegal value ".$self->{valign}." for attribute valign";
1924             }
1925             return $self->{"valign"};
1926             }
1927              
1928             #
1929             # Syndication::NITF::caption -- Text for the caption of a table
1930             #
1931             package Syndication::NITF::caption;
1932             use Carp;
1933             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode Syndication::NITF::BlockContentNode );
1934              
1935             sub _init {
1936             my ($self, $node) = @_;
1937             $self->{_attributes}->{align} = IMPLIED; # alignment of caption in table
1938             }
1939              
1940             # attribute is an enumeration so we must handle separately
1941             sub getalign {
1942             my ($self) = @_;
1943             my @possiblevalues = qw( top bottom left right );
1944             my $attr = $self->{node}->getAttributeNode("align");
1945             $self->{"align"} = $attr ? $attr->getValue : "";
1946             if ($self->{align} && grep !/$self->{align}/, "@possiblevalues") {
1947             croak "Illegal value ".$self->{align}." for attribute align";
1948             }
1949             return $self->{"align"};
1950             }
1951              
1952             #
1953             # Syndication::NITF::col -- Formatting for a table column
1954             #
1955             package Syndication::NITF::col;
1956             use Carp;
1957             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
1958              
1959             sub _init {
1960             my ($self, $node) = @_;
1961             $self->{_attributes}->{span} = IMPLIED; # how many cells wide this column should be
1962             $self->{_attributes}->{width} = IMPLIED; # width of column in pixels
1963             }
1964              
1965             # default value of 1
1966             sub getspan {
1967             my ($self) = @_;
1968             my $attr = $self->{span}->getAttributeNode("span");
1969             $self->{"span"} = $attr ? $attr->getValue : '1';
1970             }
1971              
1972             #
1973             # Syndication::NITF::colgroup -- Column group
1974             #
1975             package Syndication::NITF::colgroup;
1976             use Carp;
1977             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
1978              
1979             sub _init {
1980             my ($self, $node) = @_;
1981             $self->{_multiElements}->{col} = ONEORMORE;
1982             }
1983              
1984             #
1985             # Syndication::NITF::thead -- Table heading
1986             #
1987             package Syndication::NITF::thead;
1988             use Carp;
1989             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
1990              
1991             sub _init {
1992             my ($self, $node) = @_;
1993             $self->{_multiElements}->{tr} = ONEORMORE;
1994             }
1995              
1996             #
1997             # Syndication::NITF::tbody -- Table body
1998             #
1999             package Syndication::NITF::tbody;
2000             use Carp;
2001             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
2002              
2003             sub _init {
2004             my ($self, $node) = @_;
2005             $self->{_multiElements}->{tr} = ONEORMORE;
2006             }
2007              
2008             #
2009             # Syndication::NITF::tfoot -- Table footer
2010             #
2011             package Syndication::NITF::tfoot;
2012             use Carp;
2013             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
2014              
2015             sub _init {
2016             my ($self, $node) = @_;
2017             $self->{_multiElements}->{tr} = ONEORMORE;
2018             }
2019              
2020             #
2021             # Syndication::NITF::tr -- Table row
2022             #
2023             package Syndication::NITF::tr;
2024             use Carp;
2025             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
2026              
2027             sub _init {
2028             my ($self, $node) = @_;
2029             $self->{_multiElements}->{th} = ZEROORMORE;
2030             $self->{_multiElements}->{td} = ZEROORMORE;
2031             }
2032              
2033             #
2034             # Syndication::NITF::th -- Table header cell
2035             #
2036             package Syndication::NITF::th;
2037             use Carp;
2038             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode Syndication::NITF::BlockContentNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
2039              
2040             sub _init {
2041             my ($self, $node) = @_;
2042             $self->{_attributes}->{axis} = IMPLIED; # HTML formatting attribute (???)
2043             $self->{_attributes}->{axes} = IMPLIED; # HTML formatting attribute (???)
2044             $self->{_attributes}->{nowrap} = IMPLIED; # Directive not to wrap text in cell
2045             $self->{_attributes}->{rowspan} = IMPLIED; # Number of horizontal rows to span
2046             $self->{_attributes}->{colspan} = IMPLIED; # Number of vertical columns to span
2047             }
2048              
2049             # the rule here is "if this attr exists, the value must be "nowrap"
2050             sub getnowrap {
2051             my ($self) = @_;
2052             my $attr = $self->{node}->getAttributeNode("nowrap");
2053             croak "Illegal value for attribute nowrap" if ($attr && $attr->getValue ne "nowrap");
2054             $self->{"nowrap"} = $attr ? $attr->getValue : undef;
2055             }
2056              
2057             # handle default value
2058             sub getrowspan {
2059             my ($self) = @_;
2060             my $attr = $self->{node}->getAttributeNode("rowspan");
2061             $self->{"rowspan"} = $attr ? $attr->getValue : "1";
2062             }
2063              
2064             # handle default value
2065             sub getcolspan {
2066             my ($self) = @_;
2067             my $attr = $self->{node}->getAttributeNode("colspan");
2068             $self->{"colspan"} = $attr ? $attr->getValue : "1";
2069             }
2070              
2071             #
2072             # Syndication::NITF::td -- Table data cell
2073             #
2074             package Syndication::NITF::td;
2075             use Carp;
2076             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode Syndication::NITF::BlockContentNode Syndication::NITF::CellAlignNode Syndication::NITF::CellVAlignNode );
2077              
2078             sub _init {
2079             my ($self, $node) = @_;
2080             $self->{_attributes}->{axis} = IMPLIED; # HTML formatting attribute (???)
2081             $self->{_attributes}->{axes} = IMPLIED; # HTML formatting attribute (???)
2082             $self->{_attributes}->{nowrap} = IMPLIED; # Directive not to wrap text in cell
2083             $self->{_attributes}->{rowspan} = IMPLIED; # Number of horizontal rows to span
2084             $self->{_attributes}->{colspan} = IMPLIED; # Number of vertical columns to span
2085             }
2086              
2087             # the rule here is "if this attr exists, the value must be "nowrap"
2088             sub getnowrap {
2089             my ($self) = @_;
2090             my $attr = $self->{node}->getAttributeNode("nowrap");
2091             croak "Illegal value for attribute nowrap" if ($attr && $attr->getValue ne "nowrap");
2092             $self->{"nowrap"} = $attr ? $attr->getValue : undef;
2093             }
2094              
2095             # handle default value
2096             sub getrowspan {
2097             my ($self) = @_;
2098             my $attr = $self->{node}->getAttributeNode("rowspan");
2099             $self->{"rowspan"} = $attr ? $attr->getValue : "1";
2100             }
2101              
2102             # handle default value
2103             sub getcolspan {
2104             my ($self) = @_;
2105             my $attr = $self->{node}->getAttributeNode("colspan");
2106             $self->{"colspan"} = $attr ? $attr->getValue : "1";
2107             }
2108              
2109             ### Text elements ###
2110              
2111             #
2112             # Syndication::NITF::chron -- Date and time
2113             #
2114             package Syndication::NITF::chron;
2115             use Carp;
2116             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2117              
2118             sub _init {
2119             my ($self, $node) = @_;
2120             $self->{_attributes}->{norm} = IMPLIED; # normalised date and time
2121             $self->{_hasText} = 1;
2122             }
2123              
2124             #
2125             # Syndication::NITF::event -- An event considered newsworthy
2126             #
2127             package Syndication::NITF::event;
2128             use Carp;
2129             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2130              
2131             sub _init {
2132             my ($self, $node) = @_;
2133             $self->{_realname}->{altcode} = "alt-code";
2134             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2135             $self->{_realname}->{startdate} = "start-date";
2136             $self->{_attributes}->{"start-date"} = IMPLIED; # ISO Date
2137             $self->{_realname}->{enddate} = "end-date";
2138             $self->{_attributes}->{"end-date"} = IMPLIED; # ISO Date
2139             $self->{_attributes}->{idsrc} = IMPLIED; # Source (taxonomy) for value attribute
2140             $self->{_attributes}->{value} = IMPLIED; # ID Code or symbol for the element
2141             $self->{_hasText} = 1;
2142             }
2143              
2144             #
2145             # Syndication::NITF::function -- Role played by a person
2146             #
2147             package Syndication::NITF::function;
2148             use Carp;
2149             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2150              
2151             sub _init {
2152             my ($self, $node) = @_;
2153             $self->{_realname}->{altcode} = "alt-code";
2154             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2155             $self->{_attributes}->{idsrc} = IMPLIED; # Source (taxonomy) for value attribute
2156             $self->{_attributes}->{value} = IMPLIED; # ID Code or symbol for the element
2157             $self->{_hasText} = 1;
2158             }
2159              
2160             #
2161             # Syndication::NITF::location -- Significant place mentioned in an article
2162             #
2163             package Syndication::NITF::location;
2164             use Carp;
2165             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2166              
2167             sub _init {
2168             my ($self, $node) = @_;
2169             $self->{_multiElements}->{sublocation} = ZEROORMORE;
2170             $self->{_multiElements}->{city} = ZEROORMORE;
2171             $self->{_multiElements}->{state} = ZEROORMORE;
2172             $self->{_multiElements}->{region} = ZEROORMORE;
2173             $self->{_multiElements}->{country} = ZEROORMORE;
2174             $self->{_realname}->{altcode} = "alt-code";
2175             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2176             $self->{_realname}->{locationcode} = "location-code";
2177             $self->{_attributes}->{"location-code"} = IMPLIED; # ID of location
2178             $self->{_realname}->{codesource} = "code-source";
2179             $self->{_attributes}->{"code-source"} = IMPLIED; # Source (taxonomy) for location-code attribute
2180             $self->{_hasText} = 1;
2181             }
2182              
2183             #
2184             # Syndication::NITF::sublocation -- Named region within city or state
2185             #
2186             package Syndication::NITF::sublocation;
2187             use Carp;
2188             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2189              
2190             sub _init {
2191             my ($self, $node) = @_;
2192             $self->{_realname}->{altcode} = "alt-code";
2193             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2194             $self->{_realname}->{locationcode} = "location-code";
2195             $self->{_attributes}->{"location-code"} = IMPLIED; # ID of location
2196             $self->{_realname}->{codesource} = "code-source";
2197             $self->{_attributes}->{"code-source"} = IMPLIED; # Source (taxonomy) for location-code attribute
2198             $self->{_hasText} = 1;
2199             }
2200              
2201             #
2202             # Syndication::NITF::city -- City, town, village, etc
2203             #
2204             package Syndication::NITF::city;
2205             use Carp;
2206             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2207              
2208             sub _init {
2209             my ($self, $node) = @_;
2210             $self->{_realname}->{altcode} = "alt-code";
2211             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2212             $self->{_realname}->{citycode} = "city-code";
2213             $self->{_attributes}->{"city-code"} = IMPLIED; # ID of location
2214             $self->{_realname}->{codesource} = "code-source";
2215             $self->{_attributes}->{"code-source"} = IMPLIED; # Source (taxonomy) for location-code attribute
2216             $self->{_hasText} = 1;
2217             }
2218              
2219             #
2220             # Syndication::NITF::state -- State, province, region
2221             #
2222             package Syndication::NITF::state;
2223             use Carp;
2224             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2225              
2226             sub _init {
2227             my ($self, $node) = @_;
2228             $self->{_realname}->{altcode} = "alt-code";
2229             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2230             $self->{_realname}->{statecode} = "state-code";
2231             $self->{_attributes}->{"state-code"} = IMPLIED; # ID of location
2232             $self->{_realname}->{codesource} = "code-source";
2233             $self->{_attributes}->{"code-source"} = IMPLIED; # Source (taxonomy) for location-code attribute
2234             $self->{_hasText} = 1;
2235             }
2236              
2237             #
2238             # Syndication::NITF::region -- Geographic area
2239             #
2240             package Syndication::NITF::region;
2241             use Carp;
2242             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2243              
2244             sub _init {
2245             my ($self, $node) = @_;
2246             $self->{_realname}->{altcode} = "alt-code";
2247             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2248             $self->{_realname}->{regioncode} = "region-code";
2249             $self->{_attributes}->{"region-code"} = IMPLIED; # ID of location
2250             $self->{_realname}->{codesource} = "code-source";
2251             $self->{_attributes}->{"code-source"} = IMPLIED; # Source (taxonomy) for location-code attribute
2252             $self->{_hasText} = 1;
2253             }
2254              
2255             #
2256             # Syndication::NITF::country -- Geographic area with a government
2257             #
2258             package Syndication::NITF::country;
2259             use Carp;
2260             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2261              
2262             sub _init {
2263             my ($self, $node) = @_;
2264             $self->{_realname}->{altcode} = "alt-code";
2265             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2266             $self->{_realname}->{isocc} = "iso-cc";
2267             $self->{_attributes}->{"iso-cc"} = IMPLIED; # ISO 3166 country code
2268             $self->{_hasText} = 1;
2269             }
2270              
2271             #
2272             # Syndication::NITF::money -- Monetary item
2273             #
2274             package Syndication::NITF::money;
2275             use Carp;
2276             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2277              
2278             sub _init {
2279             my ($self, $node) = @_;
2280             $self->{_attributes}->{unit} = IMPLIED; # Currency used (source taxonomy??)
2281             $self->{_attributes}->{date} = IMPLIED; # ISO date for currency value quote
2282             $self->{_hasText} = 1;
2283             }
2284              
2285             #
2286             # Syndication::NITF::num -- Numeric data (used to normalise numbers)
2287             #
2288             package Syndication::NITF::num;
2289             use Carp;
2290             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2291              
2292             sub _init {
2293             my ($self, $node) = @_;
2294             $self->{_multiElements}->{frac} = ZEROORMORE;
2295             $self->{_multiElements}->{sub} = ZEROORMORE;
2296             $self->{_multiElements}->{sup} = ZEROORMORE;
2297             $self->{_attributes}->{units} = IMPLIED; # Units the number is in
2298             $self->{_realname}->{decimalch} = "decimal-ch";
2299             $self->{_attributes}->{"decimal-ch"} = IMPLIED; # character used to separate decimal portion
2300             $self->{_realname}->{thousandsch} = "thousands-ch";
2301             $self->{_attributes}->{"thousands-ch"} = IMPLIED; # character used to separate thousands groups
2302             $self->{_hasText} = 1;
2303             }
2304              
2305             #
2306             # Syndication::NITF::frac -- fraction
2307             #
2308             package Syndication::NITF::frac;
2309             use Carp;
2310             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2311              
2312             sub _init {
2313             my ($self, $node) = @_;
2314             $self->{_multiElements}->{numer} = ZEROORMORE;
2315             $self->{_realname}->{fracsep} = "frac-sep";
2316             $self->{_multiElements}->{"frac-sep"} = OPTIONAL;
2317             $self->{_multiElements}->{denom} = ZEROORMORE;
2318             }
2319              
2320             #
2321             # Syndication::NITF::numer -- Numerator of a fraction
2322             #
2323             package Syndication::NITF::numer;
2324             use Carp;
2325             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2326              
2327             sub _init {
2328             my ($self, $node) = @_;
2329             $self->{_hasText} = 1;
2330             }
2331              
2332              
2333             #
2334             # Syndication::NITF::frac-sep -- Separator of a fraction
2335             #
2336             package Syndication::NITF::fracsep;
2337             use Carp;
2338             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2339              
2340             sub _init {
2341             my ($self, $node) = @_;
2342             $self->{_hasText} = 1;
2343             }
2344              
2345             #
2346             # Syndication::NITF::denom -- Denominator of a fraction
2347             #
2348             package Syndication::NITF::denom;
2349             use Carp;
2350             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2351              
2352             sub _init {
2353             my ($self, $node) = @_;
2354             $self->{_hasText} = 1;
2355             }
2356              
2357             #
2358             # Syndication::NITF::sub -- Subscript
2359             #
2360             package Syndication::NITF::sub;
2361             use Carp;
2362             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2363              
2364             sub _init {
2365             my ($self, $node) = @_;
2366             $self->{_hasText} = 1;
2367             }
2368              
2369             #
2370             # Syndication::NITF::sup -- Superscript
2371             #
2372             package Syndication::NITF::sup;
2373             use Carp;
2374             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2375              
2376             sub _init {
2377             my ($self, $node) = @_;
2378             $self->{_hasText} = 1;
2379             }
2380              
2381             #
2382             # Syndication::NITF::object.title -- title of inline object (song, book etc)
2383             #
2384             package Syndication::NITF::objecttitle;
2385             use Carp;
2386             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2387              
2388             sub _init {
2389             my ($self, $node) = @_;
2390             $self->{_realname}->{altcode} = "alt-code";
2391             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2392             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy of identifying code
2393             $self->{_attributes}->{value} = IMPLIED; # identifying code
2394             $self->{_hasText} = 1;
2395             }
2396              
2397             #
2398             # Syndication::NITF::org -- organisation (public, private, non-profit)
2399             #
2400             package Syndication::NITF::org;
2401             use Carp;
2402             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2403              
2404             sub _init {
2405             my ($self, $node) = @_;
2406             $self->{_realname}->{altcode} = "alt-code";
2407             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2408             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy of identifying code
2409             $self->{_attributes}->{value} = IMPLIED; # identifying code
2410             $self->{_hasText} = 1;
2411             }
2412              
2413             #
2414             # Syndication::NITF::alt-code -- alternative identifying code for an item
2415             #
2416             package Syndication::NITF::altcode;
2417             use Carp;
2418             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2419              
2420             sub _init {
2421             my ($self, $node) = @_;
2422             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy of identifying code
2423             $self->{_attributes}->{value} = IMPLIED; # identifying code
2424             }
2425              
2426             #
2427             # Syndication::NITF::person -- a human individual
2428             #
2429             package Syndication::NITF::person;
2430             use Carp;
2431             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2432              
2433             sub _init {
2434             my ($self, $node) = @_;
2435             $self->{_realname}->{namegiven} = "name.given";
2436             $self->{_multiElements}->{"name.given"} = ZEROORMORE;
2437             $self->{_realname}->{namefamily} = "name.family";
2438             $self->{_multiElements}->{"name.family"} = ZEROORMORE;
2439             $self->{_multiElements}->{function} = ZEROORMORE;
2440             $self->{_realname}->{altcode} = "alt-code";
2441             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2442             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy of identifying code
2443             $self->{_attributes}->{value} = IMPLIED; # identifying code
2444             $self->{_hasText} = 1;
2445             }
2446              
2447             #
2448             # Syndication::NITF::name.given -- person's given (Western, first) name
2449             #
2450             package Syndication::NITF::namegiven;
2451             use Carp;
2452             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2453              
2454             sub _init {
2455             my ($self, $node) = @_;
2456             $self->{_hasText} = 1;
2457             }
2458              
2459             #
2460             # Syndication::NITF::name.family -- person's family (Western, last) name
2461             #
2462             package Syndication::NITF::namefamily;
2463             use Carp;
2464             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2465              
2466             sub _init {
2467             my ($self, $node) = @_;
2468             $self->{_hasText} = 1;
2469             }
2470              
2471             #
2472             # Syndication::NITF::postaddr -- postal address
2473             #
2474             package Syndication::NITF::postaddr;
2475             use Carp;
2476             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2477              
2478             sub _init {
2479             my ($self, $node) = @_;
2480             $self->{_singleElements}->{addressee} = REQUIRED;
2481             $self->{_realname}->{deliverypoint} = "delivery.point";
2482             $self->{_singleElements}->{"delivery.point"} = OPTIONAL;
2483             $self->{_multiElements}->{postcode} = ZEROORMORE;
2484             $self->{_realname}->{deliveryoffice} = "delivery.office";
2485             $self->{_multiElements}->{"delivery.office"} = ZEROORMORE;
2486             $self->{_multiElements}->{region} = ZEROORMORE;
2487             $self->{_multiElements}->{country} = ZEROORMORE;
2488             }
2489              
2490             #
2491             # Syndication::NITF::virtloc -- virtual location
2492             #
2493             package Syndication::NITF::virtloc;
2494             use Carp;
2495             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2496              
2497             sub _init {
2498             my ($self, $node) = @_;
2499             $self->{_realname}->{altcode} = "alt-code";
2500             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2501             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy of identifying code
2502             $self->{_attributes}->{value} = IMPLIED; # identifying code
2503             $self->{_hasText} = 1;
2504             }
2505              
2506             #
2507             # Syndication::NITF::a -- HTML-like anchor
2508             #
2509             package Syndication::NITF::a;
2510             use Carp;
2511             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
2512              
2513             sub _init {
2514             my ($self, $node) = @_;
2515             $self->{_attributes}->{href} = IMPLIED; # URL
2516             $self->{_attributes}->{name} = IMPLIED; # Alternate name for link
2517             $self->{_attributes}->{rel} = IMPLIED; # describes relationship from source to target
2518             $self->{_attributes}->{rev} = IMPLIED; # describe relationship from target to source
2519             $self->{_attributes}->{title} = IMPLIED; # title of document to be linked to
2520             }
2521              
2522             #
2523             # Syndication::NITF::br -- HTML-style line break
2524             #
2525             package Syndication::NITF::br;
2526             use Carp;
2527             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2528              
2529             sub _init {
2530             my ($self, $node) = @_;
2531             }
2532              
2533             #
2534             # Syndication::NITF::em -- HTML-like emphasis
2535             #
2536             package Syndication::NITF::em;
2537             use Carp;
2538             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
2539              
2540             sub _init {
2541             my ($self, $node) = @_;
2542             }
2543              
2544             #
2545             # Syndication::NITF::lang -- Language identifier
2546             #
2547             package Syndication::NITF::lang;
2548             use Carp;
2549             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
2550              
2551             sub _init {
2552             my ($self, $node) = @_;
2553             }
2554              
2555             #
2556             # Syndication::NITF::pronounce -- Pronunciation information
2557             #
2558             package Syndication::NITF::pronounce;
2559             use Carp;
2560             @ISA = qw( Syndication::NITF::GlobalAttributesNode Syndication::NITF::EnrichedTextNode );
2561              
2562             sub _init {
2563             my ($self, $node) = @_;
2564             $self->{_attributes}->{guide} = IMPLIED; # Source used to create pronunciation
2565             $self->{_attributes}->{phonetic} = IMPLIED; # Phonetic pronunciation of a phrase
2566             }
2567              
2568             #
2569             # Syndication::NITF::q -- quotation
2570             #
2571             package Syndication::NITF::q;
2572             use Carp;
2573             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
2574              
2575             sub _init {
2576             my ($self, $node) = @_;
2577             $self->{_realname}->{quotesource} = "quote-source";
2578             $self->{_attributes}->{"quote-source"} = IMPLIED; # who said or wrote the quotation
2579             }
2580              
2581             ### postaddr elements ###
2582              
2583             #
2584             # Syndication::NITF::addressee -- recipient of a postal item (used in postal address)
2585             #
2586             package Syndication::NITF::addressee;
2587             use Carp;
2588             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2589              
2590             sub _init {
2591             my ($self, $node) = @_;
2592             $self->{_singleElements}->{person} = REQUIRED;
2593             $self->{_singleElements}->{function} = OPTIONAL;
2594             $self->{_realname}->{careof} = "care.of";
2595             $self->{_singleElements}->{"care.of"} = OPTIONAL;
2596             }
2597              
2598             #
2599             # Syndication::NITF::care.of -- Poste restante
2600             #
2601             package Syndication::NITF::careof;
2602             use Carp;
2603             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2604              
2605             sub _init {
2606             my ($self, $node) = @_;
2607             $self->{_hasText} = 1;
2608             }
2609              
2610             #
2611             # Syndication::NITF::delivery.point -- street / po box no
2612             #
2613             package Syndication::NITF::deliverypoint;
2614             use Carp;
2615             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2616              
2617             sub _init {
2618             my ($self, $node) = @_;
2619             $self->{_multiElements}->{br} = ZEROORMORE;
2620             $self->{_realname}->{pointcode} = "point-code";
2621             $self->{_attributes}->{"point-code"} = IMPLIED; # Coded location for a delivery point
2622             $self->{_realname}->{codesource} = "code-source";
2623             $self->{_attributes}->{"code-source"} = IMPLIED; # Source of coded list information
2624             $self->{_hasText} = 1;
2625             }
2626              
2627             #
2628             # Syndication::NITF::postcode -- postal/zip code
2629             #
2630             package Syndication::NITF::postcode;
2631             use Carp;
2632             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2633              
2634             sub _init {
2635             my ($self, $node) = @_;
2636             $self->{_realname}->{codesource} = "code-source";
2637             $self->{_attributes}->{"code-source"} = IMPLIED; # Source of coded list information
2638             $self->{_hasText} = 1;
2639             }
2640              
2641             #
2642             # Syndication::NITF::delivery.office -- city or town where post office is located
2643             #
2644             package Syndication::NITF::deliveryoffice;
2645             use Carp;
2646             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2647              
2648             sub _init {
2649             my ($self, $node) = @_;
2650             $self->{_multiElements}->{br} = ZEROORMORE;
2651             $self->{_realname}->{officecode} = "office-code";
2652             $self->{_attributes}->{"office-code"} = IMPLIED; # Coded location for a delivery office
2653             $self->{_realname}->{codesource} = "code-source";
2654             $self->{_attributes}->{"code-source"} = IMPLIED; # Source of coded list information
2655             $self->{_hasText} = 1;
2656             }
2657              
2658             ### body end ###
2659              
2660             #
2661             # Syndication::NITF::body.end -- information at end of article body
2662             #
2663             package Syndication::NITF::bodyend;
2664             use Carp;
2665             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2666              
2667             sub _init {
2668             my ($self, $node) = @_;
2669             $self->{_singleElements}->{tagline} = OPTIONAL;
2670             $self->{_singleElements}->{bibliography} = OPTIONAL;
2671             }
2672              
2673             #
2674             # Syndication::NITF::tagline -- Byline at the end of a story
2675             #
2676             package Syndication::NITF::tagline;
2677             use Carp;
2678             @ISA = qw( Syndication::NITF::CommonAttributesNode Syndication::NITF::EnrichedTextNode );
2679              
2680             sub _init {
2681             my ($self, $node) = @_;
2682             $self->{_attributes}->{type} = IMPLIED; # type of notice
2683             }
2684              
2685             # attribute is an enumeration so we must handle separately
2686             sub gettype {
2687             my ($self) = @_;
2688             my @possiblevalues = qw( std pa npa ); # standard, publishable advisory, non-publishable advisory
2689             my $attr = $self->{node}->getAttributeNode("type");
2690             $self->{"type"} = $attr ? $attr->getValue : "";
2691             if ($self->{type} && grep !/$self->{type}/, "@possiblevalues") {
2692             croak "Illegal value ".$self->{type}." for attribute type";
2693             }
2694             return $self->{"type"};
2695             }
2696              
2697             #
2698             # Syndication::NITF::bibliography -- Free-form bibliographic data
2699             #
2700             package Syndication::NITF::bibliography;
2701             use Carp;
2702             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2703              
2704             sub _init {
2705             my ($self, $node) = @_;
2706             $self->{_hasText} = 1;
2707             }
2708              
2709             #
2710             # Syndication::NITF::classifier -- Generic container for metadata
2711             #
2712             package Syndication::NITF::classifier;
2713             use Carp;
2714             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2715              
2716             sub _init {
2717             my ($self, $node) = @_;
2718             $self->{_realname}->{altcode} = "alt-code";
2719             $self->{_multiElements}->{"alt-code"} = ZEROORMORE;
2720             $self->{_attributes}->{type} = IMPLIED; # type of classifier (eg concept)
2721             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy for the element's value
2722             $self->{_attributes}->{value} = IMPLIED; # the value itself
2723             $self->{_hasText} = 1;
2724             }
2725              
2726             #
2727             # Syndication::NITF::nitf-table -- Holder for a table and metadata
2728             #
2729             package Syndication::NITF::nitftable;
2730             use Carp;
2731             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2732              
2733             sub _init {
2734             my ($self, $node) = @_;
2735             $self->{_realname}->{nitftablemetadata} = "nitf-table-metadata";
2736             $self->{_singleElements}->{"nitf-table-metadata"} = REQUIRED;
2737             $self->{_singleElements}->{table} = OPTIONAL;
2738             $self->{_realname}->{customtable} = "custom-table";
2739             $self->{_singleElements}->{"custom-table"} = OPTIONAL;
2740             $self->{_realname}->{tablereference} = "table-reference";
2741             $self->{_multiElements}->{"table-reference"} = ZEROORMORE;
2742             }
2743              
2744             # return how many columns this table contains. Try a number of methods to work it out.
2745             sub getColumnCount {
2746             my ($self) = @_;
2747             # if the column count is given in the metadata, let's believe it
2748             my $count = 0;
2749             $count = $self->getnitftablemetadata->getcolumncount;
2750             if (!$count) {
2751             foreach my $coltag ($self->getnitftablemetadata->{node}->getElementsByTagName("nitf-col", 0)) {
2752             $count += $coltag->getAttributeNode("occurrences")
2753             ? $coltag->getAttributeNode("occurrences")->getValue
2754             : 1;
2755             }
2756             foreach my $colgrouptag ($self->getnitftablemetadata->{node}->getElementsByTagName("nitf-colgroup", 0)) {
2757             my $occurrences = $colgrouptag->getAttributeNode("occurrences")->getValue
2758             if $colgrouptag->getAttributeNode("occurrences");
2759             my $subcount = 0;
2760             foreach my $coltag ($colgrouptag->getElementsByTagName("nitf-col", 0)) {
2761             $subcount += $coltag->getAttributeNode("occurrences")
2762             ? $coltag->getAttributeNode("occurrences")->getValue
2763             : 1;
2764             }
2765             $count += $subcount * $occurrences;
2766             }
2767             }
2768             return $count;
2769             }
2770              
2771             # return how many rows this table contains. Try a number of methods to work it out.
2772             sub getRowCount {
2773             my ($self) = @_;
2774             # if the rows count is given in the metadata, let's believe it
2775             my $count = 0;
2776             $count = $self->getnitftablemetadata->getrowcount;
2777             # otherwise do a simple count of all the
2778             if (!$count) {
2779             foreach my $rowtag ($self->gettable->{node}->getElementsByTagName("tr", 0)) {
2780             $count += 1;
2781             }
2782             }
2783             return $count;
2784             }
2785              
2786             #
2787             # Syndication::NITF::custom-table -- holder for a namespaced XML fragment for custom-tagged metadata
2788             #
2789             package Syndication::NITF::customtable;
2790             use Carp;
2791             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2792              
2793             sub _init {
2794             my ($self, $node) = @_;
2795             $self->{_hasText} = 1;
2796             }
2797              
2798             #
2799             # Syndication::NITF::table-reference -- pointer to a table elsewhere in the document
2800             #
2801             package Syndication::NITF::tablereference;
2802             use Carp;
2803             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2804              
2805             sub _init {
2806             my ($self, $node) = @_;
2807             $self->{_attributes}->{idref} = REQUIRED; # ID for referenced table
2808             }
2809              
2810             #
2811             # Syndication::NITF::nitf-table-metadata -- holder for namespaced XML fragment for custom-tagged metadata
2812             #
2813             package Syndication::NITF::nitftablemetadata;
2814             use Carp;
2815             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2816              
2817             sub _init {
2818             my ($self, $node) = @_;
2819             $self->{_realname}->{nitftablesummary} = "nitf-table-summary";
2820             $self->{_singleElements}->{"nitf-table-summary"} = OPTIONAL;
2821             $self->{_realname}->{nitfcolgroup} = "nitf-colgroup";
2822             $self->{_multiElements}->{"nitf-colgroup"} = ZEROORMORE;
2823             $self->{_realname}->{nitfcol} = "nitf-col";
2824             $self->{_multiElements}->{"nitf-col"} = ZEROORMORE;
2825             $self->{_attributes}->{subclass} = IMPLIED; # further refinement of class attribute (see CommonAttributes)
2826             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy used for referenced value
2827             $self->{_attributes}->{value} = IMPLIED; # actual value
2828             $self->{_attributes}->{status} = IMPLIED; # see below
2829             $self->{_realname}->{columncount} = "column-count";
2830             $self->{_attributes}->{"column-count"} = IMPLIED; # Num of columns in entire table
2831             $self->{_realname}->{rowcount} = "row-count";
2832             $self->{_attributes}->{"row-count"} = IMPLIED; # Num of rows in entire table
2833             }
2834              
2835             # attribute is an enumeration so we must handle separately
2836             sub getstatus {
2837             my ($self) = @_;
2838             my @possiblevalues = qw( pre snap-shot interim final official );
2839             my $attr = $self->{node}->getAttributeNode("status");
2840             $self->{"status"} = $attr ? $attr->getValue : "";
2841             if ($self->{status} && grep !/$self->{status}/, "@possiblevalues") {
2842             croak "Illegal value ".$self->{status}." for attribute status";
2843             }
2844             return $self->{"status"};
2845             }
2846              
2847             #
2848             # Syndication::NITF::nitf-table-summary -- Textual description of the table
2849             #
2850             package Syndication::NITF::nitftablesummary;
2851             use Carp;
2852             @ISA = qw( Syndication::NITF::CommonAttributesNode );
2853              
2854             sub _init {
2855             my ($self, $node) = @_;
2856             $self->{_multiElements}->{p} = ZEROORMORE; # paragraphs
2857             }
2858              
2859             #
2860             # Syndication::NITF::nitf-colgroup -- Collection of nitf-col elements
2861             #
2862             package Syndication::NITF::nitfcolgroup;
2863             use Carp;
2864             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2865              
2866             sub _init {
2867             my ($self, $node) = @_;
2868             $self->{_realname}->{nitfcol} = "nitf-col";
2869             $self->{_multiElements}->{"nitf-col"} = ONEORMORE;
2870             $self->{_attributes}->{occurrences} = IMPLIED; # Count. Default is 1 (but not written into DTD?)
2871             }
2872              
2873             #
2874             # Syndication::NITF::nitf-col -- Holder for namespaced XML fragment for custom-tagged data
2875             #
2876             package Syndication::NITF::nitfcol;
2877             use Carp;
2878             @ISA = qw( Syndication::NITF::GlobalAttributesNode );
2879              
2880             sub _init {
2881             my ($self, $node) = @_;
2882             $self->{_attributes}->{order} = IMPLIED; # position of column within table (means metadata may be out of order)
2883             $self->{_attributes}->{idsrc} = IMPLIED; # taxonomy for the value attribute
2884             $self->{_attributes}->{value} = IMPLIED; # the value itself
2885             $self->{_attributes}->{occurrences} = IMPLIED; # number of occurrences (default 1)
2886             $self->{_realname}->{datatype} = "data-type";
2887             $self->{_attributes}->{"data-type"} = IMPLIED; # general type of data in the column
2888             $self->{_realname}->{dataformat} = "data-format";
2889             $self->{_attributes}->{"data-format"} = IMPLIED; # expanded definition of the data
2890             }
2891              
2892             # attribute is an enumeration so we must handle separately
2893             sub getdatatype {
2894             my ($self) = @_;
2895             my @possiblevalues = qw( text number graphic other );
2896             my $attr = $self->{node}->getAttributeNode("data-type");
2897             $self->{"data-type"} = $attr ? $attr->getValue : "";
2898             if ($self->{"data-type"} && grep !/$self->{"data-type"}/, "@possiblevalues") {
2899             croak "Illegal value ".$self->{"data-type"}." for attribute data-type";
2900             }
2901             return $self->{"data-type"};
2902             }
2903