XML::Compile - Perl Modules

advertisement
From XML (schema) to Application
Mark Overmeer
MARKOV@cpan.org
YAPC::EU 2008
2008-08-13
MARKOV Solutions
http://perl.overmeer.net
From XML (schema) to Application
Mark Overmeer
MARKOV@cpan.org
YAPC::EU 2008
2008-08-13
I HATE XML
MARKOV Solutions
http://perl.overmeer.net
Objective
XML schema's are very popular
Schema/XML complications
name-spaces
strongly typed
verbose notation
often generated
Application complications
message validation: strictness
schema location
schema versioning
XML::Compile suite helps!
3
XML::Compile
Advantages over other XML modules:
very strict following the rules: no DWIM, no guessing
usually no need for name-space understanding
"slow" compile phase, then fast run
very close to 100% support: no known bugs
4
XML::Compile
Advantages over other XML modules:
very strict following the rules: no DWIM, no guessing
usually no need for name-space understanding
"slow" compile phase, then fast run
very close to 100% support: no known bugs
my $schema = XML::Compile::Schema->new($xsdfile);
5
XML::Compile
Advantages over other XML modules:
very strict following the rules: no DWIM, no guessing
usually no need for name-space understanding
"slow" compile phase, then fast run
very close to 100% support: no known bugs
my $schema = XML::Compile::Schema->new($xsdfile);
my $read = $schema->compile(READER => '{myns}mytype');
my $hash = $read->($xml);
print Dumper $hash;
6
XML::Compile
Advantages over other XML modules:
very strict following the rules: no DWIM, no guessing
usually no need for name-space understanding
"slow" compile phase, then fast run
very close to 100% support: no known bugs
my $schema = XML::Compile::Schema->new($xsdfile);
my $read = $schema->compile(READER => '{myns}mytype');
my $hash = $read->($xml);
print Dumper $hash;
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
my $write = $schema->compile(WRITER => '{myns}mytype');
my $xml = $write->($doc, $hash);
print $xml->toString(1);
7
XML::Compile::Schema
Collects information from all used schema's
Organizes compilation
X::C::Translate, with back-ends
X::C::T::Reader
X::C::T::Writer
X::C::T::Template
XML → HASH
HASH → XML
example generator
built-in types
name-space administration
Compilation results in code-refs
8
XML::Compile::Cache
Extends X::C::Schema
compiled code-ref management
compile option management
pre-compile for daemons or
compile-on-demand single shot
use of prefixes
9
XML::Compile::Cache
Extends X::C::Schema
compiled code-ref management
compile option management
pre-compile for daemons or
compile-on-demand single shot
use of prefixes
my @p
= (myprefix => $mynamespace);
my $schema = XML::Compile::Cache->new(prefixes => \@p);
my $type = 'myprefix:mylocal'; # {mynamespace}mylocal
$schema->declare(READER => $type, @options);
# $schema->compileAll
my $data = $schema->reader($type)->($xml);
my $xml = $schema->writer($type)->($doc, $data);
10
Other modules for XML::Compile
XML::Compile::SOAP11
XML::Compile::WSDL11
my $wsdl = XML::Compile::WSDL11->new($wsdlfile);
my $call = $wsdl->compileClient('CallName');
my ($answer, $trace) = $call->($request);
11
Other modules for XML::Compile
XML::Compile::SOAP11
XML::Compile::WSDL11
my $wsdl = XML::Compile::WSDL11->new($wsdlfile);
my $call = $wsdl->compileClient('CallName');
my ($answer, $trace) = $call->($request);
XML::Compile::SOAP::Daemon
my $daemon = XML::Compile::SOAP::HTTPDaemon->new;
$daemon->operationsFromWSDL($wsdl,
handlers => { CallName => \&handle_call } );
$daemon->run;
based on Net::Server and HTTP::Daemon
12
Other modules for XML::Compile
XML::Compile::Tester
XML::Compile::Dumper
XML::Compile::Rewrite
xmlrewrite --plugin schema2001
--xmlns
--no-annotations
--no-comments
--no-id-constraints
--expand-includes
--output
xsd=$SCHEMA2001,me=$OTHER
reformated.xsd
To come:
--no-elements
version,bigone
--promote-unnamed 2
--sort
name
--extract-element
--no-unused-types
... etc ...
XML::LibXML::Simple
13
Publish XML Interface
Module based on XML::Compile::Cache
Include all versions of the schema in the package
Collect validated message examples
create readers for them, and study the result
which types are really used? (what to declare)
Create constants for name-spaces
14
Example: Geo::KML
Geo::KML::Util
package Geo::KML::Util;
use base 'Exporter';
my @kml21 = qw/NS_KML_21/;
my @kml220 = qw/NS_KML_22 NS_ATOM_2005 NS_XAL_20/;
my @EXPORT = (@kml21, @kml220);
my %EXPORT_TAGS = (kml21 => \@kml21, kml220 => \@kml22);
use constant NS_KML_21 => 'http://earth.google.com/kml/2.1';
use constant NS_KML_22 => 'http://www.opengis.net/kml/2.2';
use constant NS_ATOM_2005 => 'http://www.w3.org/2005/Atom';
use constant NS_XAL_20
=> 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0';
1;
15
Example: Geo::KML
Protocol version
package Geo::KML;
use base 'XML::Compile::Cache';
use Geo::KML::Util;
# all constants
my %ns2version = ( &NS_KML_21 => '2.1'
, &NS_KML_22 => '2.2.0');
my %version2ns = reverse %ns2version;
# ::Cache::new { (bless {},$class)->init(\%args) }
sub init($)
{ my ($self, $args) = @_;
my $version = $args->{version} or die;
$class->SUPER::init($args);
...
use Geo::KML;
my $kml = Geo::KML->new(version => '2.2.0');
16
Example: Geo::KML
Version specifics
my %info =
( '2.1' =>
{ prefixes => [ '' => NS_KML_21 ]
, schemas => [ 'kml-2.1/*.xsd' ] }
, '2.2.0' =>
{ prefixes => [ '' => NS_KML_220, atom => NS_ATOM_2005
, xal => NS_XAL_20 ]
, schemas => [ 'kml-2.2.0/*.xsd', 'atom-2005/*.xsd'
, 'xal-2.0/*.xsd' ]
}
);
sub init($)
{ ...
my $info = $info{$version} or die;
$args->{prefixes} = $info->{prefixes};
$self->SUPER::init($args);
...
17
Example: Geo::KML
Compile schema's
$info{'2.2.0'}{schemas} = ['kml-2.2.0/*.xsd', ...];
sub init($)
{ ...
$self->SUPER::init($args);
(my $xsd = __FILE__) =~ s!\.pm$!/xsd!;
my $patterns = $info{$version}{schemas};
my @xsds = map {glob "$xsd/$_"} @$patterns;
$self->importDefinitions(\@xsds);
lib/Geo/KML.pm
lib/Geo/KML/Util.pm
lib/Geo/KML/xsd/atom-2005/atom-author-link.xsd
lib/Geo/KML/xsd/kml-2.2.0/ogckml22.xsd
lib/Geo/KML/xsd/xal-2.0/xAL.xsd
18
Example: Geo::KML
Read KML
sub init($)
{ ...
$self->declare(READER => 'kml');
$self;
}
name-space qualified!
(empty prefix)
sub readKML(@)
{ my ($class, $xml, %opts) = @_;
$xml->nodeName eq 'kml' or die;
my $obj = $class->new(version => $xml->namespaceURI);
my $data = $obj->reader('kml')->($xml);
return $data;
use Geo::KML;
my ($type, $data) = Geo::KML->readKML('points.kmz');
19
Example: Geo::KML
Write KML
$self->declare(WRITER => 'kml', include_namespaces => 1);
sub writeKML($$)
{ my ($self, $data, $filename) = @_;
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
my $xml = $self->writer('kml')->($doc, $data);
$doc->setDocumentElement($xml);
$doc->toFile($filename, 1);
}
20
Example: Geo::KML
Write KML
use Geo::KML;
my %location =
( name => ''
, description => ''
, Point => {coordinates => [ "$long,$lat,0" ] }
);
my %data =
( AbstractFeatureGroup =>
[ { Placemark => \%location },
]
);
my $kml = Geo::KML->new(version => '2.2.0');
$kml->writeKML(\%data, 'example.kml');
21
Example: Geo::KML
... and then ...
simplify access to the data-structure
my %typemap = ( "{$kml22}Document" => Geo::KML::Document );
$self->declare(RW => 'kml', typemap => \%typemap);
package Geo::KML::Document;
# shows default implem.
sub toXML($$)
{ my ($self, $type, $doc) = @_;
$self;
# XML data-structure or XML node
}
sub fromXML($$)
{ my ($class, $data, $type) = @_;
bless $data, $class;
}
22
Download