220 likes | 435 Views
From XML (schema) to Application. From XML (schema) to Application. I HATE XML. 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
E N D
From XML (schema) to Application I HATE XML
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!
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
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);
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;
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);
XML::Compile::Schema • Collects information from all used schema's • Organizes compilation • X::C::Translate, with back-ends • X::C::T::Reader XML → HASH • X::C::T::Writer HASH → XML • X::C::T::Template example generator • built-in types • name-space administration • Compilation results in code-refs
XML::Compile::Cache • Extends X::C::Schema • compiled code-ref management • compile option management • pre-compile for daemons orcompile-on-demand single shot • use of prefixes
XML::Compile::Cache • Extends X::C::Schema • compiled code-ref management • compile option management • pre-compile for daemons orcompile-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);
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);
Other modules for XML::Compile • XML::Compile::SOAP11XML::Compile::WSDL11 • XML::Compile::SOAP::Daemonbased 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;
Other modules for XML::Compile • XML::Compile::Tester • XML::Compile::Dumper • XML::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 ...
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
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;
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');
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); ...
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
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; name-space qualified! (empty prefix) use Geo::KML; my ($type, $data) = Geo::KML->readKML('points.kmz');
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); }
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');
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; }