[Xml-compile] Reading (hooks) according to xsi:type without xsi:type hierarchy
Roman Daniel
roman.daniel at davosro.cz
Thu Nov 26 11:29:27 GMT 2015
Hi Mark,
thanks for the answer. It works. I do not understand how could I overlook
compileType. Notice it earlier could have saved me from tens of XPaths.
There is only one minor problem. The element with xsi:Type can be defined
in the schema either as xs:anyType or as a base type. So I decided to use
replace hook and for each element to check xsi:type first. If there is a
xsi:type I will create new reader, otherwise I use the reader passed to the
hook. But if I create a new reader and call it from the hook, the hook is
called again, again, and again. So I need to come up with a cumbersome
solution how to skip the invocation of reader based on xsi:type when I am
already in the reader based on xsi:type.
Is there a cleaner way how to deal with such infinite recursion?
Also if I use reader instead of compile, compileType I will end up with
error message: cannot find element or attribute `{urn:testHook}extType' at
me:extType
Both problems are better illustrated with example below:
Thanks
Roman Daniel
use strict;
use warnings;
use XML::Compile::Schema;
use XML::Compile::Util qw(pack_type);
use Data::Dump qw(pp);
sub get_xsi_type {
my ($elem) = @_;
my $type
= $elem->getAttributeNS( "http://www.w3.org/2001/XMLSchema-instance
",
'type' )
or return;
my ( $prefix, $localname )
= $type =~ /^(.*?):(.*)/ ? ( $1, $2 ) : ( '', $type );
my $ns = $elem->lookupNamespaceURI($prefix);
return pack_type( $ns, $localname );
}
my $TEST_NS = 'urn:testHook';
my $schema_txt = <<"END_SCHEMA";
<schema targetNamespace="$TEST_NS"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:me="$TEST_NS"
elementFormDefault="qualified">
<element name="env">
<complexType>
<sequence>
<element name="alfa" type="me:baseType" />
<element name="beta" type="anyType" />
</sequence>
</complexType>
</element>
<complexType name="baseType">
<sequence>
<element name="num_one" type="int" />
</sequence>
</complexType>
<complexType name="extType">
<complexContent>
<extension base="me:baseType">
<sequence>
<element name="num_two" type="int" />
</sequence>
</extension>
</complexContent>
</complexType>
</schema>
END_SCHEMA
my $xc = XML::Compile::Schema->new( $schema_txt, allow_undeclared => 1 );
my $skip_elem;
my $hook_ok = sub {
my ( $elem, $args, $path, $type, $r ) = @_;
if ( not($skip_elem) and my $xsi_type = get_xsi_type($elem) ) {
my $type_reader = $xc->compileType(
READER => $xsi_type,
element => pack_type( $elem->namespaceURI, $elem->localname ),
);
$skip_elem = 1;
return $type_reader->($elem);
}
undef $skip_elem;
return $r->($elem);
};
my $hook_infinite = sub {
my ( $elem, $args, $path, $type, $r ) = @_;
if ( my $xsi_type = get_xsi_type($elem) ) {
my $type_reader = $xc->compileType(
READER => $xsi_type,
element => pack_type( $elem->namespaceURI, $elem->localname ),
);
return $type_reader->($elem);
}
return $r->($elem);
};
$xc->addHook(
action => 'READER',
replace => $hook_ok,
);
my $reader = $xc->compile( READER => pack_type( $TEST_NS, 'env' ) );
my $doc = XML::LibXML->new->parse_string(<<"END_XML");
<me:env xmlns:me="$TEST_NS" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance">
<me:alfa xsi:type="me:extType">
<me:num_one>12</me:num_one>
<me:num_two>13</me:num_two>
</me:alfa>
<me:beta xsi:type="me:extType">
<me:num_one>14</me:num_one>
<me:num_two>15</me:num_two>
</me:beta>
</me:env>
END_XML
my $struct = $reader->( $doc->documentElement );
pp($struct);
2015-11-23 9:55 GMT+01:00 Mark Overmeer <mark at overmeer.net>:
>
> Hi Roman,
>
> * Roman Daniel (roman.daniel at davosro.cz) [151122 19:08]:
> > I have a schema (VMWare webservices, with urn:vim25 namespace) which have
> > some elements defined as xsd:anyType
>
> > <element name="val" type="xsd:anyType" />
> > <val xsi:type="ManagedEntityStatus">green</val>
>
> The ugliness of anyType combined with the ugliness of xsi:type! Argggg!
> Haven't seen that before.
>
> > When I read XML elements based on such schema, those elements (val
> above),
> > are left untranslated and appears in the resulting structure
> > as original XML::LibXML elements. I understand this and do not expect
> > XML::Compile to behave differently.
>
> That's the default behavior of the anyType handler, yes.
>
> > What I want is to translate those "xsd:anyType" elements manually, either
> > via hook or by traversing the result structure and compiling those
> > untranslated elements with another call of a new reader.
>
> There exists logic to decode <any> elements, but not for anyType elements.
> Yes, a hook will probably work.
>
> > Since all of these elements always come with a type I thought that would
> be
> > nice to create a new reader for the type,
> > say "{urn:vim25}ManagedEntityStatus".
> >
> > my $reader = $xml_schema->compile(READER =>
> > "{urn:vim25}ManagedEntityStatus");
>
> Why are you not using
> my $r = $schema->reader("{urn:vim25}ManagedEntityStatus");
>
> or $schema->addPrefixes(vm => 'urn:vim25');
> my $r = $schema->reader("vm:ManagedEntityStatus");
>
> It will cash the compiled handlers for you.
>
> > with the meaning read the element, translate its content and attributes
> > according to XML type, regardless of element name.
> > But to create such $reader is not possible.
>
> Of course it is possible... whether it is supported is a different
> question ;-)
>
> > So the only other way I can imagine is to:
> >
> > 1) add a new fake XML schema to my $xml_schema
> >
> > <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
> > xmlns:tns="urn:myNonsenseSchema"
> > xmlns:orig="urn:vim25"
> > targetNamespace="urn:myNonsenseSchema"
> > elementFormDefault="qualified">
> > <xsd:element name="ManagedEntityStatus" type="orig:ManagedEntityStatus"/>
> > </xsd:element>
> >
> > creating an element for the type.
>
> This is the trick used by $schema->compileType
> Don't hessitate to ask for more details.
> --
> Regards,
>
> MarkOv
>
> ------------------------------------------------------------------------
> Mark Overmeer MSc MARKOV Solutions
> Mark at Overmeer.net solutions at overmeer.net
> http://Mark.Overmeer.net http://solutions.overmeer.net
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.scsys.co.uk/pipermail/xml-compile/attachments/20151126/4434253a/attachment.htm>
More information about the Xml-compile
mailing list