<div dir="ltr">Hi Mark,<div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>Is there a cleaner way how to deal with such infinite recursion?</div><div><br></div><div>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<br></div><div><br></div><div>Both problems are better illustrated with example below:</div><div><br></div><div>Thanks </div><div><br></div><div>Roman Daniel </div><div><br></div><div><div>use strict;</div><div>use warnings;</div><div><br></div><div>use XML::Compile::Schema;</div><div>use XML::Compile::Util qw(pack_type);</div><div>use Data::Dump qw(pp);</div><div><br></div><div>sub get_xsi_type {</div><div> my ($elem) = @_;</div><div><br></div><div> my $type</div><div> = $elem->getAttributeNS( "<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>",</div><div> 'type' )</div><div> or return;</div><div><br></div><div> my ( $prefix, $localname )</div><div> = $type =~ /^(.*?):(.*)/ ? ( $1, $2 ) : ( '', $type );</div><div> my $ns = $elem->lookupNamespaceURI($prefix);</div><div> return pack_type( $ns, $localname );</div><div>}</div><div><br></div><div>my $TEST_NS = 'urn:testHook';</div><div>my $schema_txt = <<"END_SCHEMA";</div><div><schema targetNamespace="$TEST_NS"</div><div> xmlns="<a href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</a>"</div><div><span class="" style="white-space:pre">        </span>xmlns:me="$TEST_NS"</div><div><span class="" style="white-space:pre">        </span>elementFormDefault="qualified"></div><div><br></div><div><element name="env"></div><div> <complexType></div><div> <sequence></div><div> <element name="alfa" type="me:baseType" /></div><div> <element name="beta" type="anyType" /></div><div> </sequence></div><div> </complexType></div><div></element></div><div><br></div><div><complexType name="baseType"></div><div> <sequence></div><div> <element name="num_one" type="int" /></div><div> </sequence></div><div></complexType></div><div><br></div><div><complexType name="extType"></div><div> <complexContent></div><div> <extension base="me:baseType"></div><div> <sequence></div><div> <element name="num_two" type="int" /></div><div> </sequence></div><div> </extension></div><div> </complexContent></div><div></complexType></div><div><br></div><div></schema></div><div>END_SCHEMA</div><div><br></div><div>my $xc = XML::Compile::Schema->new( $schema_txt, allow_undeclared => 1 );</div><div><br></div><div><br></div><div>my $skip_elem;</div><div>my $hook_ok = sub {</div><div> my ( $elem, $args, $path, $type, $r ) = @_;</div><div><br></div><div> if ( not($skip_elem) and my $xsi_type = get_xsi_type($elem) ) {</div><div> my $type_reader = $xc->compileType(</div><div> READER => $xsi_type,</div><div> element => pack_type( $elem->namespaceURI, $elem->localname ),</div><div> );</div><div> $skip_elem = 1;</div><div> return $type_reader->($elem);</div><div> }</div><div> undef $skip_elem;</div><div> return $r->($elem);</div><div>};</div><div>my $hook_infinite = sub {</div><div> my ( $elem, $args, $path, $type, $r ) = @_;</div><div><br></div><div> if ( my $xsi_type = get_xsi_type($elem) ) {</div><div> my $type_reader = $xc->compileType(</div><div> READER => $xsi_type,</div><div> element => pack_type( $elem->namespaceURI, $elem->localname ),</div><div> );</div><div> return $type_reader->($elem);</div><div> }</div><div> return $r->($elem);</div><div>};</div><div>$xc->addHook(</div><div> action => 'READER',</div><div> replace => $hook_ok,</div><div>);</div><div><br></div><div>my $reader = $xc->compile( READER => pack_type( $TEST_NS, 'env' ) );</div><div>my $doc = XML::LibXML->new->parse_string(<<"END_XML");</div><div><me:env xmlns:me="$TEST_NS" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"></div><div> <me:alfa xsi:type="me:extType"></div><div><span class="" style="white-space:pre">        </span><me:num_one>12</me:num_one></div><div><span class="" style="white-space:pre">        </span><me:num_two>13</me:num_two></div><div> </me:alfa></div><div> <me:beta xsi:type="me:extType"></div><div><span class="" style="white-space:pre">        </span><me:num_one>14</me:num_one></div><div><span class="" style="white-space:pre">        </span><me:num_two>15</me:num_two></div><div> </me:beta></div><div></me:env></div><div>END_XML</div><div><br></div><div>my $struct = $reader->( $doc->documentElement );</div><div>pp($struct);</div><div><br></div></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">2015-11-23 9:55 GMT+01:00 Mark Overmeer <span dir="ltr"><<a href="mailto:mark@overmeer.net" target="_blank">mark@overmeer.net</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Hi Roman,<br>
<br>
* Roman Daniel (<a href="mailto:roman.daniel@davosro.cz">roman.daniel@davosro.cz</a>) [151122 19:08]:<br>
<span class="">> I have a schema (VMWare webservices, with urn:vim25 namespace) which have<br>
> some elements defined as xsd:anyType<br>
<br>
</span><span class="">> <element name="val" type="xsd:anyType" /><br>
</span><span class="">> <val xsi:type="ManagedEntityStatus">green</val><br>
<br>
</span>The ugliness of anyType combined with the ugliness of xsi:type! Argggg!<br>
Haven't seen that before.<br>
<span class=""><br>
> When I read XML elements based on such schema, those elements (val above),<br>
> are left untranslated and appears in the resulting structure<br>
> as original XML::LibXML elements. I understand this and do not expect<br>
> XML::Compile to behave differently.<br>
<br>
</span>That's the default behavior of the anyType handler, yes.<br>
<span class=""><br>
> What I want is to translate those "xsd:anyType" elements manually, either<br>
> via hook or by traversing the result structure and compiling those<br>
> untranslated elements with another call of a new reader.<br>
<br>
</span>There exists logic to decode <any> elements, but not for anyType elements.<br>
Yes, a hook will probably work.<br>
<span class=""><br>
> Since all of these elements always come with a type I thought that would be<br>
> nice to create a new reader for the type,<br>
> say "{urn:vim25}ManagedEntityStatus".<br>
><br>
> my $reader = $xml_schema->compile(READER =><br>
> "{urn:vim25}ManagedEntityStatus");<br>
<br>
</span>Why are you not using<br>
my $r = $schema->reader("{urn:vim25}ManagedEntityStatus");<br>
<br>
or $schema->addPrefixes(vm => 'urn:vim25');<br>
my $r = $schema->reader("vm:ManagedEntityStatus");<br>
<br>
It will cash the compiled handlers for you.<br>
<span class=""><br>
> with the meaning read the element, translate its content and attributes<br>
> according to XML type, regardless of element name.<br>
> But to create such $reader is not possible.<br>
<br>
</span>Of course it is possible... whether it is supported is a different<br>
question ;-)<br>
<span class=""><br>
> So the only other way I can imagine is to:<br>
><br>
> 1) add a new fake XML schema to my $xml_schema<br>
><br>
> <xsd:schema xmlns:xsd="<a href="http://www.w3.org/2001/XMLSchema" rel="noreferrer" target="_blank">http://www.w3.org/2001/XMLSchema</a>"<br>
> xmlns:tns="urn:myNonsenseSchema"<br>
> xmlns:orig="urn:vim25"<br>
> targetNamespace="urn:myNonsenseSchema"<br>
> elementFormDefault="qualified"><br>
> <xsd:element name="ManagedEntityStatus" type="orig:ManagedEntityStatus"/><br>
> </xsd:element><br>
><br>
> creating an element for the type.<br>
<br>
</span>This is the trick used by $schema->compileType<br>
Don't hessitate to ask for more details.<br>
<span class="HOEnZb"><font color="#888888">--<br>
Regards,<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
MarkOv<br>
<br>
------------------------------------------------------------------------<br>
Mark Overmeer MSc MARKOV Solutions<br>
Mark@Overmeer.net <a href="mailto:solutions@overmeer.net">solutions@overmeer.net</a><br>
<a href="http://Mark.Overmeer.net" rel="noreferrer" target="_blank">http://Mark.Overmeer.net</a> <a href="http://solutions.overmeer.net" rel="noreferrer" target="_blank">http://solutions.overmeer.net</a><br>
<br>
</div></div></blockquote></div><br></div>