2008-08-13
MARKOV Solutionshttp://perl.overmeer.net
Mark [email protected]
YAPC::EU 2008
From XML (schema) to Application
2008-08-13
MARKOV Solutionshttp://perl.overmeer.net
Mark [email protected]
YAPC::EU 2008
From XML (schema) to Application
I HATE XML
3
Objective
XML schema's are very popular
Schema/XML complicationsname-spacesstrongly typedverbose notationoften generated
Application complicationsmessage validation: strictnessschema locationschema versioning
XML::Compile suite helps!
4
XML::Compile
Advantages over other XML modules:very strict following the rules: no DWIM, no guessingusually no need for name-space understanding"slow" compile phase, then fast runvery close to 100% support: no known bugs
5
XML::Compile
Advantages over other XML modules:very strict following the rules: no DWIM, no guessingusually no need for name-space understanding"slow" compile phase, then fast runvery close to 100% support: no known bugs
my $schema = XML::Compile::Schema->new($xsdfile);
6
XML::Compile
Advantages over other XML modules:very strict following the rules: no DWIM, no guessingusually no need for name-space understanding"slow" compile phase, then fast runvery 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;
7
XML::Compile
Advantages over other XML modules:very strict following the rules: no DWIM, no guessingusually no need for name-space understanding"slow" compile phase, then fast runvery 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);
8
XML::Compile::Schema
Collects information from all used schema's
Organizes compilationX::C::Translate, with back-ends
X::C::T::Reader XML → HASHX::C::T::Writer HASH → XMLX::C::T::Template example generator
built-in typesname-space administration
Compilation results in code-refs
9
XML::Compile::Cache
Extends X::C::Schemacompiled code-ref managementcompile option managementpre-compile for daemons orcompile-on-demand single shotuse of prefixes
10
XML::Compile::Cache
Extends X::C::Schemacompiled code-ref managementcompile option managementpre-compile for daemons orcompile-on-demand single shotuse 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);
11
Other modules for XML::Compile
XML::Compile::SOAP11XML::Compile::WSDL11
my $wsdl = XML::Compile::WSDL11->new($wsdlfile);my $call = $wsdl->compileClient('CallName');
my ($answer, $trace) = $call->($request);
12
Other modules for XML::Compile
XML::Compile::SOAP11XML::Compile::WSDL11
XML::Compile::SOAP::Daemon
based on Net::Server and HTTP::Daemon
my $wsdl = XML::Compile::WSDL11->new($wsdlfile);my $call = $wsdl->compileClient('CallName');
my ($answer, $trace) = $call->($request);
my $daemon = XML::Compile::SOAP::HTTPDaemon->new;$daemon->operationsFromWSDL($wsdl, handlers => { CallName => \&handle_call } );$daemon->run;
13
Other modules for XML::Compile
XML::Compile::TesterXML::Compile::DumperXML::Compile::Rewrite
XML::LibXML::Simple
xmlrewrite --plugin schema2001--xmlns xsd=$SCHEMA2001,me=$OTHER--no-annotations--no-comments--no-id-constraints--expand-includes--output reformated.xsd
To come:--no-elements version,bigone --extract-element--promote-unnamed 2 --no-unused-types--sort name ... etc ...
14
Publish XML Interface
Module based on XML::Compile::Cache
Include all versions of the schema in the package
Collect validated message examplescreate readers for them, and study the resultwhich types are really used? (what to declare)
Create constants for name-spaces
15
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;
16
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');
17
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); ...
18
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.pmlib/Geo/KML/Util.pmlib/Geo/KML/xsd/atom-2005/atom-author-link.xsdlib/Geo/KML/xsd/kml-2.2.0/ogckml22.xsdlib/Geo/KML/xsd/xal-2.0/xAL.xsd
19
Example: Geo::KML
Read KML
sub init($){ ... $self->declare(READER => 'kml'); $self;}
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');
name-space qualified!(empty prefix)
20
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);}
21
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');
22
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;}