File Coverage

lib/Data/DublinCore.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             # Copyrights 2009-2010 by Mark Overmeer.
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 1.06.
5 2     2   32609 use warnings;
  2         4  
  2         55  
6 2     2   9 use strict;
  2         3  
  2         74  
7              
8             package Data::DublinCore;
9 2     2   10 use vars '$VERSION';
  2         17  
  2         95  
10             $VERSION = '0.04';
11              
12 2     2   9 use base 'XML::Compile::Cache';
  2         2  
  2         2642  
13             our $VERSION = '0.01';
14              
15             use Log::Report 'data-dublincore', syntax => 'SHORT';
16              
17             use XML::Compile::Util qw/type_of_node unpack_type pack_type SCHEMA2001/;
18             use XML::LibXML::Simple qw/XMLin/;
19             use Scalar::Util qw/weaken/;
20              
21              
22             use Data::DublinCore::Util;
23             use XML::Compile::Util qw/XMLNS/;
24              
25             # map namespace always to the newest implementation of the protocol
26             my $newest = '20080211';
27             my %ns2version = (&NS_DC_ELEMS11 => $newest);
28              
29             my %info =
30             ( 20020312 => {}
31             , 20021212 => {}
32             , 20030402 => {}
33             , 20060106 => {}
34             , 20080211 => {}
35             );
36              
37             # there are no other options yet
38             my @prefixes =
39             ( dc => NS_DC_ELEMS11
40             , dcterms => NS_DC_TERMS
41             , dcmi => NS_DC_DCMITYPE
42             , xml => XMLNS
43             );
44              
45             #----------------
46              
47              
48             sub new($)
49             { my $class = shift;
50             $class->SUPER::new(direction => 'RW', @_);
51             }
52              
53             sub init($)
54             { my ($self, $args) = @_;
55             $args->{allow_undeclared} = 1
56             unless exists $args->{allow_undeclared};
57              
58             my $r = $args->{opts_readers};
59             $r = @$r if ref $r eq 'ARRAY';
60             $r->{mixed_elements} = 'XML_NODE';
61              
62             my $s = $self; weaken $s; # avoid memory leak
63             $r->{any_type} = sub { $s->_handle_any_type(@_) };
64              
65             $args->{opts_readers} = $r;
66              
67             $args->{any_element} ||= 'ATTEMPT';
68              
69             $self->SUPER::init($args);
70              
71             my $version = $args->{version} || $newest;
72              
73             unless(exists $info{$version})
74             { exists $ns2version{$version}
75             or error __x"DC version {v} not recognized", v => $version;
76             $version = $ns2version{$version};
77             }
78             $self->{version} = $version;
79             my $info = $info{$version};
80              
81             $self->prefixes(@prefixes);
82             $self->addKeyRewrite('PREFIXED(dc,xml,dcterms)');
83              
84             (my $xsd = __FILE__) =~ s!\.pm!/xsd!;
85             my @xsds;
86             if($version lt 2003)
87             { @xsds = glob "$xsd/dc$version/*";
88             }
89             else
90             { @xsds = glob "$xsd/dc$version/{dcmitype,dcterms,dc}.xsd";
91              
92             # tricky... the application will load the following two,
93             # specifying the targetNamespace. Use with
94             # $self->importDefinitions('qualifieddc', target_namespace => );
95             $self->knownNamespace($_ => "$xsd/dc$version/$_.xsd")
96             for qw/qualifieddc simpledc/;
97             }
98              
99             $self->importDefinitions(\@xsds);
100             $self->importDefinitions(XMLNS);
101              
102             $self;
103             }
104              
105             sub _handle_any_type($$$)
106             { my ($self, $path, $node, $default_handler) = @_;
107             my $r = $default_handler->($path, $node);
108              
109             # convert unknown anyType element structure into something
110             my $v = ref $r ? XMLin($r) : $r;
111              
112             if(ref $node)
113             { if(my $attrn = $node->getAttributeNodeNS(XMLNS, 'lang'))
114             { ref $v eq 'HASH' or $v = { _ => $v };
115             $v->{'xml:lang'} = $attrn->value;
116             }
117             }
118              
119             $v;
120             }
121              
122              
123             # Business::XPDL shows how to create conversions here... but all
124             # DC versions are backwards compatible
125             sub from($@)
126             { my ($thing, $source, %args) = @_;
127              
128             my $xml = XML::Compile->dataToXML($source);
129             my $top = type_of_node $xml;
130             my ($ns, $topname) = unpack_type $top;
131             my $version = $ns2version{$ns}
132             or error __x"unknown DC version with namespace {ns}", ns => $ns;
133              
134             my $self = ref $thing ? $thing : $thing->new(version => $version);
135             my $r = $self->reader($top, %args)
136             or error __x"root node `{top}' not recognized", top => $top;
137              
138             ($top, $r->($xml));
139             }
140              
141              
142             sub version() {shift->{version}}
143             sub namespace() {shift->{namespace}}
144              
145             1;