Commits

Anonymous committed c84b994

structured errors branch:

- this commits my last copy of the structerror branch
(with Christian's adaptations for the new callback interface)
- many tests fail but this version is closer to the trunk

Comments (0)

Files changed (13)

 Revision history for Perl extension XML::LibXML
 
+1.59
+   - PP: fixed weired 2 -> c2 typo in dom.c
+
+   - refactored the input callback interface (1.60)
+   - implemented support for libxml2's structured errors
+   - cleaned up the test cases
+   - fixed a bunch of bugs from rt.cpan.org.
+
 1.58
    - fixed a pointer initialization in parse_xml_chunk(), fixes 
      random several segmentation faults on document fragments.
     if ( defined $self->{XML_LIBXML_EXPAND_XINCLUDE}
          and  $self->{XML_LIBXML_EXPAND_XINCLUDE} == 1 ) {
         $self->{_State_} = 1;
-        eval { $self->processXIncludes($result); };
+        eval { 
+            $self->processXIncludes($result); 
+        };
         my $err = $@;
         $self->{_State_} = 0;
         if ($err) {
     $self->{_State_} = 1;
     my $result;
     my $err;
+
     if ( defined $self->{SAX} ) {
+        $self->{SAX_ELSTACK} = [];
         my $string = shift;
-        $self->{SAX_ELSTACK} = [];
         eval {
+            XML::LibXML::Error::_init_error();
             $result = $self->_parse_sax_string($string); 
             XML::LibXML::Error::_report_error( );
         };
+        $self->{_State_} = 0;
 
-        $err = $@;
-        $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
+        unless ( XML::LibXML::HAVE_STRUCT_ERRORS() 
+                 && $self->{XML_LIBXML_RECOVER} ) {
+            $err = $@;
+            if ($err) {
+                croak $err;
+            }
         }
     }
     else {
         eval { 
+            XML::LibXML::Error::_init_error();
             $result = $self->_parse_string( @_ );
             XML::LibXML::Error::_report_error();
         };
 
-        $err = $@;
         $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
+
+        unless ( XML::LibXML::HAVE_STRUCT_ERRORS() 
+                 && $self->{XML_LIBXML_RECOVER} ) {
+        #unless ( $self->{XML_LIBXML_RECOVER} ) {
+            $err = $@;
+            if ($err) {
+                croak $err;
+            }
         }
-        else {
-            $result = $self->_auto_expand( $result, 
-                                           $self->{XML_LIBXML_BASE_URI} );
-        }
+
+        $result = $self->_auto_expand( $result, 
+                                       $self->{XML_LIBXML_BASE_URI} );
     }
 
     return $result;
     my $result;
     if ( defined $self->{SAX} ) {
         $self->{SAX_ELSTACK} = [];
-        eval { $self->_parse_sax_fh( @_ );  };
-        my $err = $@;
-        $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
+        eval { 
+            XML::LibXML::Error::_init_error();
+            $self->_parse_sax_fh( @_ );  
+            XML::LibXML::Error::_report_error();
+        };
+
+        unless ( XML::LibXML::HAVE_STRUCT_ERRORS()
+                 && $self->{XML_LIBXML_RECOVER} ) {
+        #unless ( $self->{XML_LIBXML_RECOVER} ) {
+            my $err = $@;
+            $self->{_State_} = 0;
+            if ($err) {
+                croak $err;
+            }
         }
     }
     else {
-        eval { $result = $self->_parse_fh( @_ ); };
-        my $err = $@;
-        $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
+        eval { 
+            XML::LibXML::Error::_init_error();
+            $result = $self->_parse_fh( @_ ); 
+            XML::LibXML::Error::_report_error();
+        };
+        unless ( XML::LibXML::HAVE_STRUCT_ERRORS() 
+                 && $self->{XML_LIBXML_RECOVER} ) {
+        #unless ( $self->{XML_LIBXML_RECOVER} ) {
+            my $err = $@;
+            $self->{_State_} = 0;
+            if ($err) {
+                croak $err;
+            }
         }
 
         $result = $self->_auto_expand( $result, $self->{XML_LIBXML_BASE_URI} );
     my $result;
     if ( defined $self->{SAX} ) {
         $self->{SAX_ELSTACK} = [];
-        eval { $self->_parse_sax_file( @_ );  };
-        my $err = $@;
-        $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
+        eval {
+            XML::LibXML::Error::_init_error();
+            $self->_parse_sax_file( @_ );
+            XML::LibXML::Error::_report_error();
+        };
+        unless ( XML::LibXML::HAVE_STRUCT_ERRORS() 
+                 && $self->{XML_LIBXML_RECOVER} ) {
+        #unless ( $self->{XML_LIBXML_RECOVER} ) {
+            my $err = $@;
+            $self->{_State_} = 0;
+            if ($err) {
+                croak $err;
+            }
         }
+
     }
     else {
-        eval { $result = $self->_parse_file(@_); };
-        my $err = $@;
-        $self->{_State_} = 0;
-        if ($err) {
-            croak $err;
-        }
+        eval { 
+            XML::LibXML::Error::_init_error();
+            $result = $self->_parse_file(@_); 
+            XML::LibXML::Error::_report_error();
+        };
+        #unless ( $self->{XML_LIBXML_RECOVER} ) {
+            my $err = $@;
+            $self->{_State_} = 0;
+            if ($err) {
+                croak $err;
+            }
+        #}
 
         $result = $self->_auto_expand( $result );
     }
     }
 
     $self->{_State_} = 1;
-    if ( defined $self->{SAX} ) {
-        eval {
+    eval {
+        XML::LibXML::Error::_init_error();
+        if ( defined $self->{SAX} ) {
             $self->_parse_sax_xml_chunk( @_ );
 
             # this is required for XML::GenericChunk.
             unless ( $self->{IS_FILTER} ) {
                 $result = $self->{HANDLER}->end_document();
             }
-        };
-    }
-    else {
-        eval { $result = $self->_parse_xml_chunk( @_ ); };
-    }
+        }
+        else {
+            $result = $self->_parse_xml_chunk( @_ ); 
+        }
+        XML::LibXML::Error::_report_error();
+    };
 
-    my $err = $@;
-    $self->{_State_} = 0;
-    if ($err) {
-        croak $err;
+    unless ( XML::LibXML::HAVE_STRUCT_ERRORS() 
+                 && $self->{XML_LIBXML_RECOVER} ) {
+    #unless ( $self->{XML_LIBXML_RECOVER} ) {
+        my $err = $@;
+        $self->{_State_} = 0;
+        if ($err) {
+            croak $err;
+        }
     }
 
     return $result;
 sub processXIncludes {
     my $self = shift;
     my $doc = shift;
-    return $self->_processXIncludes($doc || " ");
+    my $retval; 
+    eval {
+        XML::LibXML::Error::_init_error();
+        $retval =  $self->_processXIncludes($doc || " ");
+        XML::LibXML::Error::_report_error();
+    };
+    if ( $@ ) {
+        croak $@;
+    }
+    return $retval;
 }
 
 # perl style
 sub process_xincludes {
     my $self = shift;
     my $doc = shift;
-    return $self->_processXIncludes($doc || " ");
+    return $self->processXIncludes($doc);
 }
 
 
         delete $self->{CONTEXT};
     }
 
-    if ( defined $self->{SAX} ) {
-        $self->{CONTEXT} = $self->_start_push(1);
-    }
-    else {
-        $self->{CONTEXT} = $self->_start_push(0);
+    eval {
+        XML::LibXML::Error::_init_error();
+        if ( defined $self->{SAX} ) {
+            $self->{CONTEXT} = $self->_start_push(1);
+        }
+        else {
+            $self->{CONTEXT} = $self->_start_push(0);
+        }
+        XML::LibXML::Error::_report_error();
+    };
+
+    if ( $@ ) {
+        croak($@);
     }
 }
 
     }
 
     foreach ( @_ ) {
-        $self->_push( $self->{CONTEXT}, $_ );
+        eval {
+            XML::LibXML::Error::_init_error();
+            $self->_push( $self->{CONTEXT}, $_ );
+            XML::LibXML::Error::_report_error();
+        };
+        croak $@ if $@;
     }
 }
 
     }
 
     if ( defined $chunk and length $chunk ) {
-        $self->_push( $self->{CONTEXT}, $chunk );
+        $self->push( $chunk );
     }
 
     if ( $terminate ) {
     my $self = shift;
     my $restore = shift || 0;
     return undef unless defined $self->{CONTEXT};
-
+    
     my $retval;
-
-    if ( defined $self->{SAX} ) {
-        eval {
+    
+    eval {
+        XML::LibXML::Error::_init_error();
+          
+        if ( defined $self->{SAX} ) {
             $self->_end_sax_push( $self->{CONTEXT} );
             $retval = $self->{HANDLER}->end_document( {} );
-        };
-    }
-    else {
-        eval { $retval = $self->_end_push( $self->{CONTEXT}, $restore ); };
-    }
+        }
+        else {
+            $retval = $self->_end_push( $self->{CONTEXT}, $restore ); 
+        }
+       XML::LibXML::Error::_report_error(); 
+    };
 
     delete $self->{CONTEXT};
 
-    if ( $@ ) {
-        croak( $@ );
+    if ( $restore == 0 ) {
+        if ( $@ ) {
+            croak( $@ );
+        }
     }
+
     return $retval;
 }
 
 
 sub findnodes {
     my ($node, $xpath) = @_;
-    my @nodes = $node->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$node->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
+
     if (wantarray) {
         return @nodes;
     }
 
 sub find {
     my ($node, $xpath) = @_;
-    my ($type, @params) = $node->_find($xpath);
+    XML::LibXML::Error::_init_error();
+    my ($type, @params) = @{$node->_find($xpath)};
+    XML::LibXML::Error::_report_error( );
     if ($type) {
         return $type->new(@params);
     }
 sub getElementsByTagName {
     my ( $doc , $name ) = @_;
     my $xpath = "descendant-or-self::node()/$name";
-    my @nodes = $doc->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$doc->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
-sub  getElementsByTagNameNS {
+sub getElementsByTagNameNS {
     my ( $doc, $nsURI, $name ) = @_;
     my $xpath = "descendant-or-self::*[local-name()='$name' and namespace-uri()='$nsURI']";
-    my @nodes = $doc->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$doc->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
 sub getElementsByLocalName {
     my ( $doc,$name ) = @_;
     my $xpath = "descendant-or-self::*[local-name()='$name']";
-    my @nodes = $doc->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$doc->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
     return ($doc->findnodes( "id('$id')" ))[0];
 }
 
+sub validate {
+    my $self = shift;
+    XML::LibXML::Error::_init_error();
+    my $rv = $self->_validate(@_);
+    XML::LibXML::Error::_report_error();
+    return $rv;
+}
+
 1;
 
 #-------------------------------------------------------------------------#
 sub getElementsByTagName {
     my ( $node , $name ) = @_;
     my $xpath = "descendant::$name";
-    my @nodes = $node->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{ $node->_findnodes($xpath) };
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
 sub  getElementsByTagNameNS {
     my ( $node, $nsURI, $name ) = @_;
     my $xpath = "descendant::*[local-name()='$name' and namespace-uri()='$nsURI']";
-    my @nodes = $node->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$node->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
 sub getElementsByLocalName {
     my ( $node,$name ) = @_;
     my $xpath = "descendant::*[local-name()='$name']";
-        my @nodes = $node->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$node->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
 sub getChildrenByTagNameNS {
     my ( $node, $nsURI, $name ) = @_;
     my $xpath = "*[local-name()='$name' and namespace-uri()='$nsURI']";
-    my @nodes = $node->_findnodes($xpath);
+    XML::LibXML::Error::_init_error();
+    my @nodes = @{$node->_findnodes($xpath)};
+    XML::LibXML::Error::_report_error( );
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
     my %args = @_;
 
     my $self = undef;
+    XML::LibXML::Error::_init_error();
     if ( defined $args{location} ) {
         $self = $class->parse_location( $args{location} );
     }
     elsif ( defined $args{DOM} ) {
         $self = $class->parse_document( $args{DOM} );
     }
+    XML::LibXML::Error::_report_error();
+    return $self;
+}
 
-    return $self;
+sub validate {
+    my $self = shift;
+    XML::LibXML::Error::_init_error();
+    my $rv = $self->_validate(@_);
+    XML::LibXML::Error::_report_error();
+    return $rv;
 }
 
 1;
     my $class = shift;
     my %args = @_;
 
-    my $self = undef;
+    XML::LibXML::Error::_init_error();
+    my $self;
     if ( defined $args{location} ) {
         $self = $class->parse_location( $args{location} );
     }
     elsif ( defined $args{string} ) {
         $self = $class->parse_buffer( $args{string} );
     }
+    XML::LibXML::Error::_report_error();
 
     return $self;
 }
 
+sub validate {
+    my $self = shift;
+    XML::LibXML::Error::_init_error();
+    my $rv = $self->_validate(@_);
+    XML::LibXML::Error::_report_error();
+    return $rv;
+}
+
 1;
 
 __END__
 #include <libxml/xmlschemas.h>
 #endif
 
+#if LIBXML_VERSION >= 20600
+#define HAVE_SERRORS 1
+#endif
+
 #ifdef LIBXML_CATALOG_ENABLED
 #include <libxml/catalog.h>
 #endif
 
     SvREFCNT_dec(sv);
 }
-
 #ifdef HAVE_SERRORS
 void
 LibXML_struct_error_handler(void * userData, xmlErrorPtr error )
 
     if ( SvTRUE(ERRSV) ) {
         croak( "DIE: %s", SvPV_nolen(ERRSV) );
-        POPs;
     }
-
+    POPs;
+
+    PUTBACK;
     FREETMPS;
     LEAVE;
 }
 void
 LibXML_dummy_handler(void * ctxt, const char * msg, ...)
 {
+
+  dTHX;
+    va_list args;
+    SV * sv;
+    sv = NEWSV(0,512);
+
+    va_start(args, msg);
+    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+
+    warn("got flat error %s\n",SvPV_nolen(sv));
+
+    SvREFCNT_dec(sv);
+
+
     return;
 }
 
 #ifdef HAVE_SERRORS
     xmlSetGenericErrorFunc(NULL, LibXML_dummy_handler);
     xmlSetStructuredErrorFunc(NULL,
-			      (xmlStructuredErrorFunc)LibXML_struct_error_handler);
+    		      (xmlStructuredErrorFunc)LibXML_struct_error_handler);
+
     LibXML_error = &PL_sv_undef;
 #else
     LibXML_error = NEWSV(0, 512);
 LibXML_report_error(SV * saved_error, int recover)
 {
 #ifdef HAVE_SERRORS
-   /* if (LibXML_error_OK) {
+    /* if HAVE_SERRORS is defined, XML::LibXML uses Perl level 
+     * Error reporting. 
+     * On C level we just take care on code consistency.
+     */
+    SvREFCNT_dec(LibXML_error);
+    LibXML_error = saved_error;
+#else
+    SV *my_error = LibXML_error;
+    LibXML_error = saved_error;
+    if ( SvCUR( my_error ) > 0 ) {
         if ( recover ) {
-            if ( recover == 1 ) {
+            /* this check is required, otherwise parsing a valid doc 
+             * in recover mode will cause segmentation faults 
+             */
+            if ( LibXML_error && SvCUR(LibXML_error) && recover == 1 ) {
                 warn("%s",SvPV_nolen(LibXML_error));
             }
             SvREFCNT_dec(LibXML_error);
             LibXML_error = saved_error;
         } else {
-            SV* perl_err_var;
-            perl_err_var = get_sv("@", TRUE);
-            sv_setsv(perl_err_var, LibXML_error);
-            LibXML_error = saved_error;
-            croak(Nullch);
-        }
-    } else {
-        LibXML_error = saved_error;
-    } */
-#else
-    SV *my_error = sv_2mortal(LibXML_error);
-    LibXML_error = saved_error;
-    if ( SvCUR( my_error ) > 0 ) {
-        if ( recover ) {
-            if ( recover == 1 ) {
-                warn("%s", SvPV_nolen(my_error));
-            }
-        } else {
             croak("%s", SvPV_nolen(my_error));
         }
     }
                               (xmlInputCloseCallback) LibXML_input_close);
 #ifdef HAVE_SERRORS
     xmlSetStructuredErrorFunc( NULL ,
-                               (xmlStructuredErrorFunc)LibXML_serror_handler);
+                               (xmlStructuredErrorFunc)LibXML_struct_error_handler);
 #else
     xmlSetGenericErrorFunc(NULL , NULL);
 #endif /* HAVE_SERRORS */
         RETVAL
 
 
+int
+HAVE_STRUCT_ERRORS()
+    CODE:
+#ifdef HAVE_SERRORS
+        RETVAL = 1;
+#else
+        RETVAL = 0;
+#endif
+    OUTPUT:
+        RETVAL
+
 void
 END()
     CODE:
                 xmlFreeDoc(real_doc);
             }
         }
-
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
         LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
+
 int
 _parse_sax_string(self, string)
         SV * self
         LibXML_report_error(saved_error, recover);
 
         if ( RETVAL < 0 ) {
-            croak( "unknown error during XInclude processing" );
+            /* croak( "unknown error during XInclude processing" );*/
             XSRETURN_UNDEF;
         } else if ( RETVAL == 0 ) {
             RETVAL = 1;
         LibXML_report_error(saved_error, recover);
 
         if ( ctxt->wellFormed == 0 ) {
-            croak( "XML not well-formed in xmlParseChunk" );
+            /* croak( "XML not well-formed in xmlParseChunk" ); */
             XSRETURN_UNDEF;
         }
         RETVAL = 1;
         RETVAL
 
 int
-validate(self, ...)
+_validate(self, ...)
         xmlDocPtr self
     PREINIT:
         SV * saved_error;
         RETVAL
 
 
-void
+AV*
 _find( pnode, pxpath )
         SV* pnode
         SV * pxpath
             croak( "empty XPath found" );
             XSRETURN_UNDEF;
         }
-    PPCODE:
+    CODE:
         if ( node->doc ) {
             domNodeNormalize( xmlDocGetRootElement( node->doc ) );
         }
 
         LibXML_init_error(&saved_error);
 
+        RETVAL = newAV();
+        /* This is required due a bug in perl; 
+         * see section "Returning SVs, AVs and HVs through RETVAL" 
+         * in perlxs
+         * Also note, that scalars which are pushed into the array
+         * must not be sv_2mortal()ed anymore.
+         */
+        sv_2mortal((SV*)RETVAL);
+
         found = domXPathFind( node, xpath );
         xmlFree( xpath );
 
                 case XPATH_NODESET:
                     /* return as a NodeList */
                     /* access ->nodesetval */
-                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
+                    av_push(RETVAL, newSVpv("XML::LibXML::NodeList", 0));
                     nodelist = found->nodesetval;
                     if ( nodelist ) {
                         if ( nodelist->nodeNr > 0 ) {
                                 else {
                                     element = PmmNodeToSv(tnode, owner);
                                 }
-
-                                XPUSHs( sv_2mortal(element) );
+                                av_push( RETVAL, element );
                             }
                         }
                         xmlXPathFreeNodeSet( found->nodesetval );
                 case XPATH_BOOLEAN:
                     /* return as a Boolean */
                     /* access ->boolval */
-                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
-                    XPUSHs(sv_2mortal(newSViv(found->boolval)));
+                    av_push(RETVAL, newSVpv("XML::LibXML::Boolean", 0));
+                    av_push(RETVAL, newSViv(found->boolval));
                     break;
                 case XPATH_NUMBER:
                     /* return as a Number */
                     /* access ->floatval */
-                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
-                    XPUSHs(sv_2mortal(newSVnv(found->floatval)));
+                    av_push(RETVAL, newSVpv("XML::LibXML::Number", 0));
+                    av_push(RETVAL, newSVnv(found->floatval));
                     break;
                 case XPATH_STRING:
                     /* access ->stringval */
                     /* return as a Literal */
-                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
-                    XPUSHs(sv_2mortal(C2Sv(found->stringval, NULL)));
+                    av_push(RETVAL, newSVpv("XML::LibXML::Literal", 0));
+                    av_push(RETVAL, C2Sv(found->stringval, NULL));
                     break;
                 default:
                     croak("Unknown XPath return type");
             }
             xmlXPathFreeObject(found);
         }
-
+    OUTPUT:
+        RETVAL
+    CLEANUP:
         LibXML_report_error(saved_error, 0);
 
-void
+AV*
 _findnodes( pnode, perl_xpath )
         SV* pnode
         SV * perl_xpath
             croak( "empty XPath found" );
             XSRETURN_UNDEF;
         }
-    PPCODE:
+    CODE:
         if ( node->doc ) {
             domNodeNormalize( xmlDocGetRootElement(node->doc ) );
         }
         }
 
         LibXML_init_error(&saved_error);
+        
+        RETVAL = newAV();
+        /* This is required due a bug in perl; 
+         * see section "Returning SVs, AVs and HVs through RETVAL" 
+         * in perlxs
+         * Also note, that scalars which are pushed into the array
+         * must not be sv_2mortal()ed anymore.
+         */
+        sv_2mortal((SV*)RETVAL);
 
         nodelist = domXPathSelect( node, xpath );
         xmlFree(xpath);
                     else {
                         element = PmmNodeToSv(tnode, owner);
                     }
-
-                    XPUSHs( sv_2mortal(element) );
+                    av_push(RETVAL, element );
                 }
             }
             xmlXPathFreeNodeSet( nodelist );
         }
-
+    OUTPUT:
+        RETVAL
+    CLEANUP:
         LibXML_report_error(saved_error, 0);
 
 void
         RETVAL
 
 int
-validate( self, doc )
+_validate( self, doc )
         xmlRelaxNGPtr self
         xmlDocPtr doc
     PREINIT:
 
 
 int
-validate( self, doc )
+_validate( self, doc )
         xmlSchemaPtr self
         xmlDocPtr doc
     PREINIT:
 t/20extras.t
 t/23rawfunctions.t
 t/24c14n.t
+t/25relaxng.t
+t/29_struct_errors.t
 lib/XML/LibXML/NodeList.pm
 lib/XML/LibXML/Literal.pm
 lib/XML/LibXML/Boolean.pm
 lib/XML/LibXML/Parser.pod
 lib/XML/LibXML/PI.pod
 LibXML.pod
+test/relaxng/demo.rng
+test/relaxng/demo2.rng
+test/relaxng/demo3.rng
+test/relaxng/demo.xml
+test/relaxng/invaliddemo.xml
+test/relaxng/schema.rng
+test/relaxng/badschema.rng
+META.yml                                 Module meta-data (added by MakeMaker)
-Ok, I don't implement namespace handling yet. 
+Removed the very old changes in VERSION 1.59
 
-But I introduced the node types in XML::LibXML and by default I 
-export them. I am aware this is not very beautyfull -- well, the 
-way it's done ... 
+$Id$
 
-Since most functions need more than just a simple call to libxml2
-I wrapped them in dom.c. I believe this is a better way than just put
-the whole code in the XS file.
+from now on this file holds some notes on my XS learning curve.
 
-Then I patched LibXML.xs and added the parts
- XML::LibXML::Node 
- XML::LibXML::Element
- XML::LibXML::Text
- XML::LibXML::Comment
- XML::LibXML::CDATASection
-As well some extra functions in XML::LibXML::Document.
 
-Common node related functions are implemented in XML::LibXML::Node, 
-so only specialized functions had to be reimplemented for sublevel 
-classes. 
-
-I treat XML::LibXML::Text as the CharacterData Class from the 
-DOM spec. Since libxml2 implements all character classes slightly
-different, each constructor had to be implemented seperatly.
-
-This implementation is aware about all subclasses that are supported:
-The CLASS Constant is set depending on the type of the node currently 
-handled. Differently to the previous implementation it does not 
-coredump that much any more. ;-)
-
-As well I added a chunk of documentation and a new example.
-
-_VERSION_F_ (05.17.2001)
-
-code cleanup and better documentation
-"dom.h" , "dom.c" are both much smaller after I removed redundant code
-"dom.c" is sorted analogue to "dom.h"
-
-all documentation about my extensions can be found in "examples/libxml.xml"
-the script "examples/xml2pod.pl" will transform this XML document into 
-various .pod documents.  
-better testing the encoding
-
-
-_VERSION_D_
-
-added nodelist functions 
-and 
-element->getElementsByTagName 
-
-
-_VERSION_C_
-
-the current version includes some securety fixes in dom.c and LibXML.xs
-
-also a better testsuite
-
--- LibXML.xs_1.22
-
-completed function setAttributeNode
-added function getAttributes 
-added function getAttributesNS
-
-more node security fixes 
-
-these functions will return an array of attribute nodes.
-both will probably renamed before i make them public
-
-
-idea: global encoding constant, so all user input will be encoded from
-that encoding to utf8 INTERNALLY
-
-todo: add xmlEncodeEntitiesReentrant for all text content
-
-dom.h/dom.c
-
-introduced domSetAttributeNode
-cleaned the test suite
-
-LibXML.xs_1.23
-    + getOwner returns the Owner Node (root of the subtree)
-      of the current element 
-    + getOwnerDocument returns the Owner document of the node if any 
-    + proxy fixes
-    + introduced documentfragment
-      i will allways create a document fragment for EACH unbound node.
-      made the documentFragment a node 
-    + more securety checks and less memory leaks...
-    + better array handling
-    + DOM L2 conform naming (optional)
-    + entity encoding fixed
-
-dom.c_1.21
-   + domsetnodevalue is aware of attributes as well
-   + domreplacenode introduced
-   + added internal function insert_node_to_nodelist
-
-t/06nodetypes.t
-   + document_fragment tests 
-
-VERSION 1.01
-
-   + multiple parser layer (it looks like overkill but it is not!)
-   + on the fly XInclude expanding while parsing
-
    o past 2.4.20: tested; working.
    o 2.4.25: tested; not working
    o past 2.4.25: tested, working
-   o past 2.5.0: tested; working
+   o past 2.5.0: tested; brocken Attribute handling
    o version 2.5.5: tested; tests pass, but known as broken
    o up to version 2.5.11: tested; working
    o version 2.6.0: tested; not working
    o version 2.6.3: tested; not working
    o version 2.6.4: tested; not working (XML Schema errors)
    o version 2.6.5: tested; not working (broken XIncludes)
-   o up to version 2.6.7: tested; working
+   o up to version 2.6.8: tested; working
 
 It happens, that an older version of libxml2 passes all tests under certain
 conditions. This is no reason to assume that version to work on all platforms.
 10.2.2. Since I don't have full access to this OS, help/ patches from OS X
 gurus are highly apprecheated.
 
-It is confirmed that XML::LibXML builds and runs without problems with Mac OS X
-10.2.6.
+It is confirmed that XML::LibXML builds and runs without problems since Mac OS
+X 10.2.6.
 
 
 Notes for HPUX
 CONTACT
 =======
 
-For suggestions, bugreports etc. you may contact the maintainer directly
+For suggestions etc. you may contact the maintainer directly
 christian.glahn@uibk.ac.at
 
+For bug reports, please use the CPAN request tracker on
+http://rt.cpan.org/NoAuth/Bugs.html?Dist=XML-LibXML
+
 Also XML::LibXML issues are discussed among other things on the perl XML
 mailing list (perl-xml@listserv.ActiveState.com). In case of problems you
 should check the archives of that list first. Many problems are already
 
 0.98 > Version > 1.49 were maintained by Matt Sergeant and Christian Glahn
 
-Version >= 1.49 are maintained by Christian Glahn
+Versions >= 1.49 are maintained by Christian Glahn
+
+Versions > 1.56 are co-maintained by Petr Pajas
 
 
 PATCHES AND DEVELOPER VERSION
            cur->parent = p;
        }
        
-       if (c1 && 2 && c1!=leader) {
+       if (c1 && c2 && c1!=leader) {
            if ( leader ) {
                leader->next = c1;
 	       c1->prev = leader;

lib/XML/LibXML/Error.pm

 package XML::LibXML::Error;
 
 use strict;
-use vars qw($AUTOLOAD @error_domains $ERROR);
+use vars qw($AUTOLOAD @error_domains);
 use Carp;
 use overload
   '""' => \&as_string;
 		  "Relax-NG parser", "Relax-NG validity",
 		  "Catalog", "C14N", "XSLT", "validity");
 
+{ 
+    # internal callback routines
+    my $ERROR = undef;
 
-sub _callback_error {
-    my $xE = shift;
-
-    my $terr =bless {
-        domain  => $xE->domain(),
-        level   => $xE->level(),
-        code    => $xE->code(),
-        message => $xE->message(),
-        file    => $xE->file(),
-        line    => $xE->line(),
-        str1    => $xE->str1(),
-        str2    => $xE->str2(),
-        str3    => $xE->str3(),
-        int1    => $xE->num1(),
-        int2    => $xE->num2(),
-    }, "XML::LibXML::Error";
-
-    unless ( defined $terr->{file} and length $terr->{file} ) {
-        $terr->{file} = 'string()'; # make it easier to recognize parsed strings
+    sub _init_error {
+        $ERROR = undef;
     }
 
-    if ( defined $ERROR ) {
-        $terr->{prev} = $ERROR;
+    sub _callback_error {
+        my $xE = shift;
+	my $terr;
+	
+	if (ref($xE)) {
+	  $terr =bless {
+            domain  => $xE->domain(),
+            level   => $xE->level(),
+            code    => $xE->code(),
+            message => $xE->message(),
+            file    => $xE->file(),
+            line    => $xE->line(),
+            str1    => $xE->str1(),
+            str2    => $xE->str2(),
+            str3    => $xE->str3(),
+            num1    => $xE->num1(),
+            num2    => $xE->num2(),
+	  }, "XML::LibXML::Error";
+	} else {
+	  # !!!! problem : got flat error
+	  warn("PROBLEM: GOT FLAT ERROR\n");
+	  $terr =bless {
+            domain  => 0,
+            level   => 2,
+            code    => -1,
+            message => $xE,
+            file    => undef,
+            line    => undef,
+            str1    => undef,
+            str2    => undef,
+            str3    => undef,
+            num1    => undef,
+            num2    => undef,
+	  }, "XML::LibXML::Error";
+	}
+
+        unless ( defined $terr->{file} and length $terr->{file} ) {
+            # this would make it easier to recognize parsed strings
+            # but it breaks old implementations
+            # [CG] $terr->{file} = 'string()'; 
+        }
+        
+        if ( defined $ERROR ) {
+            $terr->{prev} = $ERROR;
+        }
+        
+        $ERROR = $terr;
     }
 
-    $ERROR = $terr;
-}
-
-sub _report_error {
-    die $ERROR;
+    sub _report_error {
+        if ( defined $ERROR ) {
+	  print "reporting error ",$ERROR->dump;
+            my $err = $ERROR;
+            $ERROR = undef;
+            die $err;
+        }
+    }
 }
 
 
   return undef unless ref($self);
   my $sub = $AUTOLOAD;
   $sub =~ s/.*:://;
-  if ($sub=~/^(?:code|_prev|level|file|line|domain|nodename|message|str[123]|int[12])$/) {
+  if ($sub=~/^(?:code|_prev|level|file|line|domain|nodename|message|num[123]|num[12])$/) {
     return $self->{$sub};
   } else {
     croak("Unknown error field $sub");
     if (($self->{domain} == XML_ERR_FROM_XPATH) and
         defined($self->{str1})) {
         $msg.=$self->{str1}."\n";
-        $msg.=(" " x $self->{int1})."^\n";
+        $msg.=(" " x $self->{num1})."^\n";
     }
     return $msg;
 }
 
 BEGIN { use XML::LibXML;
     if ( XML::LibXML::LIBXML_VERSION >= 20600 ) {
-        plan tests => 472; 
+        plan tests => 423; 
     }
     else {
-        plan tests => 464;
+        plan tests => 415;
         print "# skip NS cleaning tests\n";
     }
 };
     ok($@);
 }
 
-
 print "# 1.1.2 NO KEEP BLANKS\n";
 
-$parser->keep_blanks(0);
+sub Test_no_keep_blanks_good {
+    my $p = XML::LibXML->new();
+    $p->keep_blanks(0);
+    foreach my $str ( @goodWFStrings,@goodWFNSStrings,@goodWFDTDStrings ) {
+        my $doc;
+        eval {
+            $doc = $p->parse_string( $str );
+        };
+        return 0 unless defined $doc;
+        # warn "\$\@ is defined !!!! ($@)" if $@;
+        return 0 if $@;
+    }
 
-{
-    foreach my $str ( @goodWFStrings,@goodWFNSStrings,@goodWFDTDStrings ) {
-	my $doc = $parser->parse_string($str);
-        ok($doc);
+    return 1;
+
+} ok( Test_no_keep_blanks_good() );
+
+sub Test_no_keep_blanks_undef_data {
+    my $fail;
+
+    my $p = XML::LibXML->new();
+    $p->keep_blanks(0);
+
+    eval { 
+        $fail = $parser->parse_string(undef); 
+    };
+    
+    return 0 if defined $fail;
+    return 0 unless $@;
+
+    return 1;
+
+} ok( Test_no_keep_blanks_undef_data() );
+
+sub Test_no_keep_blanks_bad {
+    my $p = XML::LibXML->new();
+    $p->keep_blanks(0);
+
+    
+    foreach my $str ( @badWFStrings ) {
+        my $fail;
+        eval {
+            $fail = $p->parse_string($str); 
+        };
+
+        return 0 if defined $fail;
+        return 0 unless $@;
     }
-}
 
-eval { my $fail = $parser->parse_string(undef); };
-ok($@);
+    return 1;
 
-foreach my $str ( @badWFStrings ) {
-    eval { my $fail = $parser->parse_string($str); };
-    ok($@);
-}
+} ok( Test_no_keep_blanks_bad() );
 
-$parser->keep_blanks(1);
 
 print "# 1.1.3 EXPAND ENTITIES\n";
 
 
 print "# 1.2 PARSE A FILE\n";
 
-{
-    my $doc = $parser->parse_file($goodfile);
-    ok($doc);
-}
- 
-eval {my $fail = $parser->parse_file($badfile1);};
-ok($@);
+sub Test_parse_file_good {
+    my $p = XML::LibXML->new();
+    my $doc; 
+    eval {
+        $doc = $parser->parse_file($goodfile);
+    };
 
-eval { $parser->parse_file($badfile2); };
-ok($@);
+    return 0 unless defined $doc;
+    return 1 if $@;
+
+    return 1;
+} ok( Test_parse_file_good() );
+
+sub Test_parse_file_bad {
+    my $p = XML::LibXML->new();
+    my $doc;
+    eval {
+        $doc = $p->parse_file($badfile1);
+    };
+
+    return 0 unless $@;
+    return 0 if $doc;
+
+    eval {
+        $doc = $p->parse_file($badfile2);
+    };
+    
+    return 0 unless $@;
+    return 0 if $doc;
+
+    return 1;
+
+} ok( Test_parse_file_bad() );
+
 
 {
     my $str = "<a>    <b/> </a>";
 
 print "# 1.4 x-include processing\n";
 
-my $goodXInclude = q{
+sub Test_XIncludes_good {
+    my $goodXInclude = <<EXML;
 <x>
 <xinclude:include 
  xmlns:xinclude="http://www.w3.org/2001/XInclude"
  href="test2.xml"/>
 </x>
-};
+EXML
 
+    my $p = XML::LibXML->new();
+    $p->base_uri( "example/" );
+    $p->keep_blanks(0);
+    my $doc;
+    eval {
+        $doc = $p->parse_string( $goodXInclude );
+    };
+    
+    return 0 if $@;
+    return 0 unless $doc;
+    
+    my $i;
+    eval { 
+        $i = $p->processXIncludes($doc); 
+    };
+    
+    return 0 unless $i;
+    return 0 if $@;
 
-my $badXInclude = q{
+    return 1;
+
+} ok( Test_XIncludes_good() );
+
+
+sub Test_XIncludes_bad {
+    my $badXInclude = <<EXML;
 <x xmlns:xinclude="http://www.w3.org/2001/XInclude">
 <xinclude:include href="bad.xml"/>
 </x>
-};
+EXML
 
-{
-    $parser->base_uri( "example/" );
-    $parser->keep_blanks(0);
-    my $doc = $parser->parse_string( $goodXInclude );
-    ok($doc);
+    my $p = XML::LibXML->new();
+    $p->base_uri( "example/" );
+    $p->keep_blanks(0);
+    my $doc;
+    eval {
+        $doc = $p->parse_string( $badXInclude );
+    };
+
+    return 0 if $@;
+    return 0 unless defined $doc;
 
     my $i;
-    eval { $i = $parser->processXIncludes($doc); };
-    ok( $i );
+     eval {
+        $i = $p->processXIncludes($doc); 
+    };
+    
+    return 0 unless $@;
+    return 0 if $i;
 
-    $doc = $parser->parse_string( $badXInclude );
-    $i= undef;
-    eval { $i = $parser->processXIncludes($doc); };
-    ok($@);
+
+    # some other bad stuff 
+    eval{ $p->processXIncludes(undef); };
+    return 0 unless $@;
+    eval{ $p->processXIncludes("blahblah"); };
+    return 0 unless $@;
+
+    return 1;
+
+} ok( Test_XIncludes_bad() );
+
+
+
+sub Test_auto_xincludes_good {
+    my $p = XML::LibXML->new();
+    
+    my $goodXInclude = <<EXML;
+<x>
+<xinclude:include 
+ xmlns:xinclude="http://www.w3.org/2001/XInclude"
+ href="test2.xml"/>
+</x>
+EXML
     
     # auto expand
-    $parser->expand_xinclude(1);
-    $doc = $parser->parse_string( $goodXInclude );
-    ok($doc);
+    $p->base_uri( "example/" );
+    $p->expand_xinclude(1);
+    my $doc ;
+    eval {
+        $doc = $p->parse_string( $goodXInclude );
+    };
+    return 0 unless defined $doc;
 
-    $doc = undef;
-    eval { $doc = $parser->parse_string( $badXInclude ); };
-    ok($@);
-    ok(!$doc);
+    return 1;
 
-    # some bad stuff 
-    eval{ $parser->processXIncludes(undef); };
-    ok($@);
-    eval{ $parser->processXIncludes("blahblah"); };
-    ok($@);
-}
+} ok ( Test_auto_xincludes_good() );
+
+sub Test_auto_xincludes_fail {
+    my $p = XML::LibXML->new();
+    $p->base_uri( "example/" );
+    $p->expand_xinclude(1);
+
+    my $badXInclude = <<EXML;
+<x xmlns:xinclude="http://www.w3.org/2001/XInclude">
+<xinclude:include href="bad.xml"/>
+</x>
+EXML
+
+    my $doc;
+    eval { $doc = $p->parse_string( $badXInclude ); };
+    return 0 unless $@;
+    return 0 if defined $doc;
+
+    return 1;
+} ok( Test_auto_xincludes_fail() );
 
 print "# 2 PUSH PARSER\n";
 
         }
 
     }
+}
+sub Test_recovering_push_parser {
+    print "# 2.3 RECOVERING PUSH PARSER\n";
 
-    {
-        print "# 2.3 RECOVERING PUSH PARSER\n";
-        $parser->init_push;
+    my $p = XML::LibXML->new;
+    
+    $p->init_push;
 
-        foreach ( "<A>", "B" ) {
-            $parser->push( $_);
-        }
+    foreach ( "<A>", "B" ) {
+        $p->push( $_);
+    }
 
-        my $doc;
-        eval {
-	       local $SIG{'__WARN__'} = sub { };
-	       $doc = $parser->finish_push(1);
-	     };
-        ok( $doc );
+    my $doc = $p->finish_push(1);
+
+    return 0 unless defined $doc;
+
+    if ( XML::LibXML::HAVE_STRUCT_ERRORS() ) {
+        # the following conditions will only work with the 
+        # struct error code
+        # warn "compiled with HAVE_SERRORS";
+        return 0 unless $@;
+        return 0 unless ref( $@ ) eq "XML::LibXML::Error";
+        return 0 unless $@->{level} == 3;
     }
-}
+    else {
+        # warn "compiled without HAVE_SERRORS";
+    }
+    return 1;
+
+} ok( Test_recovering_push_parser() );
 
 print "# 3 SAX PARSER\n";
 
     eval { $parser->parse_string( $badxml ); };
     # correct line number may or may not be present
     # depending on libxml2 version
+
+    # [CG 1.59] fixed to work with the structured error implementation
     ok( $@ =~ /^:[03]:/ );
 
     $parser->line_numbers(1);
     eval { $parser->parse_string( $badxml ); };
+
+    # [CG 1.59] fixed to work with the structured error implementation
     ok( $@ =~ /^:3:/ );
 
     # switch off validation for the following tests
             @as   = $doc2->getElementsByLocalName( "A" );
             ok( scalar( @as ), 3);
         }
-        {
-	    $parser2->recover(1);
-	    local $SIG{'__WARN__'} = sub { }; 
-            my $doc2 = $parser2->parse_string($string4);
+    }
+}
+
+sub Test_recovered_doc_access  {
+    my $string = '<C:A><C:A><C:B/></C:A><C:A><C:B/></C:A></C:A>';
+
+    my $p = XML::LibXML->new();
+    my $doc;
+
+    $p->recover(1);
+    
+#    local $SIG{'__WARN__'} = sub {}; 
+
+    $doc = $p->parse_string($string);
+
+    return 0 unless defined $doc;
+
 #            my @as   = $doc2->getElementsByTagName( "C:A" );
 #            ok( scalar( @as ), 3);
-            my @as   = $doc2->getElementsByLocalName( "A" );
-            ok( scalar( @as ), 3);
-        }
-    }
-}
+
+    my @as;
+    @as   = $doc->getElementsByLocalName( "A" );
+
+    return 0 unless scalar( @as ) == 3;
+
+    return 1;
+
+} ok( Test_recovered_doc_access() );
     eval {
         $xml->validate($dtd);
     };
-    print $@, "\n";
+    # print $@, "\n";
     ok($@);
 
     my $parser = XML::LibXML->new();
     eval {
         $parser->parse_file('example/article_internal_bad.xml');
     };
-    print $@, "\n";
+    # print $@, "\n";
     ok($@);
 }
 

t/29_struct_errors.t

 # First version of the new structured error test suite
 
 use Test;
-BEGIN { plan tests => 4}
+BEGIN { 
+    use XML::LibXML;
+    if ( XML::LibXML::HAVE_STRUCT_ERRORS() ) {
+        plan tests => 4;
+    }else{
+        plan tests => 1;
+    }
+}
 END { ok(0) unless $loaded }
 
-use XML::LibXML;
 use XML::LibXML::Error;
 
 $loaded = 1;
         ok(ref($@), "XML::LibXML::Error");
         ok($@->domain(), "parser");
         ok($@->line(), 1);
-        warn "se: ", $@;
+        # warn "se: ", $@;
     }
 }
 

test/schema/schema.xsd

       <xsd:pattern value="\d{3}-[A-Z]{2}"/>
     </xsd:restriction>
   </xsd:simpleType>
-  <xsd:element name="Item" minOccurs="0" maxOccurs="unbounded">
+  <xsd:element name="Item" >
     <xsd:complexType>
       <xsd:sequence>
         <xsd:element name="productName" type="xsd:string"/>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.