1/* $Id: LibXML.xs,v 1.1.1.2 2007/10/10 23:04:13 ahuda Exp $ */
2
3#ifdef __cplusplus
4extern "C" {
5#endif
6
7/* perl stuff */
8#include "EXTERN.h"
9#include "perl.h"
10#include "XSUB.h"
11#include "ppport.h"
12#include "Av_CharPtrPtr.h"  /* XS_*_charPtrPtr() */
13
14#include <fcntl.h>
15
16#ifndef WIN32
17#  include <unistd.h>
18#endif
19
20/* libxml2 configuration properties */
21#include <libxml/xmlversion.h>
22
23#define DEBUG_C14N
24
25/* libxml2 stuff */
26#include <libxml/xmlversion.h>
27#include <libxml/globals.h>
28#include <libxml/xmlmemory.h>
29#include <libxml/parser.h>
30#include <libxml/parserInternals.h>
31#include <libxml/HTMLparser.h>
32#include <libxml/HTMLtree.h>
33#include <libxml/c14n.h>
34#include <libxml/tree.h>
35#include <libxml/xpath.h>
36#include <libxml/xpathInternals.h>
37#include <libxml/xmlIO.h>
38/* #include <libxml/debugXML.h> */
39#include <libxml/xmlerror.h>
40#include <libxml/xinclude.h>
41#include <libxml/valid.h>
42
43#if LIBXML_VERSION >= 20510
44#define HAVE_SCHEMAS
45#include <libxml/relaxng.h>
46#include <libxml/xmlschemas.h>
47#endif
48
49#if LIBXML_VERSION >= 20621
50#define HAVE_READER_SUPPORT
51#include <libxml/xmlreader.h>
52#endif
53
54#ifdef LIBXML_CATALOG_ENABLED
55#include <libxml/catalog.h>
56#endif
57
58/* GDOME support
59 * libgdome installs only the core functions to the system.
60 * this is not enough for XML::LibXML <-> XML::GDOME conversion.
61 * therefore there is the need to ship as well the GDOME core headers.
62 */
63#ifdef XML_LIBXML_GDOME_SUPPORT
64
65#include <libgdome/gdome.h>
66#include <libgdome/gdome-libxml-util.h>
67
68#endif
69
70/* XML::LibXML stuff */
71#include "perl-libxml-mm.h"
72#include "perl-libxml-sax.h"
73
74#include "dom.h"
75#include "xpath.h"
76#include "xpathcontext.h"
77
78#ifdef __cplusplus
79}
80#endif
81
82
83#define TEST_PERL_FLAG(flag) \
84    SvTRUE(perl_get_sv(flag, FALSE)) ? 1 : 0
85
86#ifdef HAVE_READER_SUPPORT
87#define LIBXML_READER_TEST_ELEMENT(reader,name,nsURI) \
88  (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) &&	\
89   ((!nsURI && !name) \
90    || \
91    (!nsURI && xmlStrcmp((const xmlChar*)name, xmlTextReaderConstName(reader) ) == 0 ) \
92    || \
93    (nsURI && xmlStrcmp((const xmlChar*)nsURI, xmlTextReaderConstNamespaceUri(reader))==0 \
94     && \
95     (!name || xmlStrcmp((const xmlChar*)name, xmlTextReaderConstLocalName(reader)) == 0)))
96#endif
97
98/* this should keep the default */
99static xmlExternalEntityLoader LibXML_old_ext_ent_loader = NULL;
100
101
102/* ****************************************************************
103 * Error handler
104 * **************************************************************** */
105
106/* If threads-support is working correctly in libxml2 then
107 * this method will be called with the correct thread-context */
108void
109LibXML_error_handler_ctx(void * ctxt, const char * msg, ...)
110{
111	va_list args;
112	SV * saved_error = (SV *) ctxt;
113
114	/* If saved_error is null we croak with the error */
115	if( NULL == saved_error ) {
116		SV * sv = sv_2mortal(newSV(0));
117		va_start(args, msg);
118                /* vfprintf(stderr, msg, args); */
119   		sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
120   		va_end(args);
121		croak("%s", SvPV_nolen(sv));
122	/* Otherwise, save the error */
123	} else {
124		va_start(args, msg);
125                /* vfprintf(stderr, msg, args);	*/
126   		sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
127		va_end(args);
128	}
129}
130
131static void
132LibXML_validity_error_ctx(void * ctxt, const char *msg, ...)
133{
134	va_list args;
135	SV * saved_error = (SV *) ctxt;
136
137	/* If saved_error is null we croak with the error */
138	if( NULL == saved_error ) {
139		SV * sv = sv_2mortal(newSV(0));
140		va_start(args, msg);
141   		sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
142   		va_end(args);
143		croak("%s", SvPV_nolen(sv));
144	/* Otherwise, save the error */
145	} else {
146		va_start(args, msg);
147   		sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
148		va_end(args);
149	}
150}
151
152static void
153LibXML_validity_warning_ctx(void * ctxt, const char *msg, ...)
154{
155	va_list args;
156	SV * saved_error = (SV *) ctxt;
157	STRLEN len;
158
159	/* If saved_error is null we croak with the error */
160	if( NULL == saved_error ) {
161		SV * sv = sv_2mortal(newSV(0));
162		va_start(args, msg);
163   		sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
164   		va_end(args);
165		croak("LibXML_validity_warning_ctx internal error: context was null (%s)", SvPV_nolen(sv));
166	/* Otherwise, give the warning */
167	} else {
168		va_start(args, msg);
169   		sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
170		va_end(args);
171		warn("validation error: %s", SvPV(saved_error, len));
172	}
173}
174
175static void
176LibXML_init_error_ctx(SV * saved_error)
177{
178    xmlSetGenericErrorFunc((void *) saved_error, (xmlGenericErrorFunc) LibXML_error_handler_ctx);
179}
180
181static int
182LibXML_will_die_ctx(SV * saved_error, int recover)
183{
184    if( 0 < SvCUR( saved_error ) ) {
185	if ( recover == 0 ) {
186	    return 1;
187	}
188    }
189    return 0;
190}
191
192
193static void
194LibXML_report_error_ctx(SV * saved_error, int recover)
195{
196    if( 0 < SvCUR( saved_error ) ) {
197	if( recover ) {
198	    if ( recover == 1 ) {
199		warn("%s", SvPV_nolen(saved_error));
200	    } /* else recover silently */
201	} else {
202	    croak("%s", SvPV_nolen(saved_error));
203	}
204    }
205}
206
207#ifdef HAVE_READER_SUPPORT
208static void
209LibXML_reader_error_handler(void * ctxt,
210				const char * msg,
211				xmlParserSeverities severity,
212				xmlTextReaderLocatorPtr locator)
213{
214  int line = xmlTextReaderLocatorLineNumber(locator);
215  xmlChar * filename = xmlTextReaderLocatorBaseURI(locator);
216  SV * msg_sv = sv_2mortal(C2Sv((xmlChar*) msg,NULL));
217  SV * error = sv_2mortal(newSVpv("", 0));
218
219  switch (severity) {
220  case XML_PARSER_SEVERITY_VALIDITY_WARNING:
221    sv_catpv(error, "Validity WARNING");
222    break;
223  case XML_PARSER_SEVERITY_WARNING:
224    sv_catpv(error, "Reader WARNING");
225    break;
226  case XML_PARSER_SEVERITY_VALIDITY_ERROR:
227    sv_catpv(error, "Validity ERROR");
228    break;
229  case XML_PARSER_SEVERITY_ERROR:
230    sv_catpv(error, "Reader ERROR");
231    break;
232  }
233  if (filename) {
234    sv_catpvf(error, " in %s", filename);
235    xmlFree(filename);
236  }
237  if (line >= 0) {
238    sv_catpvf(error, " at line %d", line);
239  }
240  sv_catpvf(error, ": %s", SvPV_nolen(msg_sv));
241  if (severity == XML_PARSER_SEVERITY_VALIDITY_WARNING ||
242      severity == XML_PARSER_SEVERITY_WARNING ) {
243    warn("%s", SvPV_nolen(error));
244  } else {
245    SV * error_sv = (SV*) ctxt;
246    if (error_sv) {
247      sv_catpvf(error_sv, "%s  ", SvPV_nolen(error));
248    } else {
249      croak("%s",SvPV_nolen(error));
250    }
251  }
252}
253
254static void
255LibXML_report_reader_error(xmlTextReaderPtr reader)
256{
257  SV * error_sv = NULL;
258  xmlTextReaderErrorFunc f = NULL;
259
260  xmlTextReaderGetErrorHandler(reader, &f, (void **) &error_sv);
261  if ( error_sv && SvOK( error_sv) && 0 < SvCUR( error_sv ) ) {
262    croak("%s", SvPV_nolen(error_sv));
263  }
264}
265#endif /* HAVE_READER_SUPPORT */
266
267static int
268LibXML_get_recover(HV * real_obj)
269{
270    SV** item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
271    return ( item != NULL && SvTRUE(*item) ) ? SvIV(*item) : 0;
272}
273
274static SV *
275LibXML_NodeToSv(HV * real_obj, xmlNodePtr real_doc)
276{
277    SV** item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
278
279    if ( item != NULL && SvTRUE(*item) ) {
280        return PmmNodeToGdomeSv(real_doc);
281    }
282    else {
283        return PmmNodeToSv(real_doc, NULL);
284    }
285}
286
287/* ****************************************************************
288 * IO callbacks
289 * **************************************************************** */
290
291int
292LibXML_read_perl (SV * ioref, char * buffer, int len)
293{
294    dTHX;
295    dSP;
296
297    int cnt;
298    SV * read_results;
299    STRLEN read_length;
300    char * chars;
301    SV * tbuff = NEWSV(0,len);
302    SV * tsize = newSViv(len);
303
304    ENTER;
305    SAVETMPS;
306
307    PUSHMARK(SP);
308    EXTEND(SP, 3);
309    PUSHs(ioref);
310    PUSHs(sv_2mortal(tbuff));
311    PUSHs(sv_2mortal(tsize));
312    PUTBACK;
313
314    if (sv_isobject(ioref)) {
315        cnt = call_method("read", G_SCALAR | G_EVAL);
316    }
317    else {
318        cnt = call_pv("XML::LibXML::__read", G_SCALAR | G_EVAL);
319    }
320
321    SPAGAIN;
322
323    if (cnt != 1) {
324        croak("read method call failed");
325    }
326
327    if (SvTRUE(ERRSV)) {
328       croak("read on filehandle failed: %s", SvPV_nolen(ERRSV));
329       POPs ;
330    }
331
332    read_results = POPs;
333
334    if (!SvOK(read_results)) {
335        croak("read error");
336    }
337
338    read_length = SvIV(read_results);
339
340    chars = SvPV(tbuff, read_length);
341    strncpy(buffer, chars, read_length);
342
343    PUTBACK;
344    FREETMPS;
345    LEAVE;
346
347    return read_length;
348}
349
350/* used only by Reader */
351int
352LibXML_close_perl (SV * ioref)
353{
354  SvREFCNT_dec(ioref);
355  return 0;
356}
357
358int
359LibXML_input_match(char const * filename)
360{
361    int results;
362    int count;
363    SV * res;
364
365    results = 0;
366
367    {
368        dTHX;
369        dSP;
370
371        ENTER;
372        SAVETMPS;
373
374        PUSHMARK(SP);
375        EXTEND(SP, 1);
376        PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
377        PUTBACK;
378
379        count = call_pv("XML::LibXML::InputCallback::_callback_match",
380                             G_SCALAR | G_EVAL);
381
382        SPAGAIN;
383
384        if (count != 1) {
385            croak("match callback must return a single value");
386        }
387
388        if (SvTRUE(ERRSV)) {
389            croak("input match callback died: %s", SvPV_nolen(ERRSV));
390            POPs ;
391        }
392
393        res = POPs;
394
395        if (SvTRUE(res)) {
396            results = 1;
397        }
398
399        PUTBACK;
400        FREETMPS;
401        LEAVE;
402    }
403    return results;
404}
405
406void *
407LibXML_input_open(char const * filename)
408{
409    SV * results;
410    int count;
411
412    dTHX;
413    dSP;
414
415    ENTER;
416    SAVETMPS;
417
418    PUSHMARK(SP);
419    EXTEND(SP, 1);
420    PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
421    PUTBACK;
422
423    count = call_pv("XML::LibXML::InputCallback::_callback_open",
424                              G_SCALAR | G_EVAL);
425
426    SPAGAIN;
427
428    if (count != 1) {
429        croak("open callback must return a single value");
430    }
431
432    if (SvTRUE(ERRSV)) {
433        croak("input callback died: %s", SvPV_nolen(ERRSV));
434        POPs ;
435    }
436
437    results = POPs;
438
439    SvREFCNT_inc(results);
440
441    PUTBACK;
442    FREETMPS;
443    LEAVE;
444
445    return (void *)results;
446}
447
448int
449LibXML_input_read(void * context, char * buffer, int len)
450{
451    STRLEN res_len;
452    const char * output;
453    SV * ctxt;
454
455    res_len = 0;
456    ctxt = (SV *)context;
457
458    {
459        int count;
460
461        dTHX;
462        dSP;
463
464        ENTER;
465        SAVETMPS;
466
467        PUSHMARK(SP);
468        EXTEND(SP, 2);
469        PUSHs(ctxt);
470        PUSHs(sv_2mortal(newSViv(len)));
471        PUTBACK;
472
473        count = call_pv("XML::LibXML::InputCallback::_callback_read",
474                             G_SCALAR | G_EVAL);
475
476        SPAGAIN;
477
478        if (count != 1) {
479            croak("read callback must return a single value");
480        }
481
482        if (SvTRUE(ERRSV)) {
483            croak("read callback died: %s", SvPV_nolen(ERRSV));
484            POPs ;
485        }
486
487        output = POPp;
488        if (output != NULL) {
489            res_len = strlen(output);
490            if (res_len) {
491                strncpy(buffer, output, res_len);
492            }
493            else {
494                buffer[0] = 0;
495            }
496        }
497
498	PUTBACK;
499        FREETMPS;
500        LEAVE;
501    }
502    return res_len;
503}
504
505void
506LibXML_input_close(void * context)
507{
508    SV * ctxt;
509
510    ctxt = (SV *)context;
511
512    {
513        dTHX;
514        dSP;
515
516        ENTER;
517        SAVETMPS;
518
519        PUSHMARK(SP);
520        EXTEND(SP, 1);
521        PUSHs(ctxt);
522        PUTBACK;
523
524        call_pv("XML::LibXML::InputCallback::_callback_close",
525                             G_SCALAR | G_EVAL | G_DISCARD);
526
527        SvREFCNT_dec(ctxt);
528
529        if (SvTRUE(ERRSV)) {
530            croak("close callback died: %s", SvPV_nolen(ERRSV));
531        }
532
533        FREETMPS;
534        LEAVE;
535    }
536}
537
538int
539LibXML_output_write_handler(void * ioref, char * buffer, int len)
540{
541    if ( buffer != NULL && len > 0) {
542        dTHX;
543        dSP;
544
545        SV * tbuff = newSVpv(buffer,len);
546        SV * tsize = newSViv(len);
547
548
549        ENTER;
550        SAVETMPS;
551
552        PUSHMARK(SP);
553        EXTEND(SP, 3);
554        PUSHs((SV*)ioref);
555        PUSHs(sv_2mortal(tbuff));
556        PUSHs(sv_2mortal(tsize));
557        PUTBACK;
558
559        call_pv("XML::LibXML::__write", G_SCALAR | G_EVAL | G_DISCARD );
560
561        if (SvTRUE(ERRSV)) {
562            croak("write method call died: %s", SvPV_nolen(ERRSV));
563        }
564
565        FREETMPS;
566        LEAVE;
567    }
568    return len;
569}
570
571int
572LibXML_output_close_handler( void * handler )
573{
574    return 1;
575}
576
577xmlParserInputPtr
578LibXML_load_external_entity(
579        const char * URL,
580        const char * ID,
581        xmlParserCtxtPtr ctxt)
582{
583    SV * self;
584    HV * real_obj;
585    SV ** func;
586    int count;
587    SV * results;
588    STRLEN results_len;
589    const char * results_pv;
590    xmlParserInputBufferPtr input_buf;
591
592    if (ctxt->_private == NULL) {
593        return xmlNewInputFromFile(ctxt, URL);
594    }
595
596    if (URL == NULL) {
597        URL = "";
598    }
599    if (ID == NULL) {
600        ID = "";
601    }
602
603    self = (SV *)ctxt->_private;
604    real_obj = (HV *)SvRV(self);
605    func = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
606
607    if (func) {
608        dTHX;
609        dSP;
610
611        ENTER;
612        SAVETMPS;
613
614        PUSHMARK(SP) ;
615        XPUSHs(sv_2mortal(newSVpv((char*)URL, 0)));
616        XPUSHs(sv_2mortal(newSVpv((char*)ID, 0)));
617        PUTBACK;
618
619        count = call_sv(*func, G_SCALAR | G_EVAL);
620
621        SPAGAIN;
622
623        if (count == 0) {
624            croak("external entity handler did not return a value");
625        }
626
627        if (SvTRUE(ERRSV)) {
628            croak("external entity callback died: %s", SvPV_nolen(ERRSV));
629            POPs ;
630        }
631
632        results = POPs;
633
634        results_pv = SvPV(results, results_len);
635        input_buf = xmlParserInputBufferCreateMem(
636                        results_pv,
637                        results_len,
638                        XML_CHAR_ENCODING_NONE
639                        );
640
641        PUTBACK;
642        FREETMPS;
643        LEAVE;
644
645        return xmlNewIOInputStream(ctxt, input_buf, XML_CHAR_ENCODING_NONE);
646    }
647    else {
648        if (URL == NULL) {
649            return NULL;
650        }
651        return xmlNewInputFromFile(ctxt, URL);
652    }
653}
654
655/* ****************************************************************
656 * Helper functions
657 * **************************************************************** */
658
659HV*
660LibXML_init_parser( SV * self ) {
661    /* we fetch all switches and callbacks from the hash */
662    HV* real_obj = NULL;
663    SV** item    = NULL;
664
665    /* A NOTE ABOUT xmlInitParser();                     */
666    /* xmlInitParser() should be used only at startup and*/
667    /* not for initializing a single parser. libxml2's   */
668    /* documentation is quite clear about this. If       */
669    /* something fails it is a problem elsewhere. Simply */
670    /* resetting the entire module will lead to unwanted */
671    /* results in server environments, such as if        */
672    /* mod_perl is used together with php's xml module.  */
673    /* calling xmlInitParser() here is definitly wrong!  */
674    /* xmlInitParser(); */
675
676    xmlGetWarningsDefaultValue = 0;
677
678    if ( self != NULL ) {
679        /* first fetch the values from the hash */
680        real_obj = (HV *)SvRV(self);
681
682        item = hv_fetch( real_obj, "XML_LIBXML_KEEP_BLANKS", 22, 0 );
683        if ( item != NULL ) {
684            if ( SvTRUE(*item) )
685                xmlKeepBlanksDefault(1);
686            else {
687                xmlKeepBlanksDefault(0);
688            }
689        }
690        else {
691            /* keep blanks on default */
692            xmlKeepBlanksDefault(1);
693        }
694
695        item = hv_fetch( real_obj, "XML_LIBXML_PEDANTIC", 19, 0 );
696        if ( item != NULL && SvTRUE(*item) ) {
697#ifdef LIBXML_THREAD_ENABLED
698#if LIBXML_VERSION != 20507
699            xmlThrDefPedanticParserDefaultValue( 1 );
700#endif
701#endif
702            xmlPedanticParserDefaultValue = 1;
703        }
704        else {
705#ifdef LIBXML_THREAD_ENABLED
706#if LIBXML_VERSION != 20507
707            xmlThrDefPedanticParserDefaultValue( 0 );
708#endif
709#endif
710            xmlPedanticParserDefaultValue = 0;
711        }
712
713        item =  hv_fetch( real_obj, "XML_LIBXML_LINENUMBERS", 22, 0 );
714        if ( item != NULL && SvTRUE(*item) ) {
715            xmlLineNumbersDefault( 1 );
716        }
717        else {
718            xmlLineNumbersDefault( 0 );
719        }
720
721        item = hv_fetch( real_obj, "XML_LIBXML_EXT_DTD", 18, 0 );
722        if ( item != NULL && SvTRUE(*item) ) {
723            xmlLoadExtDtdDefaultValue |= 1;
724
725            item = hv_fetch( real_obj, "XML_LIBXML_VALIDATION", 21, 0 );
726            if ( item != NULL && SvTRUE(*item) ) {
727                xmlDoValidityCheckingDefaultValue = 1;
728                xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
729            }
730            else {
731                xmlDoValidityCheckingDefaultValue = 0;
732            }
733            item = hv_fetch( real_obj, "XML_LIBXML_COMPLETE_ATTR", 24, 0 );
734            if (item != NULL && SvTRUE(*item)) {
735                xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
736            }
737            else {
738                xmlLoadExtDtdDefaultValue ^= XML_COMPLETE_ATTRS;
739            }
740
741            item = hv_fetch( real_obj, "XML_LIBXML_EXPAND_ENTITIES", 26, 0 );
742            if ( item != NULL ) {
743                if ( SvTRUE(*item) ) {
744                    xmlSubstituteEntitiesDefaultValue = 1;
745                    xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
746                }
747                else {
748                    xmlSubstituteEntitiesDefaultValue = 0;
749                }
750            }
751            else {
752                xmlSubstituteEntitiesDefaultValue = 1;
753                xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
754            }
755        }
756        else {
757            /* xmlLoadExtDtdDefaultValue ^= 1;*/
758            xmlLoadExtDtdDefaultValue = 0;
759        }
760
761        item = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
762        if ( item != NULL  && SvTRUE(*item)) {
763            LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader();
764            xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
765        }
766        else {
767	    item = hv_fetch( real_obj, "XML_LIBXML_NONET", 16, 0 );
768            if (item != NULL && SvTRUE(*item)) {
769                LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader();
770                xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
771            }
772            /* LibXML_old_ext_ent_loader =  NULL; */
773        }
774    }
775
776    return real_obj;
777}
778
779void
780LibXML_cleanup_parser() {
781    xmlSubstituteEntitiesDefaultValue = 1;
782    xmlKeepBlanksDefaultValue = 1;
783    xmlGetWarningsDefaultValue = 0;
784    xmlLoadExtDtdDefaultValue = 5;
785    xmlPedanticParserDefaultValue = 0;
786    xmlLineNumbersDefault( 0 );
787    xmlDoValidityCheckingDefaultValue = 0;
788
789    if (LibXML_old_ext_ent_loader != NULL ) {
790        xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_old_ext_ent_loader );
791    }
792}
793
794int
795LibXML_test_node_name( xmlChar * name )
796{
797    xmlChar * cur = name;
798    int tc  = 0;
799    int len = 0;
800
801    if ( cur == NULL || *cur == 0 ) {
802        /* warn("name is empty" ); */
803        return(0);
804    }
805
806    tc = domParseChar( cur, &len );
807
808    if ( !( IS_LETTER( tc ) || (tc == '_') || (tc == ':')) ) {
809        /* warn( "is not a letter\n" ); */
810        return(0);
811    }
812
813    tc  =  0;
814    cur += len;
815
816    while (*cur != 0 ) {
817        tc = domParseChar( cur, &len );
818
819        if (!(IS_LETTER(tc) || IS_DIGIT(tc) || (tc == '_') ||
820             (tc == '-') || (tc == ':') || (tc == '.') ||
821             IS_COMBINING(tc) || IS_EXTENDER(tc)) ) {
822            /* warn( "is not a letter\n" ); */
823            return(0);
824        }
825        tc = 0;
826        cur += len;
827    }
828
829    /* warn("name is ok"); */
830    return(1);
831}
832
833/* ****************************************************************
834 * XPathContext helper functions
835 * **************************************************************** */
836
837/* Temporary node pool:                                              *
838 * Stores pnode in context node-pool hash table in order to preserve *
839 * at least one reference.                                           *
840 * If pnode is NULL, only return current value for hashkey           */
841static SV*
842LibXML_XPathContext_pool ( xmlXPathContextPtr ctxt, void * hashkey, SV * pnode ) {
843    SV ** value;
844    SV * key;
845    STRLEN len;
846    char * strkey;
847    dTHX;
848
849    if (XPathContextDATA(ctxt)->pool == NULL) {
850        if (pnode == NULL) {
851            return &PL_sv_undef;
852        } else {
853            xs_warn("initializing node pool");
854            XPathContextDATA(ctxt)->pool = newHV();
855        }
856    }
857
858    key = newSViv((IV) hashkey);
859    strkey = SvPV(key, len);
860    if (pnode != NULL && !hv_exists(XPathContextDATA(ctxt)->pool,strkey,len)) {
861        value = hv_store(XPathContextDATA(ctxt)->pool,strkey,len, SvREFCNT_inc(pnode),0);
862    } else {
863        value = hv_fetch(XPathContextDATA(ctxt)->pool,strkey,len, 0);
864    }
865    SvREFCNT_dec(key);
866
867    if (value == NULL) {
868        return &PL_sv_undef;
869    } else {
870        return *value;
871    }
872}
873
874/* convert perl result structures to LibXML structures */
875static xmlXPathObjectPtr
876LibXML_perldata_to_LibXMLdata(xmlXPathParserContextPtr ctxt,
877                              SV* perl_result) {
878    dTHX;
879
880    if (!SvOK(perl_result)) {
881        return (xmlXPathObjectPtr)xmlXPathNewCString("");
882    }
883    if (SvROK(perl_result) &&
884        SvTYPE(SvRV(perl_result)) == SVt_PVAV) {
885        /* consider any array ref to be a nodelist */
886        int i;
887        int length;
888        SV ** pnode;
889        AV * array_result;
890        xmlXPathObjectPtr ret;
891
892        ret = (xmlXPathObjectPtr) xmlXPathNewNodeSet((xmlNodePtr) NULL);
893        array_result = (AV*)SvRV(perl_result);
894        length = av_len(array_result);
895        for( i = 0; i <= length ; i++ ) {
896            pnode = av_fetch(array_result,i,0);
897            if (pnode != NULL && sv_isobject(*pnode) &&
898                sv_derived_from(*pnode,"XML::LibXML::Node")) {
899                xmlXPathNodeSetAdd(ret->nodesetval,
900                                   (xmlNodePtr)PmmSvNode(*pnode));
901                if(ctxt) {
902                    LibXML_XPathContext_pool(ctxt->context,
903                                             PmmSvNode(*pnode), *pnode);
904                }
905            } else {
906                warn("XPathContext: ignoring non-node member of a nodelist");
907            }
908        }
909        return ret;
910    } else if (sv_isobject(perl_result) &&
911               (SvTYPE(SvRV(perl_result)) == SVt_PVMG))
912        {
913            if (sv_derived_from(perl_result, "XML::LibXML::Node")) {
914                xmlNodePtr tmp_node;
915                xmlXPathObjectPtr ret;
916
917                ret =  (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
918                tmp_node = (xmlNodePtr)PmmSvNode(perl_result);
919                xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
920                if(ctxt) {
921                    LibXML_XPathContext_pool(ctxt->context, PmmSvNode(perl_result),
922                                             perl_result);
923                }
924
925                return ret;
926            }
927            else if (sv_isa(perl_result, "XML::LibXML::Boolean")) {
928                return (xmlXPathObjectPtr)
929                    xmlXPathNewBoolean(SvIV(SvRV(perl_result)));
930            }
931            else if (sv_isa(perl_result, "XML::LibXML::Literal")) {
932                return (xmlXPathObjectPtr)
933                    xmlXPathNewCString(SvPV_nolen(SvRV(perl_result)));
934            }
935            else if (sv_isa(perl_result, "XML::LibXML::Number")) {
936                return (xmlXPathObjectPtr)
937                    xmlXPathNewFloat(SvNV(SvRV(perl_result)));
938            }
939        } else if (SvNOK(perl_result) || SvIOK(perl_result)) {
940            return (xmlXPathObjectPtr)xmlXPathNewFloat(SvNV(perl_result));
941        } else {
942            return (xmlXPathObjectPtr)
943                xmlXPathNewCString(SvPV_nolen(perl_result));
944    }
945    return NULL;
946}
947
948
949/* save XPath context and XPathContextDATA for recursion */
950static xmlXPathContextPtr
951LibXML_save_context(xmlXPathContextPtr ctxt)
952{
953    xmlXPathContextPtr copy;
954    copy = xmlMalloc(sizeof(xmlXPathContext));
955    if (copy) {
956	/* backup ctxt */
957	memcpy(copy, ctxt, sizeof(xmlXPathContext));
958	/* clear namespaces so that they are not freed and overwritten
959	   by configure_namespaces */
960	ctxt->namespaces = NULL;
961	/* backup data */
962	copy->user = xmlMalloc(sizeof(XPathContextData));
963	if (XPathContextDATA(copy)) {
964	    memcpy(XPathContextDATA(copy), XPathContextDATA(ctxt),sizeof(XPathContextData));
965	    /* clear ctxt->pool, so that it is not used freed during re-entrance */
966	    XPathContextDATA(ctxt)->pool = NULL;
967	}
968    }
969    return copy;
970}
971
972/* restore XPath context and XPathContextDATA from a saved copy */
973static void
974LibXML_restore_context(xmlXPathContextPtr ctxt, xmlXPathContextPtr copy)
975{
976    dTHX;
977    /* cleanup */
978    if (XPathContextDATA(ctxt)) {
979	/* cleanup newly created pool */
980	if (XPathContextDATA(ctxt)->pool != NULL &&
981	    SvOK(XPathContextDATA(ctxt)->pool)) {
982	    SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
983	}
984    }
985    if (ctxt->namespaces) {
986	/* free namespaces allocated during recursion */
987        xmlFree( ctxt->namespaces );
988    }
989
990    /* restore context */
991    if (copy) {
992	/* 1st restore our data */
993	if (XPathContextDATA(copy)) {
994	    memcpy(XPathContextDATA(ctxt),XPathContextDATA(copy),sizeof(XPathContextData));
995	    xmlFree(XPathContextDATA(copy));
996	    copy->user = XPathContextDATA(ctxt);
997	}
998	/* now copy the rest */
999	memcpy(ctxt, copy, sizeof(xmlXPathContext));
1000	xmlFree(copy);
1001    }
1002}
1003
1004
1005/* ****************************************************************
1006 * Variable Lookup
1007 * **************************************************************** */
1008/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT   */
1009static xmlXPathObjectPtr
1010LibXML_generic_variable_lookup(void* varLookupData,
1011                               const xmlChar *name,
1012                               const xmlChar *ns_uri)
1013{
1014    xmlXPathObjectPtr ret;
1015    xmlXPathContextPtr ctxt;
1016    xmlXPathContextPtr copy;
1017    XPathContextDataPtr data;
1018    I32 count;
1019    dTHX;
1020    dSP;
1021
1022    ctxt = (xmlXPathContextPtr) varLookupData;
1023    if ( ctxt == NULL )
1024	croak("XPathContext: missing xpath context");
1025    data = XPathContextDATA(ctxt);
1026    if ( data == NULL )
1027	croak("XPathContext: missing xpath context private data");
1028    if ( data->varLookup == NULL || !SvROK(data->varLookup) ||
1029	 SvTYPE(SvRV(data->varLookup)) != SVt_PVCV )
1030        croak("XPathContext: lost variable lookup function!");
1031
1032    ENTER;
1033    SAVETMPS;
1034    PUSHMARK(SP);
1035
1036    XPUSHs( (data->varData != NULL) ? data->varData : &PL_sv_undef );
1037    XPUSHs(sv_2mortal(C2Sv(name,NULL)));
1038    XPUSHs(sv_2mortal(C2Sv(ns_uri,NULL)));
1039
1040    /* save context to allow recursive usage of XPathContext */
1041    copy = LibXML_save_context(ctxt);
1042
1043    PUTBACK ;
1044    count = perl_call_sv(data->varLookup, G_SCALAR|G_EVAL);
1045    SPAGAIN;
1046
1047    /* restore the xpath context */
1048    LibXML_restore_context(ctxt, copy);
1049
1050    if (SvTRUE(ERRSV)) {
1051        POPs;
1052        croak("XPathContext: error coming back from variable lookup function. %s", SvPV_nolen(ERRSV));
1053    }
1054    if (count != 1) croak("XPathContext: variable lookup function returned more than one argument!");
1055
1056    ret = LibXML_perldata_to_LibXMLdata(NULL, POPs);
1057
1058    PUTBACK;
1059    FREETMPS;
1060    LEAVE;
1061    return ret;
1062}
1063
1064/* ****************************************************************
1065 * Generic Extension Function
1066 * **************************************************************** */
1067/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT   */
1068static void
1069LibXML_generic_extension_function(xmlXPathParserContextPtr ctxt, int nargs)
1070{
1071    xmlXPathObjectPtr obj,ret;
1072    xmlNodeSetPtr nodelist = NULL;
1073    int count;
1074    SV * perl_dispatch;
1075    int i;
1076    STRLEN len;
1077    ProxyNodePtr owner = NULL;
1078    SV *key;
1079    char *strkey;
1080    const char *function, *uri;
1081    SV **perl_function;
1082    dTHX;
1083    dSP;
1084    SV * data;
1085    xmlXPathContextPtr copy;
1086
1087    /* warn("entered LibXML_generic_extension_function for %s\n",ctxt->context->function); */
1088    data = (SV *) ctxt->context->funcLookupData;
1089    if (ctxt->context->funcLookupData == NULL || !SvROK(data) ||
1090        SvTYPE(SvRV(data)) != SVt_PVHV) {
1091        croak("XPathContext: lost function lookup data structure!");
1092    }
1093
1094    function = (char*) ctxt->context->function;
1095    uri = (char*) ctxt->context->functionURI;
1096
1097    key = newSVpvn("",0);
1098    if (uri && *uri) {
1099        sv_catpv(key, "{");
1100        sv_catpv(key, (const char*)uri);
1101        sv_catpv(key, "}");
1102    }
1103    sv_catpv(key, (const char*)function);
1104    strkey = SvPV(key, len);
1105    perl_function =
1106        hv_fetch((HV*)SvRV(data), strkey, len, 0);
1107    if ( perl_function == NULL || !SvOK(*perl_function) ||
1108         !(SvPOK(*perl_function) ||
1109           (SvROK(*perl_function) &&
1110            SvTYPE(SvRV(*perl_function)) == SVt_PVCV))) {
1111        croak("XPathContext: lost perl extension function!");
1112    }
1113    SvREFCNT_dec(key);
1114
1115    ENTER;
1116    SAVETMPS;
1117    PUSHMARK(SP);
1118
1119    XPUSHs(*perl_function);
1120
1121    /* set up call to perl dispatcher function */
1122    for (i = 0; i < nargs; i++) {
1123        obj = (xmlXPathObjectPtr)valuePop(ctxt);
1124        switch (obj->type) {
1125        case XPATH_XSLT_TREE:
1126        case XPATH_NODESET:
1127            nodelist = obj->nodesetval;
1128            if ( nodelist ) {
1129                XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
1130                XPUSHs(sv_2mortal(newSViv(nodelist->nodeNr)));
1131                if ( nodelist->nodeNr > 0 ) {
1132                    int j;
1133                    const char * cls = "XML::LibXML::Node";
1134                    xmlNodePtr tnode;
1135                    SV * element;
1136
1137                    len = nodelist->nodeNr;
1138                    for( j = 0 ; j < len; j++){
1139                        tnode = nodelist->nodeTab[j];
1140                        if( tnode != NULL && tnode->doc != NULL) {
1141                            owner = PmmOWNERPO(PmmNewNode((xmlNodePtr) tnode->doc));
1142                        } else {
1143                            owner = NULL;
1144                        }
1145                        if (tnode->type == XML_NAMESPACE_DECL) {
1146                            element = sv_newmortal();
1147                            cls = PmmNodeTypeName( tnode );
1148                            element = sv_setref_pv( element,
1149                                                    (const char *)cls,
1150                                                    (void *)xmlCopyNamespace((xmlNsPtr)tnode)
1151                                );
1152                        }
1153                        else {
1154                            element = PmmNodeToSv(tnode, owner);
1155                        }
1156                        XPUSHs( sv_2mortal(element) );
1157                    }
1158                }
1159            } else {
1160                /* PP: We can't simply leave out an empty nodelist as Matt does! */
1161                /* PP: The number of arguments must match! */
1162                XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
1163                XPUSHs(sv_2mortal(newSViv(0)));
1164            }
1165            /* prevent libxml2 from freeing the actual nodes */
1166            if (obj->boolval) obj->boolval=0;
1167            break;
1168        case XPATH_BOOLEAN:
1169            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
1170            XPUSHs(sv_2mortal(newSViv(obj->boolval)));
1171            break;
1172        case XPATH_NUMBER:
1173            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
1174            XPUSHs(sv_2mortal(newSVnv(obj->floatval)));
1175            break;
1176        case XPATH_STRING:
1177            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
1178            XPUSHs(sv_2mortal(C2Sv(obj->stringval, 0)));
1179            break;
1180        default:
1181            warn("Unknown XPath return type (%d) in call to {%s}%s - assuming string", obj->type, uri, function);
1182            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
1183            XPUSHs(sv_2mortal(C2Sv(xmlXPathCastToString(obj), 0)));
1184        }
1185        xmlXPathFreeObject(obj);
1186    }
1187
1188    /* save context to allow recursive usage of XPathContext */
1189    copy = LibXML_save_context(ctxt->context);
1190
1191    /* call perl dispatcher */
1192    PUTBACK;
1193    perl_dispatch = sv_2mortal(newSVpv("XML::LibXML::XPathContext::_perl_dispatcher",0));
1194    count = perl_call_sv(perl_dispatch, G_SCALAR|G_EVAL);
1195    SPAGAIN;
1196
1197    /* restore the xpath context */
1198    LibXML_restore_context(ctxt->context, copy);
1199
1200    if (SvTRUE(ERRSV)) {
1201        POPs;
1202        croak("XPathContext: error coming back from perl-dispatcher in pm file. %s", SvPV_nolen(ERRSV));
1203    }
1204
1205    if (count != 1) croak("XPathContext: perl-dispatcher in pm file returned more than one argument!");
1206
1207    ret = LibXML_perldata_to_LibXMLdata(ctxt, POPs);
1208
1209    valuePush(ctxt, ret);
1210    PUTBACK;
1211    FREETMPS;
1212    LEAVE;
1213}
1214
1215static void
1216LibXML_configure_namespaces( xmlXPathContextPtr ctxt ) {
1217    xmlNodePtr node = ctxt->node;
1218
1219    if (ctxt->namespaces != NULL) {
1220        xmlFree( ctxt->namespaces );
1221        ctxt->namespaces = NULL;
1222    }
1223    if (node != NULL) {
1224        if (node->type == XML_DOCUMENT_NODE) {
1225            ctxt->namespaces = xmlGetNsList( node->doc,
1226                                             xmlDocGetRootElement( node->doc ) );
1227        } else {
1228            ctxt->namespaces = xmlGetNsList(node->doc, node);
1229        }
1230        ctxt->nsNr = 0;
1231        if (ctxt->namespaces != NULL) {
1232            while (ctxt->namespaces[ctxt->nsNr] != NULL)
1233                ctxt->nsNr++;
1234        }
1235    }
1236}
1237
1238static void
1239LibXML_configure_xpathcontext( xmlXPathContextPtr ctxt ) {
1240    xmlNodePtr node = PmmSvNode(XPathContextDATA(ctxt)->node);
1241
1242    if (node != NULL) {
1243        ctxt->doc = node->doc;
1244    } else {
1245        ctxt->doc = NULL;
1246    }
1247    ctxt->node = node;
1248    LibXML_configure_namespaces(ctxt);
1249}
1250
1251MODULE = XML::LibXML         PACKAGE = XML::LibXML
1252
1253PROTOTYPES: DISABLE
1254
1255BOOT:
1256    LIBXML_TEST_VERSION
1257    xmlInitParser();
1258    PmmSAXInitialize(aTHX);
1259
1260    xmlSetGenericErrorFunc( NULL ,
1261                           (xmlGenericErrorFunc)LibXML_error_handler_ctx);
1262    xmlDoValidityCheckingDefaultValue = 0;
1263    xmlSubstituteEntitiesDefaultValue = 1;
1264    xmlGetWarningsDefaultValue = 0;
1265    xmlKeepBlanksDefaultValue = 1;
1266    xmlLoadExtDtdDefaultValue = 5;
1267    xmlPedanticParserDefaultValue = 0;
1268    xmlLineNumbersDefault(0);
1269    xmlSetGenericErrorFunc(NULL, NULL);
1270#ifdef LIBXML_CATALOG_ENABLED
1271    /* xmlCatalogSetDebug(10); */
1272    xmlInitializeCatalog(); /* use catalog data */
1273#endif
1274
1275char *
1276LIBXML_DOTTED_VERSION()
1277    CODE:
1278        RETVAL = LIBXML_DOTTED_VERSION;
1279    OUTPUT:
1280        RETVAL
1281
1282
1283int
1284LIBXML_VERSION()
1285    CODE:
1286        RETVAL = LIBXML_VERSION;
1287    OUTPUT:
1288        RETVAL
1289
1290const char *
1291LIBXML_RUNTIME_VERSION()
1292    CODE:
1293        RETVAL = xmlParserVersion;
1294    OUTPUT:
1295        RETVAL
1296
1297void
1298END()
1299    CODE:
1300        xmlCleanupParser();
1301
1302SV*
1303_parse_string(self, string, dir = &PL_sv_undef)
1304        SV * self
1305        SV * string
1306        SV * dir
1307    PREINIT:
1308        char * directory = NULL;
1309        STRLEN len;
1310        char * ptr;
1311        SV * saved_error = sv_2mortal(newSVpv("",0));
1312        HV * real_obj;
1313        int well_formed;
1314        int valid;
1315        xmlDocPtr real_doc;
1316        int recover = 0;
1317    INIT:
1318        if (SvPOK(dir)) {
1319            directory = SvPV(dir, len);
1320            if (len <= 0) {
1321                directory = NULL;
1322            }
1323        }
1324        ptr = SvPV(string, len);
1325        if (len <= 0) {
1326            croak("Empty string\n");
1327            XSRETURN_UNDEF;
1328        }
1329    CODE:
1330        RETVAL = &PL_sv_undef;
1331        LibXML_init_error_ctx(saved_error);
1332        real_obj = LibXML_init_parser(self);
1333        recover = LibXML_get_recover(real_obj);
1334
1335        {
1336            xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
1337            if (ctxt == NULL) {
1338                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1339                croak("Could not create memory parser context!\n");
1340            }
1341            xs_warn( "context created\n");
1342
1343            if ( directory != NULL ) {
1344                ctxt->directory = directory;
1345            }
1346            ctxt->_private = (void*)self;
1347
1348            /* make libxml2-2.6 display line number on error */
1349            if ( ctxt->input != NULL ) {
1350                if (directory != NULL) {
1351		  ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) directory);
1352                } else {
1353		  ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) "");
1354                }
1355            }
1356
1357            xs_warn( "context initialized\n" );
1358
1359            {
1360#if LIBXML_VERSION > 20600
1361                SV** item =  hv_fetch( real_obj, "XML_LIBXML_NSCLEAN", 18, 0 );
1362                if ( item != NULL && SvTRUE(*item) ) {
1363                    ctxt->options |= XML_PARSE_NSCLEAN;
1364                }
1365                item =  hv_fetch( real_obj, "XML_LIBXML_NONET", 16, 0 );
1366                if ( item != NULL && SvTRUE(*item) ) {
1367                    ctxt->options |= XML_PARSE_NONET;
1368                }
1369#endif
1370                xmlParseDocument(ctxt);
1371                xs_warn( "document parsed \n");
1372            }
1373
1374            ctxt->directory = NULL;
1375            well_formed = ctxt->wellFormed;
1376            valid = ctxt->valid;
1377            real_doc = ctxt->myDoc;
1378            ctxt->myDoc = NULL;
1379            xmlFreeParserCtxt(ctxt);
1380        }
1381        if ( real_doc != NULL ) {
1382  	    if (real_doc->URL != NULL) { /* free "" assigned above */
1383               xmlFree((char*) real_doc->URL);
1384               real_doc->URL = NULL;
1385            }
1386
1387            if ( directory == NULL ) {
1388                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
1389                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
1390            } else {
1391                real_doc->URL = xmlStrdup((const xmlChar*)directory);
1392            }
1393            if ( ! LibXML_will_die_ctx(saved_error, recover) &&
1394		 (recover || ( well_formed &&
1395                              ( !xmlDoValidityCheckingDefaultValue
1396                                || ( valid || ( real_doc->intSubset == NULL
1397                                                && real_doc->extSubset == NULL )))))) {
1398                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1399            } else {
1400                xmlFreeDoc(real_doc);
1401            }
1402        }
1403
1404        LibXML_cleanup_parser();
1405        LibXML_report_error_ctx(saved_error, recover);
1406    OUTPUT:
1407        RETVAL
1408
1409int
1410_parse_sax_string(self, string)
1411        SV * self
1412        SV * string
1413    PREINIT:
1414        STRLEN len;
1415        char * ptr;
1416        SV * saved_error = sv_2mortal(newSVpv("",0));
1417        HV * real_obj;
1418        int recover = 0;
1419    INIT:
1420        ptr = SvPV(string, len);
1421        if (len <= 0) {
1422            croak("Empty string\n");
1423            XSRETURN_UNDEF;
1424        }
1425    CODE:
1426        RETVAL = 0;
1427        LibXML_init_error_ctx(saved_error);
1428        real_obj = LibXML_init_parser(self);
1429        recover = LibXML_get_recover(real_obj);
1430
1431        {
1432            xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
1433            if (ctxt == NULL) {
1434                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1435                croak("Could not create memory parser context!\n");
1436            }
1437            xs_warn( "context created\n");
1438
1439            PmmSAXInitContext( ctxt, self, saved_error );
1440            xs_warn( "context initialized \n");
1441
1442            {
1443                RETVAL = xmlParseDocument(ctxt);
1444                xs_warn( "document parsed \n");
1445            }
1446
1447            PmmSAXCloseContext(ctxt);
1448            xmlFreeParserCtxt(ctxt);
1449        }
1450
1451        LibXML_cleanup_parser();
1452        LibXML_report_error_ctx(saved_error, recover);
1453    OUTPUT:
1454        RETVAL
1455
1456SV*
1457_parse_fh(self, fh, dir = &PL_sv_undef)
1458        SV * self
1459        SV * fh
1460        SV * dir
1461    PREINIT:
1462        STRLEN len;
1463        char * directory = NULL;
1464        SV * saved_error = sv_2mortal(newSVpv("",0));
1465        HV * real_obj;
1466        int well_formed;
1467        int valid;
1468        xmlDocPtr real_doc;
1469        int recover = 0;
1470    INIT:
1471        if (SvPOK(dir)) {
1472            directory = SvPV(dir, len);
1473            if (len <= 0) {
1474                directory = NULL;
1475            }
1476        }
1477    CODE:
1478        RETVAL = &PL_sv_undef;
1479        LibXML_init_error_ctx(saved_error);
1480        real_obj = LibXML_init_parser(self);
1481        recover = LibXML_get_recover(real_obj);
1482
1483        {
1484            int read_length;
1485            char buffer[1024];
1486            xmlParserCtxtPtr ctxt;
1487
1488            read_length = LibXML_read_perl(fh, buffer, 4);
1489            if (read_length <= 0) {
1490                croak( "Empty Stream\n" );
1491            }
1492
1493            ctxt = xmlCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL);
1494            if (ctxt == NULL) {
1495                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1496                croak("Could not create xml push parser context!\n");
1497            }
1498            xs_warn( "context created\n");
1499#if LIBXML_VERSION > 20600
1500	    /* dictionaries not support yet */
1501	    ctxt->dictNames = 0;
1502#endif
1503            if ( directory != NULL ) {
1504                ctxt->directory = directory;
1505            }
1506            ctxt->_private = (void*)self;
1507            xs_warn( "context initialized \n");
1508            {
1509                int ret;
1510#if LIBXML_VERSION > 20600
1511                SV** item =  hv_fetch( real_obj, "XML_LIBXML_NSCLEAN", 18, 0 );
1512                if ( item != NULL && SvTRUE(*item) ) {
1513                    ctxt->options |= XML_PARSE_NSCLEAN;
1514                }
1515                item =  hv_fetch( real_obj, "XML_LIBXML_NONET", 16, 0 );
1516                if ( item != NULL && SvTRUE(*item) ) {
1517                    ctxt->options |= XML_PARSE_NONET;
1518                }
1519#endif
1520                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
1521                    ret = xmlParseChunk(ctxt, buffer, read_length, 0);
1522                    if ( ret != 0 ) {
1523                        break;
1524                    }
1525                }
1526                ret = xmlParseChunk(ctxt, buffer, 0, 1);
1527                xs_warn( "document parsed \n");
1528            }
1529
1530            ctxt->directory = NULL;
1531            well_formed = ctxt->wellFormed;
1532            valid = ctxt->valid;
1533            real_doc = ctxt->myDoc;
1534            ctxt->myDoc = NULL;
1535            xmlFreeParserCtxt(ctxt);
1536        }
1537
1538        if ( real_doc != NULL ) {
1539
1540            if ( directory == NULL ) {
1541                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
1542                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
1543            } else {
1544                real_doc->URL = xmlStrdup((const xmlChar*)directory);
1545            }
1546
1547            if ( recover || ( well_formed &&
1548                              ( !xmlDoValidityCheckingDefaultValue
1549                                || ( valid || ( real_doc->intSubset == NULL
1550                                                && real_doc->extSubset == NULL ))))) {
1551                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1552            } else {
1553                xmlFreeDoc(real_doc);
1554            }
1555        }
1556
1557        LibXML_cleanup_parser();
1558        LibXML_report_error_ctx(saved_error, recover);
1559    OUTPUT:
1560        RETVAL
1561
1562void
1563_parse_sax_fh(self, fh, dir = &PL_sv_undef)
1564        SV * self
1565        SV * fh
1566        SV * dir
1567    PREINIT:
1568        STRLEN len;
1569        char * directory = NULL;
1570        SV * saved_error = sv_2mortal(newSVpv("",0));
1571        HV * real_obj;
1572        int recover = 0;
1573    INIT:
1574        if (SvPOK(dir)) {
1575            directory = SvPV(dir, len);
1576            if (len <= 0) {
1577                directory = NULL;
1578            }
1579        }
1580    CODE:
1581        LibXML_init_error_ctx(saved_error);
1582        real_obj = LibXML_init_parser(self);
1583        recover = LibXML_get_recover(real_obj);
1584
1585        {
1586            int read_length;
1587            char buffer[1024];
1588            xmlSAXHandlerPtr sax;
1589            xmlParserCtxtPtr ctxt;
1590
1591            read_length = LibXML_read_perl(fh, buffer, 4);
1592            if (read_length <= 0) {
1593                croak( "Empty Stream\n" );
1594            }
1595
1596            sax = PSaxGetHandler();
1597            ctxt = xmlCreatePushParserCtxt(sax, NULL, buffer, read_length, NULL);
1598            if (ctxt == NULL) {
1599                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1600                croak("Could not create xml push parser context!\n");
1601            }
1602            xs_warn( "context created\n");
1603
1604            if ( directory != NULL ) {
1605                ctxt->directory = directory;
1606            }
1607            PmmSAXInitContext( ctxt, self, saved_error );
1608            xs_warn( "context initialized \n");
1609
1610            {
1611                int ret;
1612                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
1613                    ret = xmlParseChunk(ctxt, buffer, read_length, 0);
1614                    if ( ret != 0 ) {
1615                        break;
1616                    }
1617                }
1618                ret = xmlParseChunk(ctxt, buffer, 0, 1);
1619                xs_warn( "document parsed \n");
1620            }
1621
1622            ctxt->directory = NULL;
1623            xmlFree(ctxt->sax);
1624            ctxt->sax = NULL;
1625            xmlFree(sax);
1626            PmmSAXCloseContext(ctxt);
1627            xmlFreeParserCtxt(ctxt);
1628        }
1629
1630        LibXML_cleanup_parser();
1631        LibXML_report_error_ctx(saved_error, recover);
1632
1633SV*
1634_parse_file(self, filename_sv)
1635        SV * self
1636        SV * filename_sv
1637    PREINIT:
1638        STRLEN len;
1639        char * filename;
1640        SV * saved_error = sv_2mortal(newSVpv("",0));
1641        HV * real_obj;
1642        int well_formed;
1643        int valid;
1644        xmlDocPtr real_doc;
1645        int recover = 0;
1646    INIT:
1647        filename = SvPV(filename_sv, len);
1648        if (len <= 0) {
1649            croak("Empty filename\n");
1650            XSRETURN_UNDEF;
1651        }
1652    CODE:
1653        RETVAL = &PL_sv_undef;
1654        LibXML_init_error_ctx(saved_error);
1655        real_obj = LibXML_init_parser(self);
1656        recover = LibXML_get_recover(real_obj);
1657
1658        {
1659            xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1660            if (ctxt == NULL) {
1661                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1662                croak("Could not create file parser context for file \"%s\": %s\n",
1663                      filename, strerror(errno));
1664            }
1665            xs_warn( "context created\n");
1666
1667            ctxt->_private = (void*)self;
1668            xs_warn( "context initialized \n");
1669
1670            {
1671#if LIBXML_VERSION > 20600
1672                SV** item =  hv_fetch( real_obj, "XML_LIBXML_NSCLEAN", 18, 0 );
1673                if ( item != NULL && SvTRUE(*item) ) {
1674                    ctxt->options |= XML_PARSE_NSCLEAN;
1675                }
1676                item =  hv_fetch( real_obj, "XML_LIBXML_NONET", 16, 0 );
1677                if ( item != NULL && SvTRUE(*item) ) {
1678                    ctxt->options |= XML_PARSE_NONET;
1679                }
1680#endif
1681                xmlParseDocument(ctxt);
1682                xs_warn( "document parsed \n");
1683            }
1684
1685            well_formed = ctxt->wellFormed;
1686            valid = ctxt->valid;
1687            real_doc = ctxt->myDoc;
1688            ctxt->myDoc = NULL;
1689            xmlFreeParserCtxt(ctxt);
1690        }
1691
1692        if ( real_doc != NULL ) {
1693
1694            if ( recover || ( well_formed &&
1695                              ( !xmlDoValidityCheckingDefaultValue
1696                                || ( valid || ( real_doc->intSubset == NULL
1697                                                && real_doc->extSubset == NULL ))))) {
1698                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1699            } else {
1700                xmlFreeDoc(real_doc);
1701            }
1702        }
1703
1704        LibXML_cleanup_parser();
1705        LibXML_report_error_ctx(saved_error, recover);
1706    OUTPUT:
1707        RETVAL
1708
1709void
1710_parse_sax_file(self, filename_sv)
1711        SV * self
1712        SV * filename_sv
1713    PREINIT:
1714        STRLEN len;
1715        char * filename;
1716        SV * saved_error = sv_2mortal(newSVpv("",0));
1717        HV * real_obj;
1718        int recover = 0;
1719    INIT:
1720        filename = SvPV(filename_sv, len);
1721        if (len <= 0) {
1722            croak("Empty filename\n");
1723            XSRETURN_UNDEF;
1724        }
1725    CODE:
1726        LibXML_init_error_ctx(saved_error);
1727        real_obj = LibXML_init_parser(self);
1728        recover = LibXML_get_recover(real_obj);
1729
1730        {
1731            xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1732            if (ctxt == NULL) {
1733                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1734                croak("Could not create file parser context for file \"%s\": %s\n",
1735                      filename, strerror(errno));
1736            }
1737            xs_warn( "context created\n");
1738
1739            ctxt->sax = PSaxGetHandler();
1740            PmmSAXInitContext( ctxt, self, saved_error );
1741            xs_warn( "context initialized \n");
1742
1743            {
1744                xmlParseDocument(ctxt);
1745                xs_warn( "document parsed \n");
1746            }
1747
1748            PmmSAXCloseContext(ctxt);
1749            xmlFreeParserCtxt(ctxt);
1750        }
1751
1752        LibXML_cleanup_parser();
1753        LibXML_report_error_ctx(saved_error, recover);
1754
1755SV*
1756_parse_html_string(self, string, svURL, svEncoding, options = 0)
1757        SV * self
1758        SV * string
1759	SV * svURL
1760	SV * svEncoding
1761        int options
1762    PREINIT:
1763        STRLEN len;
1764        char * ptr;
1765        char* URL = NULL;
1766        char * encoding = NULL;
1767        SV * saved_error = sv_2mortal(newSVpv("",0));
1768        HV * real_obj;
1769        htmlDocPtr real_doc;
1770        int recover = 0;
1771    INIT:
1772        ptr = SvPV(string, len);
1773        if (len <= 0) {
1774            croak("Empty string\n");
1775            XSRETURN_UNDEF;
1776        }
1777        if (SvOK(svURL))
1778          URL = SvPV_nolen( svURL );
1779        if (SvOK(svEncoding))
1780          encoding = SvPV_nolen( svEncoding );
1781    CODE:
1782        RETVAL = &PL_sv_undef;
1783        LibXML_init_error_ctx(saved_error);
1784        real_obj = LibXML_init_parser(self);
1785        if (encoding == NULL && SvUTF8( string )) {
1786	  encoding = "UTF-8";
1787        }
1788        recover = LibXML_get_recover(real_obj);
1789#if LIBXML_VERSION >= 20627
1790        if (recover) options |= HTML_PARSE_RECOVER;
1791        real_doc = htmlReadDoc((xmlChar*)ptr, URL, encoding, options);
1792#else
1793        real_doc = htmlParseDoc((xmlChar*)ptr, encoding);
1794#endif
1795        if ( real_doc != NULL ) {
1796            if (real_doc->URL) xmlFree((xmlChar *)real_doc->URL);
1797   	    if (URL) {
1798                real_doc->URL = xmlStrdup((const xmlChar*) URL);
1799            } else {
1800                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
1801                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
1802            }
1803
1804            /* This HTML memory parser doesn't use a ctxt; there is no "well-formed"
1805             * distinction, and if it manages to parse the HTML, it returns non-null. */
1806            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1807        }
1808
1809        LibXML_cleanup_parser();
1810        LibXML_report_error_ctx(saved_error, recover);
1811    OUTPUT:
1812        RETVAL
1813
1814
1815SV*
1816_parse_html_file(self, filename_sv, svURL, svEncoding, options = 0)
1817        SV * self
1818        SV * filename_sv
1819	SV * svURL
1820	SV * svEncoding
1821	int options
1822    PREINIT:
1823        STRLEN len;
1824        char * filename;
1825        char * URL = NULL;
1826	char * encoding = NULL;
1827        SV * saved_error = sv_2mortal(newSVpv("",0));
1828        HV * real_obj;
1829        htmlDocPtr real_doc;
1830        int recover = 0;
1831    INIT:
1832        filename = SvPV(filename_sv, len);
1833        if (len <= 0) {
1834            croak("Empty filename\n");
1835            XSRETURN_UNDEF;
1836        }
1837        if (SvOK(svURL))
1838          URL = SvPV_nolen( svURL );
1839        if (SvOK(svEncoding))
1840          encoding = SvPV_nolen( svEncoding );
1841    CODE:
1842        RETVAL = &PL_sv_undef;
1843        LibXML_init_error_ctx(saved_error);
1844        real_obj = LibXML_init_parser(self);
1845        recover = LibXML_get_recover(real_obj);
1846#if LIBXML_VERSION >= 20627
1847        if (recover) options |= HTML_PARSE_RECOVER;
1848        real_doc = htmlReadFile((const char *)filename,
1849				encoding,
1850				options);
1851#else
1852        real_doc = htmlParseFile((const char *)filename, encoding);
1853#endif
1854        if ( real_doc != NULL ) {
1855
1856            /* This HTML file parser doesn't use a ctxt; there is no "well-formed"
1857             * distinction, and if it manages to parse the HTML, it returns non-null. */
1858	    if (URL) {
1859                if (real_doc->URL) xmlFree((xmlChar*) real_doc->URL);
1860                real_doc->URL = xmlStrdup((const xmlChar*) URL);
1861	    }
1862            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1863
1864        }
1865
1866        LibXML_cleanup_parser();
1867        LibXML_report_error_ctx(saved_error, recover);
1868    OUTPUT:
1869        RETVAL
1870
1871SV*
1872_parse_html_fh(self, fh, svURL, svEncoding, options = 0)
1873        SV * self
1874        SV * fh
1875	SV * svURL
1876	SV * svEncoding
1877        int options
1878    PREINIT:
1879        SV * saved_error = sv_2mortal(newSVpv("",0));
1880        HV * real_obj;
1881        htmlDocPtr real_doc;
1882        int well_formed;
1883        int recover = 0;
1884        char * URL = NULL;
1885#if LIBXML_VERSION >= 20627
1886        char * encoding = NULL;
1887#else
1888        xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
1889#endif
1890    INIT:
1891        if (SvOK(svURL))
1892          URL = SvPV_nolen( svURL );
1893#if LIBXML_VERSION >= 20627
1894        if (SvOK(svEncoding))
1895          encoding = SvPV_nolen( svEncoding );
1896#else
1897        if (SvOK(svEncoding))
1898          enc = xmlParseCharEncoding(SvPV_nolen( svEncoding ));
1899#endif
1900    CODE:
1901        RETVAL = &PL_sv_undef;
1902        LibXML_init_error_ctx(saved_error);
1903        real_obj = LibXML_init_parser(self);
1904        recover = LibXML_get_recover(real_obj);
1905#if LIBXML_VERSION >= 20627
1906        if (recover) options |= HTML_PARSE_RECOVER;
1907
1908        real_doc = htmlReadIO((xmlInputReadCallback) LibXML_read_perl,
1909                              NULL,
1910			      (void *) fh,
1911			      URL,
1912			      encoding,
1913			      options);
1914#else /* LIBXML_VERSION >= 20627 */
1915        {
1916            int read_length;
1917            char buffer[1024];
1918            htmlParserCtxtPtr ctxt;
1919
1920            read_length = LibXML_read_perl(fh, buffer, 4);
1921            if (read_length <= 0) {
1922                croak( "Empty Stream\n" );
1923            }
1924            ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length,
1925                                            URL, enc);
1926            if (ctxt == NULL) {
1927                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
1928                croak("Could not create html push parser context!\n");
1929            }
1930            ctxt->_private = (void*)self;
1931            {
1932                int ret;
1933                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
1934                    ret = htmlParseChunk(ctxt, buffer, read_length, 0);
1935                    if ( ret != 0 ) {
1936                        break;
1937                    }
1938                }
1939                ret = htmlParseChunk(ctxt, buffer, 0, 1);
1940            }
1941            well_formed = ctxt->wellFormed;
1942            real_doc = ctxt->myDoc;
1943            ctxt->myDoc = NULL;
1944            htmlFreeParserCtxt(ctxt);
1945        }
1946#endif /* LIBXML_VERSION >= 20627 */
1947        if ( real_doc != NULL ) {
1948            if (real_doc->URL) xmlFree((xmlChar*) real_doc->URL);
1949	    if (URL) {
1950                real_doc->URL = xmlStrdup((const xmlChar*) URL);
1951	    } else {
1952                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
1953                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
1954            }
1955
1956	    RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
1957        }
1958
1959        LibXML_cleanup_parser();
1960        LibXML_report_error_ctx(saved_error, recover);
1961    OUTPUT:
1962        RETVAL
1963
1964SV*
1965_parse_xml_chunk(self, svchunk, enc = &PL_sv_undef)
1966        SV * self
1967        SV * svchunk
1968        SV * enc
1969    PREINIT:
1970        STRLEN len;
1971        char * encoding = "UTF-8";
1972        SV * saved_error = sv_2mortal(newSVpv("",0));
1973        HV * real_obj;
1974        int recover = 0;
1975        xmlChar * chunk;
1976        xmlNodePtr rv = NULL;
1977    INIT:
1978        if (SvPOK(enc)) {
1979            encoding = SvPV(enc, len);
1980            if (len <= 0) {
1981                encoding = "UTF-8";
1982            }
1983        }
1984    CODE:
1985        RETVAL = &PL_sv_undef;
1986        LibXML_init_error_ctx(saved_error);
1987        real_obj = LibXML_init_parser(self);
1988
1989        chunk = Sv2C(svchunk, (const xmlChar*)encoding);
1990
1991        if ( chunk != NULL ) {
1992            recover = LibXML_get_recover(real_obj);
1993
1994            rv = domReadWellBalancedString( NULL, chunk, recover );
1995
1996            if ( rv != NULL ) {
1997                xmlNodePtr fragment= NULL;
1998                xmlNodePtr rv_end = NULL;
1999
2000                /* now we append the nodelist to a document
2001                   fragment which is unbound to a Document!!!! */
2002
2003                /* step 1: create the fragment */
2004                fragment = xmlNewDocFragment( NULL );
2005                RETVAL = LibXML_NodeToSv(real_obj, fragment);
2006
2007                /* step 2: set the node list to the fragment */
2008                fragment->children = rv;
2009                rv_end = rv;
2010                while ( rv_end->next != NULL ) {
2011                    rv_end->parent = fragment;
2012                    rv_end = rv_end->next;
2013                }
2014                /* the following line is important, otherwise we'll have
2015                   occasional segmentation faults
2016                 */
2017                rv_end->parent = fragment;
2018                fragment->last = rv_end;
2019            }
2020
2021            /* free the chunk we created */
2022            xmlFree( chunk );
2023        }
2024
2025        LibXML_cleanup_parser();
2026        LibXML_report_error_ctx(saved_error, recover);
2027
2028	if (rv == NULL) {
2029            croak("_parse_xml_chunk: chunk parsing failed\n");
2030        }
2031    OUTPUT:
2032        RETVAL
2033
2034void
2035_parse_sax_xml_chunk(self, svchunk, enc = &PL_sv_undef)
2036        SV * self
2037        SV * svchunk
2038        SV * enc
2039    PREINIT:
2040        STRLEN len;
2041        char * ptr;
2042        char * encoding = "UTF-8";
2043        SV * saved_error = sv_2mortal(newSVpv("",0));
2044        HV * real_obj;
2045        int recover = 0;
2046        xmlChar * chunk;
2047        int retCode              = -1;
2048        xmlNodePtr nodes         = NULL;
2049        xmlSAXHandlerPtr handler = NULL;
2050    INIT:
2051        if (SvPOK(enc)) {
2052            encoding = SvPV(enc, len);
2053            if (len <= 0) {
2054                encoding = "UTF-8";
2055            }
2056        }
2057        ptr = SvPV(svchunk, len);
2058        if (len <= 0) {
2059            croak("Empty string\n");
2060        }
2061    CODE:
2062        LibXML_init_error_ctx(saved_error);
2063        real_obj = LibXML_init_parser(self);
2064        recover = LibXML_get_recover(real_obj);
2065
2066        chunk = Sv2C(svchunk, (const xmlChar*)encoding);
2067
2068        if ( chunk != NULL ) {
2069            xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
2070            if (ctxt == NULL) {
2071                LibXML_report_error_ctx(saved_error, recover ? recover : 1);
2072                croak("Could not create memory parser context!\n");
2073            }
2074            xs_warn( "context created\n");
2075
2076            PmmSAXInitContext( ctxt, self, saved_error );
2077            handler = PSaxGetHandler();
2078
2079            retCode = xmlParseBalancedChunkMemory( NULL,
2080                                                   handler,
2081                                                   ctxt,
2082                                                   0,
2083                                                   chunk,
2084                                                   &nodes );
2085
2086            xmlFree( handler );
2087            PmmSAXCloseContext(ctxt);
2088            xmlFreeParserCtxt(ctxt);
2089
2090            /* free the chunk we created */
2091            xmlFree( chunk );
2092        }
2093
2094        LibXML_cleanup_parser();
2095        LibXML_report_error_ctx(saved_error, recover);
2096
2097	if (retCode == -1) {
2098            croak("_parse_sax_xml_chunk: chunk parsing failed\n");
2099        }
2100
2101int
2102_processXIncludes(self, doc, options=0)
2103        SV * self
2104        SV * doc
2105        int options
2106    PREINIT:
2107        xmlDocPtr real_doc;
2108        SV * saved_error = sv_2mortal(newSVpv("",0));
2109        HV * real_obj;
2110        int recover = 0;
2111    INIT:
2112        real_doc = (xmlDocPtr) PmmSvNode(doc);
2113        if (real_doc == NULL) {
2114            croak("No document to process!\n");
2115            XSRETURN_UNDEF;
2116        }
2117    CODE:
2118        RETVAL = 0;
2119        LibXML_init_error_ctx(saved_error);
2120        real_obj = LibXML_init_parser(self);
2121        recover = LibXML_get_recover(real_obj);
2122
2123        RETVAL = xmlXIncludeProcessFlags(real_doc,options);
2124
2125        LibXML_cleanup_parser();
2126        LibXML_report_error_ctx(saved_error, recover);
2127
2128        if ( RETVAL < 0 ) {
2129            croak( "unknown error during XInclude processing\n" );
2130            XSRETURN_UNDEF;
2131        } else if ( RETVAL == 0 ) {
2132            RETVAL = 1;
2133        }
2134    OUTPUT:
2135        RETVAL
2136
2137SV*
2138_start_push(self, with_sax=0)
2139        SV * self
2140        int with_sax
2141    PREINIT:
2142        SV * saved_error = sv_2mortal(newSVpv("",0));
2143        HV * real_obj;
2144        int recover = 0;
2145        xmlParserCtxtPtr ctxt = NULL;
2146    CODE:
2147        RETVAL = &PL_sv_undef;
2148        LibXML_init_error_ctx(saved_error);
2149        real_obj = LibXML_init_parser(self);
2150        recover = LibXML_get_recover(real_obj);
2151
2152        /* create empty context */
2153        ctxt = xmlCreatePushParserCtxt( NULL, NULL, NULL, 0, NULL );
2154#if LIBXML_VERSION > 20600
2155        {
2156                SV** item =  hv_fetch( real_obj, "XML_LIBXML_NSCLEAN", 18, 0 );
2157                if ( item != NULL && SvTRUE(*item) ) {
2158                    ctxt->options |= XML_PARSE_NSCLEAN;
2159                }
2160                item =  hv_fetch( real_obj, "XML_LIBXML_NONET", 16, 0 );
2161                if ( item != NULL && SvTRUE(*item) ) {
2162                    ctxt->options |= XML_PARSE_NONET;
2163                }
2164        }
2165#endif
2166        if ( with_sax == 1 ) {
2167	    PmmSAXInitContext( ctxt, self, saved_error );
2168        }
2169
2170        RETVAL = PmmContextSv( ctxt );
2171
2172        LibXML_cleanup_parser();
2173        LibXML_report_error_ctx(saved_error, recover);
2174    OUTPUT:
2175        RETVAL
2176
2177int
2178_push(self, pctxt, data)
2179        SV * self
2180        SV * pctxt
2181        SV * data
2182    PREINIT:
2183        SV * saved_error = sv_2mortal(newSVpv("",0));
2184        HV * real_obj;
2185        int recover = 0;
2186        xmlParserCtxtPtr ctxt = NULL;
2187        STRLEN len = 0;
2188        char * chunk = NULL;
2189    INIT:
2190        ctxt = PmmSvContext( pctxt );
2191        if ( ctxt == NULL ) {
2192            croak( "parser context already freed\n" );
2193            XSRETURN_UNDEF;
2194        }
2195        if ( data == &PL_sv_undef ) {
2196            XSRETURN_UNDEF;
2197        }
2198        chunk = SvPV( data, len );
2199        if ( len <= 0 ) {
2200            xs_warn( "empty string" );
2201            XSRETURN_UNDEF;
2202        }
2203    CODE:
2204        RETVAL = 0;
2205        LibXML_init_error_ctx(saved_error);
2206        real_obj = LibXML_init_parser(self);
2207        recover = LibXML_get_recover(real_obj);
2208
2209        xmlParseChunk(ctxt, (const char *)chunk, len, 0);
2210
2211        LibXML_cleanup_parser();
2212        LibXML_report_error_ctx(saved_error, recover);
2213
2214        if ( ctxt->wellFormed == 0 ) {
2215            croak( "XML not well-formed in xmlParseChunk\n" );
2216            XSRETURN_UNDEF;
2217        }
2218        RETVAL = 1;
2219    OUTPUT:
2220        RETVAL
2221
2222SV*
2223_end_push(self, pctxt, restore)
2224        SV * self
2225        SV * pctxt
2226        int restore
2227    PREINIT:
2228        SV * saved_error = sv_2mortal(newSVpv("",0));
2229        HV * real_obj;
2230        int well_formed;
2231        xmlParserCtxtPtr ctxt = NULL;
2232        xmlDocPtr real_doc = NULL;
2233    INIT:
2234        ctxt = PmmSvContext( pctxt );
2235        if ( ctxt == NULL ) {
2236            croak( "parser context already freed\n" );
2237            XSRETURN_UNDEF;
2238        }
2239    CODE:
2240        RETVAL = &PL_sv_undef;
2241        LibXML_init_error_ctx(saved_error);
2242        real_obj = LibXML_init_parser(self);
2243
2244        xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
2245        xs_warn( "Finished with push parser\n" );
2246
2247        well_formed = ctxt->wellFormed;
2248        real_doc = ctxt->myDoc;
2249        ctxt->myDoc = NULL;
2250        xmlFreeParserCtxt(ctxt);
2251        PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
2252
2253        if ( real_doc != NULL ) {
2254            if ( restore || well_formed ) {
2255                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
2256            } else {
2257                xmlFreeDoc(real_doc);
2258                real_doc = NULL;
2259            }
2260        }
2261
2262        LibXML_cleanup_parser();
2263        LibXML_report_error_ctx(saved_error, restore);
2264
2265        if ( real_doc == NULL ){
2266            croak( "no document found!\n" );
2267            XSRETURN_UNDEF;
2268        }
2269    OUTPUT:
2270        RETVAL
2271
2272void
2273_end_sax_push(self, pctxt)
2274        SV * self
2275        SV * pctxt
2276    PREINIT:
2277        SV * saved_error = sv_2mortal(newSVpv("",0));
2278        HV * real_obj;
2279        xmlParserCtxtPtr ctxt = NULL;
2280    INIT:
2281        ctxt = PmmSvContext( pctxt );
2282        if ( ctxt == NULL ) {
2283            croak( "parser context already freed\n" );
2284        }
2285    CODE:
2286        LibXML_init_error_ctx(saved_error);
2287        real_obj = LibXML_init_parser(self);
2288
2289        xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
2290        xs_warn( "Finished with SAX push parser\n" );
2291
2292        xmlFree(ctxt->sax);
2293        ctxt->sax = NULL;
2294        PmmSAXCloseContext(ctxt);
2295        xmlFreeParserCtxt(ctxt);
2296        PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
2297
2298        LibXML_cleanup_parser();
2299        LibXML_report_error_ctx(saved_error, 0);
2300
2301SV*
2302import_GDOME( dummy, sv_gdome, deep=1 )
2303        SV * dummy
2304        SV * sv_gdome
2305        int deep
2306    PREINIT:
2307        xmlNodePtr node  = NULL;
2308    INIT:
2309        RETVAL = &PL_sv_undef;
2310#ifndef XML_LIBXML_GDOME_SUPPORT
2311        croak( "GDOME Support not compiled" );
2312#endif
2313        if ( sv_gdome == NULL || sv_gdome == &PL_sv_undef ) {
2314            croak( "no XML::GDOME data found" );
2315        }
2316#ifdef XML_LIBXML_GDOME_SUPPORT
2317        else {
2318            GdomeNode* gnode = NULL;
2319            gnode = (GdomeNode*)SvIV((SV*)SvRV( sv_gdome ));
2320            if ( gnode == NULL ) {
2321                croak( "no XML::GDOME data found (datastructure empty)" );
2322            }
2323
2324            node = gdome_xml_n_get_xmlNode( gnode );
2325            if ( node == NULL ) {
2326                croak( "no XML::LibXML node found in GDOME object" );
2327            }
2328        }
2329#endif
2330    CODE:
2331        if ( node->type == XML_NAMESPACE_DECL ) {
2332            const char * CLASS = "XML::LibXML::Namespace";
2333            RETVAL = sv_newmortal();
2334            RETVAL = sv_setref_pv( RETVAL,
2335                                   CLASS,
2336                                   (void*)xmlCopyNamespace((xmlNsPtr)node) );
2337        }
2338        else {
2339            RETVAL = PmmNodeToSv( PmmCloneNode( node, deep ), NULL );
2340        }
2341    OUTPUT:
2342        RETVAL
2343
2344
2345SV*
2346export_GDOME( dummy, sv_libxml, deep=1 )
2347        SV * dummy
2348        SV * sv_libxml
2349        int deep
2350    PREINIT:
2351        xmlNodePtr node  = NULL, retnode = NULL;
2352    INIT:
2353        RETVAL = &PL_sv_undef;
2354#ifndef XML_LIBXML_GDOME_SUPPORT
2355        croak( "GDOME Support not configured!" );
2356#endif
2357        if ( sv_libxml == NULL || sv_libxml == &PL_sv_undef ) {
2358            croak( "no XML::LibXML data found" );
2359        }
2360        node = PmmSvNode( sv_libxml );
2361        if ( node == NULL ) {
2362            croak( "no XML::LibXML data found (empty structure)" );
2363        }
2364    CODE:
2365        retnode = PmmCloneNode( node, deep );
2366        if ( retnode == NULL ) {
2367            croak( "Copy node failed" );
2368        }
2369
2370        RETVAL =  PmmNodeToGdomeSv( retnode );
2371    OUTPUT:
2372        RETVAL
2373
2374
2375int
2376load_catalog( self, filename )
2377        SV * self
2378        SV * filename
2379    PREINIT:
2380        const char * fn = (const char *) Sv2C(filename, NULL);
2381    INIT:
2382        if ( fn == NULL || xmlStrlen( (xmlChar *)fn ) == 0 ) {
2383            croak( "cannot load catalog" );
2384        }
2385    CODE:
2386#ifdef LIBXML_CATALOG_ENABLED
2387        RETVAL = xmlLoadCatalog( fn );
2388#else
2389        XSRETURN_UNDEF;
2390#endif
2391    OUTPUT:
2392        RETVAL
2393
2394
2395
2396int
2397_default_catalog( self, catalog )
2398        SV * self
2399        SV * catalog
2400    PREINIT:
2401#ifdef LIBXML_CATALOG_ENABLED
2402        xmlCatalogPtr catal = (xmlCatalogPtr)SvIV(SvRV(catalog));
2403#endif
2404    INIT:
2405        if ( catal == NULL ) {
2406            croak( "empty catalog\n" );
2407        }
2408    CODE:
2409        warn( "this feature is not implemented" );
2410        RETVAL = 0;
2411    OUTPUT:
2412        RETVAL
2413
2414MODULE = XML::LibXML         PACKAGE = XML::LibXML::ParserContext
2415
2416void
2417DESTROY( self )
2418        SV * self
2419    CODE:
2420        xs_warn( "DROP PARSER CONTEXT!" );
2421        PmmContextREFCNT_dec( SvPROXYNODE( self ) );
2422
2423
2424MODULE = XML::LibXML         PACKAGE = XML::LibXML::Document
2425
2426SV *
2427_toString(self, format=0)
2428        xmlDocPtr self
2429        int format
2430    PREINIT:
2431        /* SV * saved_error = sv_2mortal(newSVpv("",0)); */
2432        xmlChar *result=NULL;
2433        int len=0;
2434        SV* internalFlag = NULL;
2435        int oldTagFlag = xmlSaveNoEmptyTags;
2436        xmlDtdPtr intSubset = NULL;
2437    CODE:
2438        RETVAL = &PL_sv_undef;
2439        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
2440        if( internalFlag ) {
2441            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
2442        }
2443
2444        internalFlag = perl_get_sv("XML::LibXML::skipDTD", 0);
2445        if ( internalFlag && SvTRUE(internalFlag) ) {
2446            intSubset = xmlGetIntSubset( self );
2447            if ( intSubset )
2448                xmlUnlinkNode( (xmlNodePtr)intSubset );
2449        }
2450
2451        /* LibXML_init_error_ctx(saved_error); */
2452
2453        if ( format <= 0 ) {
2454            xs_warn( "use no formated toString!" );
2455            xmlDocDumpMemory(self, &result, &len);
2456        }
2457        else {
2458            int t_indent_var = xmlIndentTreeOutput;
2459            xs_warn( "use formated toString!" );
2460            xmlIndentTreeOutput = 1;
2461            xmlDocDumpFormatMemory( self, &result, &len, format );
2462            xmlIndentTreeOutput = t_indent_var;
2463        }
2464
2465        if ( intSubset != NULL ) {
2466            if (self->children == NULL) {
2467                xmlAddChild((xmlNodePtr) self, (xmlNodePtr) intSubset);
2468            }
2469            else {
2470                xmlAddPrevSibling(self->children, (xmlNodePtr) intSubset);
2471            }
2472        }
2473
2474        xmlSaveNoEmptyTags = oldTagFlag;
2475
2476        /* LibXML_report_error_ctx(saved_error, 0); */
2477
2478        if (result == NULL) {
2479            xs_warn("Failed to convert doc to string");
2480            XSRETURN_UNDEF;
2481        } else {
2482            /* warn("%s, %d\n",result, len); */
2483            RETVAL = newSVpvn( (const char *)result, len );
2484	    /* C2Sv( result, self->encoding ); */
2485            xmlFree(result);
2486        }
2487    OUTPUT:
2488        RETVAL
2489
2490int
2491toFH( self, filehandler, format=0 )
2492        xmlDocPtr self
2493        SV * filehandler
2494        int format
2495    PREINIT:
2496        SV * saved_error = sv_2mortal(newSVpv("",0));
2497        xmlOutputBufferPtr buffer;
2498        const xmlChar * encoding = NULL;
2499        xmlCharEncodingHandlerPtr handler = NULL;
2500        SV* internalFlag = NULL;
2501        int oldTagFlag = xmlSaveNoEmptyTags;
2502        xmlDtdPtr intSubset = NULL;
2503        int t_indent_var = xmlIndentTreeOutput;
2504    CODE:
2505        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
2506        if( internalFlag ) {
2507            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
2508        }
2509
2510        internalFlag = perl_get_sv("XML::LibXML::skipDTD", 0);
2511        if ( internalFlag && SvTRUE(internalFlag) ) {
2512            intSubset = xmlGetIntSubset( self );
2513            if ( intSubset )
2514                xmlUnlinkNode( (xmlNodePtr)intSubset );
2515        }
2516
2517        xmlRegisterDefaultOutputCallbacks();
2518        encoding = (self)->encoding;
2519        if ( encoding != NULL ) {
2520            if ( xmlParseCharEncoding((const char*)encoding) != XML_CHAR_ENCODING_UTF8) {
2521                handler = xmlFindCharEncodingHandler((const char*)encoding);
2522            }
2523
2524        }
2525        else {
2526            xs_warn("no encoding?");
2527        }
2528
2529        buffer = xmlOutputBufferCreateIO( (xmlOutputWriteCallback) &LibXML_output_write_handler,
2530                                          (xmlOutputCloseCallback)&LibXML_output_close_handler,
2531                                          filehandler,
2532                                          handler );
2533
2534        if ( format <= 0 ) {
2535            format = 0;
2536            xmlIndentTreeOutput = 0;
2537        }
2538        else {
2539            xmlIndentTreeOutput = 1;
2540        }
2541
2542        LibXML_init_error_ctx(saved_error);
2543
2544        RETVAL = xmlSaveFormatFileTo( buffer,
2545                                      self,
2546                                      (const char *) encoding,
2547                                      format);
2548
2549        if ( intSubset != NULL ) {
2550            if (self->children == NULL) {
2551                xmlAddChild((xmlNodePtr) self, (xmlNodePtr) intSubset);
2552            }
2553            else {
2554                xmlAddPrevSibling(self->children, (xmlNodePtr) intSubset);
2555            }
2556        }
2557
2558        xmlIndentTreeOutput = t_indent_var;
2559        xmlSaveNoEmptyTags = oldTagFlag;
2560
2561        LibXML_report_error_ctx(saved_error, 0);
2562    OUTPUT:
2563        RETVAL
2564
2565int
2566toFile( self, filename, format=0 )
2567        xmlDocPtr self
2568        char * filename
2569        int format
2570    PREINIT:
2571        SV * saved_error = sv_2mortal(newSVpv("",0));
2572        SV* internalFlag = NULL;
2573        int oldTagFlag = xmlSaveNoEmptyTags;
2574    CODE:
2575        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
2576        if( internalFlag ) {
2577            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
2578        }
2579
2580        LibXML_init_error_ctx(saved_error);
2581
2582        if ( format <= 0 ) {
2583            xs_warn( "use no formated toFile!" );
2584            RETVAL = xmlSaveFile( filename, self );
2585        }
2586        else {
2587            int t_indent_var = xmlIndentTreeOutput;
2588            xmlIndentTreeOutput = 1;
2589            RETVAL =xmlSaveFormatFile( filename,
2590                                       self,
2591                                       format);
2592            xmlIndentTreeOutput = t_indent_var;
2593        }
2594
2595        xmlSaveNoEmptyTags = oldTagFlag;
2596
2597        LibXML_report_error_ctx(saved_error, 0);
2598
2599        if ( RETVAL > 0 )
2600            RETVAL = 1;
2601        else
2602            XSRETURN_UNDEF;
2603    OUTPUT:
2604        RETVAL
2605
2606SV *
2607toStringHTML(self)
2608        xmlDocPtr self
2609    ALIAS:
2610       XML::LibXML::Document::serialize_html = 1
2611    PREINIT:
2612        SV * saved_error = sv_2mortal(newSVpv("",0));
2613        xmlChar *result=NULL;
2614        STRLEN len = 0;
2615    CODE:
2616        xs_warn( "use no formated toString!" );
2617        LibXML_init_error_ctx(saved_error);
2618        htmlDocDumpMemory(self, &result, (int*)&len);
2619
2620        LibXML_report_error_ctx(saved_error, 0);
2621
2622        if (result == NULL) {
2623            XSRETURN_UNDEF;
2624        } else {
2625            /* warn("%s, %d\n",result, len); */
2626            RETVAL = newSVpvn((char *)result, (STRLEN)len);
2627            xmlFree(result);
2628        }
2629    OUTPUT:
2630        RETVAL
2631
2632
2633const char *
2634URI( self )
2635        xmlDocPtr self
2636    ALIAS:
2637        XML::LibXML::Document::documentURI = 1
2638    CODE:
2639        RETVAL = (const char*)xmlStrdup(self->URL );
2640    OUTPUT:
2641        RETVAL
2642
2643void
2644setBaseURI( self, new_URI )
2645        xmlDocPtr self
2646        char * new_URI
2647    CODE:
2648        if (new_URI) {
2649            xmlFree((xmlChar*)self->URL );
2650            self->URL = xmlStrdup((const xmlChar*)new_URI);
2651        }
2652
2653
2654SV*
2655createDocument( CLASS, version="1.0", encoding=NULL )
2656        char * CLASS
2657        char * version
2658        char * encoding
2659    ALIAS:
2660        XML::LibXML::Document::new = 1
2661    PREINIT:
2662        xmlDocPtr doc=NULL;
2663    CODE:
2664        doc = xmlNewDoc((const xmlChar*)version);
2665        if (encoding && *encoding != 0) {
2666            doc->encoding = (const xmlChar*)xmlStrdup((const xmlChar*)encoding);
2667        }
2668        RETVAL = PmmNodeToSv((xmlNodePtr)doc,NULL);
2669    OUTPUT:
2670        RETVAL
2671
2672SV*
2673createInternalSubset( self, Pname, extID, sysID )
2674        xmlDocPtr self
2675        SV * Pname
2676        SV * extID
2677        SV * sysID
2678    PREINIT:
2679        xmlDtdPtr dtd = NULL;
2680        xmlChar * name = NULL;
2681        xmlChar * externalID = NULL;
2682        xmlChar * systemID = NULL;
2683    CODE:
2684        name = Sv2C( Pname, NULL );
2685        if ( name == NULL ) {
2686            XSRETURN_UNDEF;
2687        }
2688
2689        externalID = Sv2C(extID, NULL);
2690        systemID   = Sv2C(sysID, NULL);
2691
2692        dtd = xmlCreateIntSubset( self, name, externalID, systemID );
2693        xmlFree(externalID);
2694        xmlFree(systemID);
2695        xmlFree(name);
2696        if ( dtd ) {
2697            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
2698        }
2699        else {
2700            XSRETURN_UNDEF;
2701        }
2702    OUTPUT:
2703        RETVAL
2704
2705SV*
2706createExternalSubset( self, Pname, extID, sysID )
2707        xmlDocPtr self
2708        SV * Pname
2709        SV * extID
2710        SV * sysID
2711    PREINIT:
2712        xmlDtdPtr dtd = NULL;
2713        xmlChar * name = NULL;
2714        xmlChar * externalID = NULL;
2715        xmlChar * systemID = NULL;
2716    CODE:
2717        name = Sv2C( Pname, NULL );
2718        if ( name == NULL ) {
2719            XSRETURN_UNDEF;
2720        }
2721
2722        externalID = Sv2C(extID, NULL);
2723        systemID   = Sv2C(sysID, NULL);
2724
2725        dtd = xmlNewDtd( self, name, externalID, systemID );
2726
2727        xmlFree(externalID);
2728        xmlFree(systemID);
2729        xmlFree(name);
2730        if ( dtd ) {
2731            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
2732        }
2733        else {
2734            XSRETURN_UNDEF;
2735        }
2736    OUTPUT:
2737        RETVAL
2738
2739SV*
2740createDTD( self, Pname, extID, sysID )
2741        xmlDocPtr self
2742        SV * Pname
2743        SV * extID
2744        SV * sysID
2745    PREINIT:
2746        xmlDtdPtr dtd = NULL;
2747        xmlChar * name = NULL;
2748        xmlChar * externalID = NULL;
2749        xmlChar * systemID = NULL;
2750    CODE:
2751        name = Sv2C( Pname, NULL );
2752        if ( name == NULL ) {
2753            XSRETURN_UNDEF;
2754        }
2755
2756        externalID = Sv2C(extID, NULL);
2757        systemID   = Sv2C(sysID, NULL);
2758
2759        dtd = xmlNewDtd( NULL, name, externalID, systemID );
2760        dtd->doc = self;
2761
2762        xmlFree(externalID);
2763        xmlFree(systemID);
2764        xmlFree(name);
2765        if ( dtd ) {
2766            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
2767        }
2768        else {
2769            XSRETURN_UNDEF;
2770        }
2771    OUTPUT:
2772        RETVAL
2773
2774SV*
2775createDocumentFragment( self )
2776        xmlDocPtr self
2777    CODE:
2778        RETVAL = PmmNodeToSv(xmlNewDocFragment(self), PmmPROXYNODE(self));
2779    OUTPUT:
2780        RETVAL
2781
2782SV*
2783createElement( self, name )
2784        xmlDocPtr self
2785        SV* name
2786    PREINIT:
2787        xmlNodePtr newNode;
2788        xmlChar * elname = NULL;
2789        ProxyNodePtr docfrag = NULL;
2790    CODE:
2791        elname = nodeSv2C( name , (xmlNodePtr) self);
2792        if ( !LibXML_test_node_name( elname ) ) {
2793            xmlFree( elname );
2794            croak( "bad name" );
2795        }
2796
2797        newNode = xmlNewNode(NULL , elname);
2798        xmlFree(elname);
2799        if ( newNode != NULL ) {
2800            docfrag = PmmNewFragment( self );
2801            newNode->doc = self;
2802            xmlAddChild(PmmNODE(docfrag), newNode);
2803            RETVAL = PmmNodeToSv(newNode,docfrag);
2804        }
2805        else {
2806            xs_warn( "no node created!" );
2807            XSRETURN_UNDEF;
2808        }
2809    OUTPUT:
2810        RETVAL
2811
2812SV*
2813createRawElement( self, name )
2814        xmlDocPtr self
2815        SV* name
2816    PREINIT:
2817        xmlNodePtr newNode;
2818        xmlChar * elname = NULL;
2819        ProxyNodePtr docfrag = NULL;
2820    CODE:
2821        elname = nodeSv2C( name , (xmlNodePtr) self);
2822        if ( !elname || xmlStrlen(elname) <= 0 ) {
2823            xmlFree( elname );
2824            croak( "bad name" );
2825        }
2826
2827        newNode = xmlNewDocNode(self,NULL , elname, NULL);
2828        xmlFree(elname);
2829        if ( newNode != NULL ) {
2830            docfrag = PmmNewFragment( self );
2831            xmlAddChild(PmmNODE(docfrag), newNode);
2832            RETVAL = PmmNodeToSv(newNode,docfrag);
2833        }
2834        else {
2835            xs_warn( "no node created!" );
2836            XSRETURN_UNDEF;
2837        }
2838    OUTPUT:
2839        RETVAL
2840
2841SV*
2842createElementNS( self, nsURI, name )
2843        xmlDocPtr self
2844        SV * nsURI
2845        SV * name
2846    PREINIT:
2847        xmlChar * ename        = NULL;
2848        xmlChar * prefix       = NULL;
2849        xmlChar * localname    = NULL;
2850        xmlChar * eURI         = NULL;
2851        xmlNsPtr ns            = NULL;
2852        ProxyNodePtr docfrag   = NULL;
2853        xmlNodePtr newNode     = NULL;
2854    CODE:
2855        ename = nodeSv2C( name , (xmlNodePtr) self );
2856        if ( !LibXML_test_node_name( ename ) ) {
2857            xmlFree( ename );
2858            croak( "bad name" );
2859        }
2860
2861        eURI  = Sv2C( nsURI , NULL );
2862
2863        if ( eURI != NULL && xmlStrlen(eURI)!=0 ){
2864            localname = xmlSplitQName2(ename, &prefix);
2865            if ( localname == NULL ) {
2866                localname = xmlStrdup( ename );
2867            }
2868
2869			ns = xmlNewNs( NULL, eURI, prefix );
2870            newNode = xmlNewDocNode( self, ns, localname, NULL );
2871			newNode->nsDef = ns;
2872
2873            xmlFree(localname);
2874        }
2875        else {
2876            xs_warn( " ordinary element " );
2877            /* ordinary element */
2878            localname = ename;
2879
2880            newNode = xmlNewDocNode( self, NULL , localname, NULL );
2881        }
2882
2883        docfrag = PmmNewFragment( self );
2884        xmlAddChild(PmmNODE(docfrag), newNode);
2885        RETVAL = PmmNodeToSv(newNode, docfrag);
2886
2887        if ( prefix != NULL ) {
2888            xmlFree(prefix);
2889        }
2890        if ( eURI != NULL ) {
2891            xmlFree(eURI);
2892        }
2893        xmlFree(ename);
2894    OUTPUT:
2895        RETVAL
2896
2897SV*
2898createRawElementNS( self, nsURI, name )
2899        xmlDocPtr self
2900        SV * nsURI
2901        SV * name
2902    PREINIT:
2903        xmlChar * ename        = NULL;
2904        xmlChar * prefix       = NULL;
2905        xmlChar * localname    = NULL;
2906        xmlChar * eURI         = NULL;
2907        xmlNsPtr ns            = NULL;
2908        ProxyNodePtr docfrag   = NULL;
2909        xmlNodePtr newNode     = NULL;
2910    CODE:
2911        ename = nodeSv2C( name , (xmlNodePtr) self );
2912        if ( !LibXML_test_node_name( ename ) ) {
2913            xmlFree( ename );
2914            croak( "bad name" );
2915        }
2916
2917        eURI  = Sv2C( nsURI , NULL );
2918
2919        if ( eURI != NULL && xmlStrlen(eURI)!=0 ){
2920            localname = xmlSplitQName2(ename, &prefix);
2921            if ( localname == NULL ) {
2922                localname = xmlStrdup( ename );
2923            }
2924
2925            newNode = xmlNewDocNode( self,NULL , localname, NULL );
2926
2927            ns = xmlSearchNsByHref( self, newNode, eURI );
2928            if ( ns == NULL ) {
2929                /* create a new NS if the NS does not already exists */
2930                ns = xmlNewNs(newNode, eURI , prefix );
2931            }
2932
2933            if ( ns == NULL ) {
2934                xmlFreeNode( newNode );
2935                xmlFree(eURI);
2936                xmlFree(localname);
2937                if ( prefix != NULL ) {
2938                    xmlFree(prefix);
2939                }
2940                xmlFree(ename);
2941                XSRETURN_UNDEF;
2942            }
2943
2944            xmlFree(localname);
2945        }
2946        else {
2947            xs_warn( " ordinary element " );
2948            /* ordinary element */
2949            localname = ename;
2950
2951            newNode = xmlNewDocNode( self, NULL , localname, NULL );
2952        }
2953
2954        xmlSetNs(newNode, ns);
2955        docfrag = PmmNewFragment( self );
2956        xmlAddChild(PmmNODE(docfrag), newNode);
2957        RETVAL = PmmNodeToSv(newNode, docfrag);
2958
2959        if ( prefix != NULL ) {
2960            xmlFree(prefix);
2961        }
2962        if ( eURI != NULL ) {
2963            xmlFree(eURI);
2964        }
2965        xmlFree(ename);
2966    OUTPUT:
2967        RETVAL
2968
2969SV *
2970createTextNode( self, content )
2971        xmlDocPtr self
2972        SV * content
2973    PREINIT:
2974        xmlNodePtr newNode;
2975        xmlChar * elname = NULL;
2976        ProxyNodePtr docfrag = NULL;
2977    CODE:
2978        elname = nodeSv2C( content , (xmlNodePtr) self );
2979        if ( elname != NULL || xmlStrlen(elname) > 0 ) {
2980            newNode = xmlNewDocText( self, elname );
2981            xmlFree(elname);
2982            if ( newNode != NULL ) {
2983                docfrag = PmmNewFragment( self );
2984                newNode->doc = self;
2985                xmlAddChild(PmmNODE(docfrag), newNode);
2986                RETVAL = PmmNodeToSv(newNode,docfrag);
2987            }
2988            else {
2989                xs_warn( "no node created!" );
2990                XSRETURN_UNDEF;
2991            }
2992        }
2993        else {
2994            XSRETURN_UNDEF;
2995        }
2996    OUTPUT:
2997        RETVAL
2998
2999SV *
3000createComment( self , content )
3001        xmlDocPtr self
3002        SV * content
3003    PREINIT:
3004        xmlNodePtr newNode;
3005        xmlChar * elname = NULL;
3006        ProxyNodePtr docfrag = NULL;
3007    CODE:
3008        elname = nodeSv2C( content , (xmlNodePtr) self );
3009        if ( elname != NULL || xmlStrlen(elname) > 0 ) {
3010            newNode = xmlNewDocComment( self, elname );
3011            xmlFree(elname);
3012            if ( newNode != NULL ) {
3013                docfrag = PmmNewFragment( self );
3014                newNode->doc = self;
3015                xmlAddChild(PmmNODE(docfrag), newNode);
3016                xs_warn( newNode->name );
3017                RETVAL = PmmNodeToSv(newNode,docfrag);
3018            }
3019            else {
3020                xs_warn( "no node created!" );
3021                XSRETURN_UNDEF;
3022            }
3023        }
3024        else {
3025            XSRETURN_UNDEF;
3026        }
3027    OUTPUT:
3028        RETVAL
3029
3030SV *
3031createCDATASection( self, content )
3032        xmlDocPtr self
3033        SV * content
3034    PREINIT:
3035        xmlNodePtr newNode;
3036        xmlChar * elname = NULL;
3037        ProxyNodePtr docfrag = NULL;
3038    CODE:
3039        elname = nodeSv2C( content , (xmlNodePtr)self );
3040        if ( elname != NULL || xmlStrlen(elname) > 0 ) {
3041            newNode = xmlNewCDataBlock( self, elname, xmlStrlen(elname) );
3042            xmlFree(elname);
3043            if ( newNode != NULL ) {
3044                docfrag = PmmNewFragment( self );
3045                newNode->doc = self;
3046                xmlAddChild(PmmNODE(docfrag), newNode);
3047                xs_warn( "[CDATA section]" );
3048                RETVAL = PmmNodeToSv(newNode,docfrag);
3049            }
3050            else {
3051                xs_warn( "no node created!" );
3052                XSRETURN_UNDEF;
3053            }
3054        }
3055        else {
3056            XSRETURN_UNDEF;
3057        }
3058    OUTPUT:
3059        RETVAL
3060
3061SV*
3062createEntityReference( self , pname )
3063        xmlDocPtr self
3064        SV * pname
3065    PREINIT:
3066        xmlNodePtr newNode;
3067        xmlChar * name = Sv2C( pname, NULL );
3068        ProxyNodePtr docfrag = NULL;
3069    CODE:
3070        if ( name == NULL ) {
3071            XSRETURN_UNDEF;
3072        }
3073        newNode = xmlNewReference( self, name );
3074        xmlFree(name);
3075        if ( newNode == NULL ) {
3076            XSRETURN_UNDEF;
3077        }
3078        docfrag = PmmNewFragment( self );
3079        xmlAddChild(PmmNODE(docfrag), newNode);
3080        RETVAL = PmmNodeToSv( newNode, docfrag );
3081    OUTPUT:
3082        RETVAL
3083
3084SV*
3085createAttribute( self, pname, pvalue=&PL_sv_undef )
3086        xmlDocPtr self
3087        SV * pname
3088        SV * pvalue
3089    PREINIT:
3090        xmlChar * name = NULL;
3091        xmlChar * value = NULL;
3092        xmlAttrPtr newAttr = NULL;
3093    CODE:
3094        name = nodeSv2C( pname , (xmlNodePtr) self );
3095        if ( !LibXML_test_node_name( name ) ) {
3096            xmlFree(name);
3097            XSRETURN_UNDEF;
3098        }
3099
3100        value = nodeSv2C( pvalue , (xmlNodePtr) self );
3101        newAttr = xmlNewDocProp( self, name, value );
3102        RETVAL = PmmNodeToSv((xmlNodePtr)newAttr, PmmPROXYNODE(self));
3103
3104        xmlFree(name);
3105        if ( value ) {
3106            xmlFree(value);
3107        }
3108    OUTPUT:
3109        RETVAL
3110
3111SV*
3112createAttributeNS( self, URI, pname, pvalue=&PL_sv_undef )
3113        xmlDocPtr self
3114        SV * URI
3115        SV * pname
3116        SV * pvalue
3117    PREINIT:
3118        xmlChar * name = NULL;
3119        xmlChar * value = NULL;
3120        xmlChar * prefix = NULL;
3121        const xmlChar * pchar = NULL;
3122        xmlChar * localname = NULL;
3123        xmlChar * nsURI = NULL;
3124        xmlAttrPtr newAttr = NULL;
3125        xmlNsPtr ns = NULL;
3126    CODE:
3127        name = nodeSv2C( pname , (xmlNodePtr) self );
3128        if ( !LibXML_test_node_name( name ) ) {
3129            xmlFree(name);
3130            XSRETURN_UNDEF;
3131        }
3132
3133        nsURI = Sv2C( URI , NULL );
3134        value = nodeSv2C( pvalue, (xmlNodePtr) self  );
3135
3136        if ( nsURI != NULL && xmlStrlen(nsURI) > 0 ) {
3137            xmlNodePtr root = xmlDocGetRootElement(self );
3138            if ( root ) {
3139                pchar = xmlStrchr(name, ':');
3140                if ( pchar != NULL ) {
3141                    localname = xmlSplitQName2(name, &prefix);
3142                }
3143                else {
3144                    localname = xmlStrdup( name );
3145                }
3146                ns = xmlSearchNsByHref( self, root, nsURI );
3147                if ( ns == NULL ) {
3148                    /* create a new NS if the NS does not already exists */
3149                    ns = xmlNewNs(root, nsURI , prefix );
3150                }
3151
3152                if ( ns == NULL ) {
3153                    xmlFree(nsURI);
3154                    xmlFree(localname);
3155                    if ( prefix ) {
3156                        xmlFree(prefix);
3157                    }
3158                    xmlFree(name);
3159                    if ( value ) {
3160                        xmlFree(value);
3161                    }
3162                    XSRETURN_UNDEF;
3163                }
3164
3165                newAttr = xmlNewDocProp( self, localname, value );
3166                xmlSetNs((xmlNodePtr)newAttr, ns);
3167
3168                RETVAL = PmmNodeToSv((xmlNodePtr)newAttr, PmmPROXYNODE(self) );
3169
3170                xmlFree(nsURI);
3171                xmlFree(name);
3172                if ( prefix ) {
3173                    xmlFree(prefix);
3174                }
3175                xmlFree(localname);
3176                if ( value ) {
3177                    xmlFree(value);
3178                }
3179            }
3180            else {
3181                croak( "can't create a new namespace on an attribute!" );
3182                xmlFree(name);
3183                if ( value ) {
3184                    xmlFree(value);
3185                }
3186                XSRETURN_UNDEF;
3187            }
3188        }
3189        else {
3190            newAttr = xmlNewDocProp( self, name, value );
3191            RETVAL = PmmNodeToSv((xmlNodePtr)newAttr,PmmPROXYNODE(self));
3192            xmlFree(name);
3193            if ( value ) {
3194                xmlFree(value);
3195            }
3196        }
3197    OUTPUT:
3198        RETVAL
3199
3200SV*
3201createProcessingInstruction(self, name, value=&PL_sv_undef)
3202        xmlDocPtr self
3203        SV * name
3204        SV * value
3205    ALIAS:
3206        createPI = 1
3207    PREINIT:
3208        xmlChar * n = NULL;
3209        xmlChar * v = NULL;
3210        xmlNodePtr newNode = NULL;
3211        ProxyNodePtr docfrag = NULL;
3212    CODE:
3213        n = nodeSv2C(name, (xmlNodePtr)self);
3214        if ( !n ) {
3215            XSRETURN_UNDEF;
3216        }
3217        v = nodeSv2C(value, (xmlNodePtr)self);
3218        newNode = xmlNewPI(n,v);
3219        xmlFree(v);
3220        xmlFree(n);
3221	if ( newNode != NULL ) {
3222 	   docfrag = PmmNewFragment( self );
3223           newNode->doc = self;
3224	   xmlAddChild(PmmNODE(docfrag), newNode);
3225	   RETVAL = PmmNodeToSv(newNode,docfrag);
3226	} else {
3227 	   xs_warn( "no node created!" );
3228 	   XSRETURN_UNDEF;
3229        }
3230    OUTPUT:
3231        RETVAL
3232
3233void
3234_setDocumentElement( self , proxy )
3235        xmlDocPtr self
3236        SV * proxy
3237    PREINIT:
3238        xmlNodePtr elem, oelem;
3239    INIT:
3240        elem = PmmSvNode(proxy);
3241        if ( elem == NULL ) {
3242            XSRETURN_UNDEF;
3243        }
3244    CODE:
3245        /* please correct me if i am wrong: the document element HAS to be
3246         * an ELEMENT NODE
3247         */
3248        if ( elem->type == XML_ELEMENT_NODE ) {
3249            if ( self != elem->doc ) {
3250	        domImportNode( self, elem, 1, 1 );
3251            }
3252
3253            oelem = xmlDocGetRootElement( self );
3254            if ( oelem == NULL || oelem->_private == NULL ) {
3255                xmlDocSetRootElement( self, elem );
3256            }
3257            else {
3258                ProxyNodePtr docfrag = PmmNewFragment( self );
3259                xmlReplaceNode( oelem, elem );
3260                xmlAddChild( PmmNODE(docfrag), oelem );
3261                PmmFixOwner( ((ProxyNodePtr)oelem->_private), docfrag);
3262            }
3263
3264            if ( elem->_private != NULL ) {
3265                PmmFixOwner( SvPROXYNODE(proxy), PmmPROXYNODE(self));
3266            }
3267        }
3268
3269SV *
3270documentElement( self )
3271        xmlDocPtr self
3272    ALIAS:
3273        XML::LibXML::Document::getDocumentElement = 1
3274    PREINIT:
3275        xmlNodePtr elem;
3276    CODE:
3277        elem = xmlDocGetRootElement( self );
3278        if ( elem ) {
3279            RETVAL = PmmNodeToSv(elem, PmmPROXYNODE(self));
3280        }
3281        else {
3282            XSRETURN_UNDEF;
3283        }
3284    OUTPUT:
3285        RETVAL
3286
3287SV *
3288externalSubset( self )
3289        xmlDocPtr self
3290    PREINIT:
3291        xmlDtdPtr dtd;
3292    CODE:
3293        if ( self->extSubset == NULL ) {
3294            XSRETURN_UNDEF;
3295        }
3296
3297        dtd = self->extSubset;
3298        RETVAL = PmmNodeToSv((xmlNodePtr)dtd, PmmPROXYNODE(self));
3299    OUTPUT:
3300        RETVAL
3301
3302SV *
3303internalSubset( self )
3304        xmlDocPtr self
3305    PREINIT:
3306        xmlDtdPtr dtd;
3307    CODE:
3308        if ( self->intSubset == NULL ) {
3309            XSRETURN_UNDEF;
3310        }
3311
3312        dtd = self->intSubset;
3313        RETVAL = PmmNodeToSv((xmlNodePtr)dtd, PmmPROXYNODE(self));
3314    OUTPUT:
3315        RETVAL
3316
3317void
3318setExternalSubset( self, extdtd )
3319        xmlDocPtr self
3320        SV * extdtd
3321    PREINIT:
3322        xmlDtdPtr dtd = NULL;
3323        xmlDtdPtr olddtd = NULL;
3324    INIT:
3325        dtd = (xmlDtdPtr)PmmSvNode(extdtd);
3326        if ( dtd == NULL ) {
3327            croak( "lost DTD node" );
3328        }
3329    CODE:
3330        if ( dtd && dtd != self->extSubset ) {
3331            if ( dtd->doc == NULL ) {
3332                xmlSetTreeDoc( (xmlNodePtr) dtd, self );
3333            } else if ( dtd->doc != self ) {
3334	        domImportNode( self, (xmlNodePtr) dtd,1,1);
3335            }
3336
3337            if ( dtd == self->intSubset ) {
3338                xmlUnlinkNode( (xmlNodePtr)dtd );
3339                self->intSubset = NULL;
3340            }
3341
3342            olddtd = self->extSubset;
3343            if ( olddtd && olddtd->_private == NULL ) {
3344                xmlFreeDtd( olddtd );
3345            }
3346            self->extSubset = dtd;
3347        }
3348
3349void
3350setInternalSubset( self, extdtd )
3351        xmlDocPtr self
3352        SV * extdtd
3353    PREINIT:
3354        xmlDtdPtr dtd = NULL;
3355        xmlDtdPtr olddtd = NULL;
3356    INIT:
3357        dtd = (xmlDtdPtr)PmmSvNode(extdtd);
3358        if ( dtd == NULL ) {
3359            croak( "lost DTD node" );
3360        }
3361    CODE:
3362        if ( dtd && dtd != self->intSubset ) {
3363            if ( dtd->doc != self ) {
3364                croak( "can't import DTDs" );
3365                domImportNode( self, (xmlNodePtr) dtd,1,1);
3366            }
3367
3368            if ( dtd == self->extSubset ) {
3369                self->extSubset = NULL;
3370            }
3371
3372            olddtd = xmlGetIntSubset( self );
3373            if( olddtd ) {
3374                xmlReplaceNode( (xmlNodePtr)olddtd, (xmlNodePtr) dtd );
3375                if ( olddtd->_private == NULL ) {
3376                    xmlFreeDtd( olddtd );
3377                }
3378            }
3379            else {
3380                if (self->children == NULL)
3381                    xmlAddChild((xmlNodePtr) self, (xmlNodePtr) dtd);
3382                else
3383                    xmlAddPrevSibling(self->children, (xmlNodePtr) dtd);
3384            }
3385            self->intSubset = dtd;
3386        }
3387
3388SV *
3389removeInternalSubset( self )
3390        xmlDocPtr self
3391    PREINIT:
3392        xmlDtdPtr dtd = NULL;
3393    CODE:
3394        dtd = xmlGetIntSubset(self);
3395        if ( !dtd ) {
3396            XSRETURN_UNDEF;
3397        }
3398        xmlUnlinkNode( (xmlNodePtr)dtd );
3399        self->intSubset = NULL;
3400        RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
3401    OUTPUT:
3402        RETVAL
3403
3404SV *
3405removeExternalSubset( self )
3406        xmlDocPtr self
3407    PREINIT:
3408        xmlDtdPtr dtd = NULL;
3409    CODE:
3410        dtd = self->extSubset;
3411        if ( !dtd ) {
3412            XSRETURN_UNDEF;
3413        }
3414        self->extSubset = NULL;
3415        RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
3416    OUTPUT:
3417        RETVAL
3418
3419SV *
3420importNode( self, node, dummy=0 )
3421        xmlDocPtr self
3422        xmlNodePtr node
3423        int dummy
3424    PREINIT:
3425        xmlNodePtr ret = NULL;
3426        ProxyNodePtr docfrag = NULL;
3427    CODE:
3428        if ( node->type == XML_DOCUMENT_NODE
3429             || node->type == XML_HTML_DOCUMENT_NODE ) {
3430            croak( "Can't import Documents!" );
3431            XSRETURN_UNDEF;
3432        }
3433
3434        ret = domImportNode( self, node, 0, 1 );
3435        if ( ret ) {
3436            docfrag = PmmNewFragment( self );
3437            xmlAddChild( PmmNODE(docfrag), ret );
3438            RETVAL = PmmNodeToSv( ret, docfrag);
3439        }
3440        else {
3441            XSRETURN_UNDEF;
3442        }
3443    OUTPUT:
3444        RETVAL
3445
3446SV *
3447adoptNode( self, node )
3448        xmlDocPtr self
3449        xmlNodePtr node
3450    PREINIT:
3451        xmlNodePtr ret = NULL;
3452        ProxyNodePtr docfrag = NULL;
3453    CODE:
3454        if ( node->type == XML_DOCUMENT_NODE
3455             || node->type == XML_HTML_DOCUMENT_NODE ) {
3456            croak( "Can't adopt Documents!" );
3457            XSRETURN_UNDEF;
3458        }
3459
3460        ret = domImportNode( self, node, 1, 1 );
3461
3462        if ( ret ) {
3463            docfrag = PmmNewFragment( self );
3464            RETVAL = PmmNodeToSv(node, docfrag);
3465            xmlAddChild( PmmNODE(docfrag), ret );
3466            PmmFixOwner(SvPROXYNODE(RETVAL), docfrag);
3467        }
3468        else {
3469            XSRETURN_UNDEF;
3470        }
3471    OUTPUT:
3472        RETVAL
3473
3474char*
3475encoding( self )
3476        xmlDocPtr self
3477    ALIAS:
3478        XML::LibXML::Document::getEncoding    = 1
3479        XML::LibXML::Document::xmlEncoding    = 2
3480    CODE:
3481        RETVAL = (char *) self->encoding;
3482    OUTPUT:
3483        RETVAL
3484
3485void
3486setEncoding( self, encoding )
3487        xmlDocPtr self
3488        char *encoding
3489    PREINIT:
3490        int charset = XML_CHAR_ENCODING_ERROR;
3491    CODE:
3492        if ( self->encoding != NULL ) {
3493            xmlFree( (xmlChar*) self->encoding );
3494        }
3495        self->encoding = xmlStrdup( (const xmlChar *)encoding );
3496        charset = (int)xmlParseCharEncoding( (const char*)self->encoding );
3497        if ( charset > 0 ) {
3498            ((ProxyNodePtr)self->_private)->encoding = charset;
3499        }
3500        else {
3501            ((ProxyNodePtr)self->_private)->encoding = XML_CHAR_ENCODING_ERROR;
3502        }
3503
3504
3505int
3506standalone( self )
3507        xmlDocPtr self
3508    ALIAS:
3509        XML::LibXML::Document::xmlStandalone    = 1
3510    CODE:
3511        RETVAL = self->standalone;
3512    OUTPUT:
3513        RETVAL
3514
3515void
3516setStandalone( self, value = 0 )
3517        xmlDocPtr self
3518        int value
3519    CODE:
3520        if ( value > 0 ) {
3521            self->standalone = 1;
3522        }
3523        else if ( value < 0 ) {
3524            self->standalone = -1;
3525        }
3526        else {
3527            self->standalone = 0;
3528        }
3529
3530char*
3531version( self )
3532         xmlDocPtr self
3533    ALIAS:
3534        XML::LibXML::Document::getVersion = 1
3535        XML::LibXML::Document::xmlVersion = 2
3536    CODE:
3537        RETVAL = (char *) self->version;
3538    OUTPUT:
3539        RETVAL
3540
3541void
3542setVersion( self, version )
3543        xmlDocPtr self
3544        char *version
3545    CODE:
3546        if ( self->version != NULL ) {
3547            xmlFree( (xmlChar*) self->version );
3548        }
3549        self->version = xmlStrdup( (const xmlChar*)version );
3550
3551int
3552compression( self )
3553        xmlDocPtr self
3554    CODE:
3555        RETVAL = xmlGetDocCompressMode(self);
3556    OUTPUT:
3557        RETVAL
3558
3559void
3560setCompression( self, zLevel )
3561        xmlDocPtr self
3562        int zLevel
3563    CODE:
3564        xmlSetDocCompressMode(self, zLevel);
3565
3566
3567int
3568is_valid(self, ...)
3569        xmlDocPtr self
3570    PREINIT:
3571        SV * saved_error = sv_2mortal(newSVpv("",0));
3572        xmlValidCtxt cvp;
3573        xmlDtdPtr dtd = NULL;
3574        SV * dtd_sv;
3575    CODE:
3576        LibXML_init_error_ctx(saved_error);
3577
3578        cvp.userData = saved_error;
3579        cvp.error = (xmlValidityErrorFunc)LibXML_validity_error_ctx;
3580        cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning_ctx;
3581
3582        /* we need to initialize the node stack, because perl might
3583         * already have messed it up.
3584         */
3585        cvp.nodeNr = 0;
3586        cvp.nodeTab = NULL;
3587        cvp.vstateNr = 0;
3588        cvp.vstateTab = NULL;
3589
3590        if (items > 1) {
3591            dtd_sv = ST(1);
3592            if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
3593                dtd = (xmlDtdPtr)PmmSvNode(dtd_sv);
3594            }
3595            RETVAL = xmlValidateDtd(&cvp, self, dtd);
3596        }
3597        else {
3598            RETVAL = xmlValidateDocument(&cvp, self);
3599        }
3600
3601        /* LibXML_report_error_ctx(saved_error, 1); */
3602    OUTPUT:
3603        RETVAL
3604
3605int
3606validate(self, ...)
3607        xmlDocPtr self
3608    PREINIT:
3609        SV * saved_error = sv_2mortal(newSVpv("",0));
3610        xmlValidCtxt cvp;
3611        xmlDtdPtr dtd;
3612        SV * dtd_sv;
3613    CODE:
3614        LibXML_init_error_ctx(saved_error);
3615
3616        cvp.userData = saved_error;
3617        cvp.error = (xmlValidityErrorFunc)LibXML_validity_error_ctx;
3618        cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning_ctx;
3619        /* we need to initialize the node stack, because perl might
3620         * already have messed it up.
3621         */
3622        cvp.nodeNr = 0;
3623        cvp.nodeTab = NULL;
3624        cvp.vstateNr = 0;
3625        cvp.vstateTab = NULL;
3626
3627        if (items > 1) {
3628            dtd_sv = ST(1);
3629            if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
3630                dtd = (xmlDtdPtr)PmmSvNode(dtd_sv);
3631            }
3632            else {
3633                croak("is_valid: argument must be a DTD object");
3634            }
3635            RETVAL = xmlValidateDtd(&cvp, self , dtd);
3636        }
3637        else {
3638            RETVAL = xmlValidateDocument(&cvp, self);
3639        }
3640
3641        LibXML_report_error_ctx(saved_error, RETVAL ? 1 : 0);
3642    OUTPUT:
3643        RETVAL
3644
3645SV*
3646cloneNode( self, deep=0 )
3647        xmlDocPtr self
3648        int deep
3649    PREINIT:
3650        xmlDocPtr ret = NULL;
3651    CODE:
3652        ret = xmlCopyDoc( self, deep );
3653        if ( ret == NULL ) {
3654            XSRETURN_UNDEF;
3655        }
3656        RETVAL = PmmNodeToSv((xmlNodePtr)ret, NULL);
3657    OUTPUT:
3658        RETVAL
3659
3660SV*
3661getElementById( self, id )
3662        xmlDocPtr self
3663        const char * id
3664    ALIAS:
3665        XML::LibXML::Document::getElementsById = 1
3666    PREINIT:
3667        xmlNodePtr elem;
3668        xmlAttrPtr attr;
3669    CODE:
3670        if ( id != NULL ) {
3671            attr = xmlGetID(self, (xmlChar *) id);
3672            if (attr == NULL)
3673                elem = NULL;
3674            else if (attr->type == XML_ATTRIBUTE_NODE)
3675                elem = attr->parent;
3676            else if (attr->type == XML_ELEMENT_NODE)
3677                elem = (xmlNodePtr) attr;
3678            else
3679                elem = NULL;
3680            if (elem != NULL) {
3681                RETVAL = PmmNodeToSv(elem, PmmPROXYNODE(self));
3682            }
3683            else {
3684                XSRETURN_UNDEF;
3685            }
3686        }
3687        else {
3688            XSRETURN_UNDEF;
3689        }
3690    OUTPUT:
3691        RETVAL
3692
3693int
3694indexElements ( self )
3695        xmlDocPtr self
3696     CODE:
3697#if LIBXML_VERSION >= 20508
3698        RETVAL = xmlXPathOrderDocElems( self );
3699#else
3700        RETVAL = -2;
3701#endif
3702     OUTPUT:
3703        RETVAL
3704
3705MODULE = XML::LibXML         PACKAGE = XML::LibXML::Node
3706
3707void
3708DESTROY( node )
3709        SV * node
3710    CODE:
3711        xs_warn("DESTROY PERL NODE\n");
3712        PmmREFCNT_dec(SvPROXYNODE(node));
3713
3714SV*
3715nodeName( self )
3716        xmlNodePtr self
3717    ALIAS:
3718        XML::LibXML::Node::getName = 1
3719        XML::LibXML::Element::tagName = 2
3720    PREINIT:
3721        xmlChar * name = NULL;
3722    CODE:
3723        name =  (xmlChar*)domName( self );
3724        if ( name != NULL ) {
3725            RETVAL = C2Sv(name,NULL);
3726            xmlFree( name );
3727        }
3728        else {
3729            XSRETURN_UNDEF;
3730        }
3731    OUTPUT:
3732        RETVAL
3733
3734SV*
3735localname( self )
3736        xmlNodePtr self
3737    ALIAS:
3738        XML::LibXML::Node::getLocalName = 1
3739        XML::LibXML::Attr::name         = 2
3740        XML::LibXML::Node::localName    = 3
3741    CODE:
3742        if (    self->type == XML_ELEMENT_NODE
3743             || self->type == XML_ATTRIBUTE_NODE
3744             || self->type == XML_ELEMENT_DECL
3745             || self->type == XML_ATTRIBUTE_DECL ) {
3746            RETVAL = C2Sv(self->name,NULL);
3747        }
3748        else {
3749            XSRETURN_UNDEF;
3750        }
3751    OUTPUT:
3752        RETVAL
3753
3754SV*
3755prefix( self )
3756        xmlNodePtr self
3757    ALIAS:
3758        XML::LibXML::Node::getPrefix = 1
3759    CODE:
3760        if( self->ns != NULL
3761            && self->ns->prefix != NULL ) {
3762            RETVAL = C2Sv(self->ns->prefix, NULL);
3763        }
3764        else {
3765            XSRETURN_UNDEF;
3766        }
3767    OUTPUT:
3768        RETVAL
3769
3770SV*
3771namespaceURI( self )
3772        xmlNodePtr self
3773    ALIAS:
3774        getNamespaceURI = 1
3775    PREINIT:
3776        xmlChar * nsURI;
3777    CODE:
3778        if ( self->ns != NULL
3779             && self->ns->href != NULL ) {
3780            nsURI =  xmlStrdup(self->ns->href);
3781            RETVAL = C2Sv( nsURI, NULL );
3782            xmlFree( nsURI );
3783        }
3784        else {
3785            XSRETURN_UNDEF;
3786        }
3787    OUTPUT:
3788        RETVAL
3789
3790
3791SV*
3792lookupNamespaceURI( self, svprefix=&PL_sv_undef )
3793        xmlNodePtr self
3794        SV * svprefix
3795    PREINIT:
3796        xmlChar * nsURI;
3797        xmlChar * prefix = NULL;
3798        xmlNsPtr ns;
3799    CODE:
3800        prefix = nodeSv2C( svprefix , self );
3801        if ( prefix != NULL && xmlStrlen(prefix) == 0) {
3802            xmlFree( prefix );
3803            prefix = NULL;
3804        }
3805        ns = xmlSearchNs( self->doc, self, prefix );
3806        if ( prefix != NULL) {
3807            xmlFree( prefix );
3808	}
3809        if ( ns != NULL ) {
3810	  nsURI = xmlStrdup(ns->href);
3811	  RETVAL = C2Sv( nsURI, NULL );
3812	  xmlFree( nsURI );
3813	}
3814	else {
3815	  XSRETURN_UNDEF;
3816        }
3817    OUTPUT:
3818        RETVAL
3819
3820SV*
3821lookupNamespacePrefix( self, svuri )
3822        xmlNodePtr self
3823        SV * svuri
3824    PREINIT:
3825        xmlChar * nsprefix;
3826        xmlChar * href = NULL;
3827    CODE:
3828        href = nodeSv2C( svuri , self );
3829        if ( href != NULL && xmlStrlen(href) > 0) {
3830            xmlNsPtr ns = xmlSearchNsByHref( self->doc, self, href );
3831            xmlFree( href );
3832            if ( ns != NULL ) {
3833		    if ( ns->prefix != NULL ) {
3834			  nsprefix = xmlStrdup( ns->prefix );
3835			  RETVAL = C2Sv( nsprefix, NULL );
3836			  xmlFree(nsprefix);
3837		    } else {
3838			  RETVAL = newSVpv("",0);
3839		    }
3840            }
3841            else {
3842                XSRETURN_UNDEF;
3843            }
3844        }
3845        else {
3846            XSRETURN_UNDEF;
3847        }
3848    OUTPUT:
3849        RETVAL
3850
3851int
3852setNamespaceDeclURI( self, svprefix, newURI )
3853        xmlNodePtr self
3854        SV * svprefix
3855        SV * newURI
3856    PREINIT:
3857        xmlChar * prefix = NULL;
3858        xmlChar * nsURI = NULL;
3859        xmlNsPtr ns;
3860    CODE:
3861        prefix = nodeSv2C( svprefix , self );
3862        nsURI = nodeSv2C( newURI , self );
3863        /* null empty values */
3864        if ( prefix && xmlStrlen(prefix) == 0) {
3865            xmlFree( prefix );
3866            prefix = NULL;
3867        }
3868        if ( nsURI && xmlStrlen(nsURI) == 0) {
3869	     xmlFree( nsURI );
3870	     nsURI = NULL;
3871        }
3872        RETVAL = 0;
3873        ns = self->nsDef;
3874        while ( ns ) {
3875		if ((ns->prefix || ns->href ) &&
3876		    ( xmlStrcmp( ns->prefix, prefix ) == 0 )) {
3877			  if (ns->href) xmlFree((char*)ns->href);
3878			  ns->href = nsURI;
3879			  if ( nsURI == NULL ) {
3880			      domRemoveNsRefs( self, ns );
3881			  } else
3882			      nsURI = NULL; /* do not free it */
3883			  RETVAL = 1;
3884			  break;
3885		} else {
3886		    ns = ns->next;
3887		}
3888	  }
3889        if ( prefix ) xmlFree( prefix );
3890        if ( nsURI ) xmlFree( nsURI );
3891    OUTPUT:
3892        RETVAL
3893
3894int
3895setNamespaceDeclPrefix( self, svprefix, newPrefix )
3896        xmlNodePtr self
3897        SV * svprefix
3898        SV * newPrefix
3899    PREINIT:
3900        xmlChar * prefix = NULL;
3901        xmlChar * nsPrefix = NULL;
3902        xmlNsPtr ns;
3903    CODE:
3904        prefix = nodeSv2C( svprefix , self );
3905        nsPrefix = nodeSv2C( newPrefix , self );
3906        /* null empty values */
3907        if ( prefix != NULL && xmlStrlen(prefix) == 0) {
3908            xmlFree( prefix );
3909            prefix = NULL;
3910        }
3911        if ( nsPrefix != NULL && xmlStrlen(nsPrefix) == 0) {
3912            xmlFree( nsPrefix );
3913            nsPrefix = NULL;
3914        }
3915        if ( xmlStrcmp( prefix, nsPrefix ) == 0 ) {
3916		RETVAL = 1;
3917	  } else {
3918		RETVAL = 0;
3919		/* check that new prefix is not in scope */
3920		ns = xmlSearchNs( self->doc, self, nsPrefix );
3921		if ( ns != NULL ) {
3922		    if (nsPrefix != NULL) xmlFree( nsPrefix );
3923		    if (prefix != NULL) xmlFree( prefix );
3924		    croak("setNamespaceDeclPrefix: prefix '%s' is in use", ns->prefix);
3925		}
3926		/* lookup the declaration */
3927		ns = self->nsDef;
3928		while ( ns != NULL ) {
3929		    if ((ns->prefix != NULL || ns->href != NULL) &&
3930			  xmlStrcmp( ns->prefix, prefix ) == 0 ) {
3931			  if ( ns->href == NULL && nsPrefix != NULL ) {
3932			      /* xmlns:foo="" - no go */
3933			      if ( prefix != NULL) xmlFree(prefix);
3934			      croak("setNamespaceDeclPrefix: cannot set non-empty prefix for empty namespace");
3935			  }
3936			  if ( ns->prefix != NULL ) xmlFree( (xmlChar*)ns->prefix );
3937			  ns->prefix = nsPrefix;
3938			  nsPrefix = NULL; /* do not free it */
3939			  RETVAL = 1;
3940			  break;
3941		    } else {
3942			  ns = ns->next;
3943		    }
3944		}
3945	  }
3946        if ( nsPrefix != NULL ) xmlFree(nsPrefix);
3947        if ( prefix != NULL) xmlFree(prefix);
3948    OUTPUT:
3949        RETVAL
3950
3951void
3952setNodeName( self , value )
3953        xmlNodePtr self
3954        SV* value
3955    ALIAS:
3956        setName = 1
3957    PREINIT:
3958        xmlChar* string;
3959        xmlChar* localname;
3960        xmlChar* prefix;
3961    CODE:
3962        string = nodeSv2C( value , self );
3963        if ( !LibXML_test_node_name( string ) ) {
3964            xmlFree(string);
3965            croak( "bad name" );
3966        }
3967        if( self->ns ){
3968            localname = xmlSplitQName2(string, &prefix);
3969	    if ( localname == NULL ) {
3970	      localname = xmlStrdup( string );
3971	    }
3972            xmlNodeSetName(self, localname );
3973            xmlFree(localname);
3974            xmlFree(prefix);
3975        }
3976        else {
3977            xs_warn("node name normal\n");
3978            xmlNodeSetName(self, string );
3979        }
3980        xmlFree(string);
3981
3982void
3983setRawName( self, value )
3984        xmlNodePtr self
3985        SV * value
3986    PREINIT:
3987        xmlChar* string;
3988        xmlChar* localname;
3989        xmlChar* prefix;
3990    CODE:
3991        string = nodeSv2C( value , self );
3992        if ( !string || xmlStrlen( string) <= 0 ) {
3993            xmlFree(string);
3994            XSRETURN_UNDEF;
3995        }
3996        if( self->ns ){
3997            localname = xmlSplitQName2(string, &prefix);
3998            xmlNodeSetName(self, localname );
3999            xmlFree(localname);
4000            xmlFree(prefix);
4001        }
4002        else {
4003            xmlNodeSetName(self, string );
4004        }
4005        xmlFree(string);
4006
4007
4008SV*
4009nodeValue( self, useDomEncoding = &PL_sv_undef )
4010        xmlNodePtr self
4011        SV * useDomEncoding
4012    ALIAS:
4013        XML::LibXML::Attr::value     = 1
4014        XML::LibXML::Attr::getValue  = 2
4015        XML::LibXML::Text::data      = 3
4016        XML::LibXML::Node::getValue  = 4
4017        XML::LibXML::Node::getData   = 5
4018    PREINIT:
4019        xmlChar * content = NULL;
4020    CODE:
4021        content = domGetNodeValue( self );
4022
4023        if ( content != NULL ) {
4024            if ( SvTRUE(useDomEncoding) ) {
4025                RETVAL = nodeC2Sv(content, self);
4026            }
4027            else {
4028                RETVAL = C2Sv(content, NULL);
4029            }
4030            xmlFree(content);
4031        }
4032        else {
4033            XSRETURN_UNDEF;
4034        }
4035    OUTPUT:
4036        RETVAL
4037
4038int
4039nodeType( self )
4040        xmlNodePtr self
4041    ALIAS:
4042        XML::LibXML::Node::getType = 1
4043    CODE:
4044        RETVAL = self->type;
4045    OUTPUT:
4046        RETVAL
4047
4048SV*
4049parentNode( self )
4050        xmlNodePtr self
4051    ALIAS:
4052        XML::LibXML::Attr::ownerElement    = 1
4053        XML::LibXML::Node::getParentNode   = 2
4054        XML::LibXML::Attr::getOwnerElement = 3
4055    CODE:
4056        RETVAL = PmmNodeToSv( self->parent,
4057                              PmmOWNERPO( PmmPROXYNODE(self) ) );
4058    OUTPUT:
4059        RETVAL
4060
4061SV*
4062nextSibling( self )
4063        xmlNodePtr self
4064    ALIAS:
4065        getNextSibling = 1
4066    CODE:
4067        RETVAL = PmmNodeToSv( self->next,
4068                              PmmOWNERPO(PmmPROXYNODE(self)) );
4069    OUTPUT:
4070        RETVAL
4071
4072SV*
4073previousSibling( self )
4074        xmlNodePtr self
4075    ALIAS:
4076        getPreviousSibling = 1
4077    CODE:
4078        RETVAL = PmmNodeToSv( self->prev,
4079                              PmmOWNERPO( PmmPROXYNODE(self) ) );
4080    OUTPUT:
4081        RETVAL
4082
4083void
4084_childNodes( self )
4085        xmlNodePtr self
4086    ALIAS:
4087        XML::LibXML::Node::getChildnodes = 1
4088    PREINIT:
4089        xmlNodePtr cld;
4090        SV * element;
4091        int len = 0;
4092        int wantarray = GIMME_V;
4093    PPCODE:
4094        if ( self->type != XML_ATTRIBUTE_NODE ) {
4095            cld = self->children;
4096            xs_warn("childnodes start");
4097            while ( cld ) {
4098                if( wantarray != G_SCALAR ) {
4099                    element = PmmNodeToSv(cld, PmmOWNERPO(PmmPROXYNODE(self)) );
4100                    XPUSHs(sv_2mortal(element));
4101                }
4102                cld = cld->next;
4103                len++;
4104            }
4105        }
4106        if ( wantarray == G_SCALAR ) {
4107            XPUSHs(sv_2mortal(newSViv(len)) );
4108        }
4109
4110void
4111_getChildrenByTagNameNS( self, namespaceURI, node_name )
4112        xmlNodePtr self
4113        SV * namespaceURI
4114        SV * node_name
4115    PREINIT:
4116        xmlChar * name;
4117        xmlChar * nsURI;
4118        xmlNodePtr cld;
4119        SV * element;
4120        int len = 0;
4121	int name_wildcard = 0;
4122	int ns_wildcard = 0;
4123        int wantarray = GIMME_V;
4124    PPCODE:
4125        name = nodeSv2C(node_name, self );
4126        nsURI = nodeSv2C(namespaceURI, self );
4127
4128        if ( nsURI != NULL ) {
4129            if (xmlStrlen(nsURI) == 0 ) {
4130                xmlFree(nsURI);
4131                nsURI = NULL;
4132            } else if (xmlStrcmp( nsURI, (xmlChar *)"*" )==0) {
4133                ns_wildcard = 1;
4134            }
4135        }
4136        if ( name !=NULL && xmlStrcmp( name, (xmlChar *)"*" ) == 0) {
4137            name_wildcard = 1;
4138        }
4139        if ( self->type != XML_ATTRIBUTE_NODE ) {
4140            cld = self->children;
4141            xs_warn("childnodes start");
4142            while ( cld ) {
4143	      if (((name_wildcard && (cld->type == XML_ELEMENT_NODE)) ||
4144		   xmlStrcmp( name, cld->name ) == 0)
4145		   && (ns_wildcard ||
4146		       (cld->ns != NULL &&
4147                        xmlStrcmp(nsURI,cld->ns->href) == 0 ) ||
4148                       (cld->ns == NULL && nsURI == NULL))) {
4149                if( wantarray != G_SCALAR ) {
4150                    element = PmmNodeToSv(cld, PmmOWNERPO(PmmPROXYNODE(self)) );
4151                    XPUSHs(sv_2mortal(element));
4152                }
4153                len++;
4154	      }
4155	      cld = cld->next;
4156            }
4157        }
4158        if ( wantarray == G_SCALAR ) {
4159            XPUSHs(sv_2mortal(newSViv(len)) );
4160        }
4161
4162SV*
4163firstChild( self )
4164        xmlNodePtr self
4165    ALIAS:
4166        getFirstChild = 1
4167    CODE:
4168        RETVAL = PmmNodeToSv( self->children,
4169                              PmmOWNERPO( PmmPROXYNODE(self) ) );
4170    OUTPUT:
4171        RETVAL
4172
4173SV*
4174lastChild( self )
4175        xmlNodePtr self
4176    ALIAS:
4177        getLastChild = 1
4178    CODE:
4179        RETVAL = PmmNodeToSv( self->last,
4180                              PmmOWNERPO( PmmPROXYNODE(self) ) );
4181    OUTPUT:
4182        RETVAL
4183
4184void
4185_attributes( self )
4186        xmlNodePtr self
4187    ALIAS:
4188        XML::LibXML::Node::getAttributes = 1
4189    PREINIT:
4190        xmlAttrPtr attr = NULL;
4191        xmlNsPtr ns = NULL;
4192        SV * element;
4193        int len=0;
4194        int wantarray = GIMME_V;
4195    PPCODE:
4196        if ( self->type != XML_ATTRIBUTE_NODE ) {
4197            attr      = self->properties;
4198            while ( attr != NULL ) {
4199                if ( wantarray != G_SCALAR ) {
4200                    element = PmmNodeToSv((xmlNodePtr)attr,
4201                                           PmmOWNERPO(PmmPROXYNODE(self)) );
4202                    XPUSHs(sv_2mortal(element));
4203                }
4204                attr = attr->next;
4205                len++;
4206            }
4207
4208            ns = self->nsDef;
4209            while ( ns != NULL ) {
4210                const char * CLASS = "XML::LibXML::Namespace";
4211                if ( wantarray != G_SCALAR ) {
4212                    /* namespace handling is kinda odd:
4213                     * as soon we have a namespace isolated from its
4214                     * owner, we loose the context. therefore it is
4215                     * forbidden to access the NS information directly.
4216                     * instead the use will recieve a copy of the real
4217                     * namespace, that can be destroied and is not
4218                     * bound to a document.
4219                     *
4220                     * this avoids segfaults in the end.
4221                     */
4222			  if ((ns->prefix != NULL || ns->href != NULL)) {
4223				xmlNsPtr tns = xmlCopyNamespace(ns);
4224				if ( tns != NULL ) {
4225				    element = sv_newmortal();
4226				    XPUSHs(sv_setref_pv( element,
4227								 (char *)CLASS,
4228								 (void*)tns));
4229				}
4230			  }
4231                }
4232                ns = ns->next;
4233                len++;
4234            }
4235        }
4236        if( wantarray == G_SCALAR ) {
4237            XPUSHs( sv_2mortal(newSViv(len)) );
4238        }
4239
4240int
4241hasChildNodes( self )
4242        xmlNodePtr self
4243    CODE:
4244        if ( self->type == XML_ATTRIBUTE_NODE ) {
4245            RETVAL = 0;
4246        }
4247        else {
4248            RETVAL =  self->children ? 1 : 0 ;
4249        }
4250    OUTPUT:
4251        RETVAL
4252
4253int
4254hasAttributes( self )
4255        xmlNodePtr self
4256    CODE:
4257        if ( self->type == XML_ATTRIBUTE_NODE ) {
4258            RETVAL = 0;
4259        }
4260        else {
4261            RETVAL =  self->properties ? 1 : 0 ;
4262        }
4263    OUTPUT:
4264        RETVAL
4265
4266SV*
4267ownerDocument( self )
4268        xmlNodePtr self
4269    ALIAS:
4270        XML::LibXML::Node::getOwnerDocument = 1
4271    CODE:
4272        xs_warn( "GET OWNERDOC\n" );
4273        if( self != NULL
4274            && self->doc != NULL ){
4275            RETVAL = PmmNodeToSv((xmlNodePtr)(self->doc), NULL);
4276        }
4277        else {
4278            XSRETURN_UNDEF;
4279        }
4280    OUTPUT:
4281        RETVAL
4282
4283SV*
4284ownerNode( self )
4285        xmlNodePtr self
4286    ALIAS:
4287        XML::LibXML::Node::getOwner = 1
4288        XML::LibXML::Node::getOwnerElement = 2
4289    CODE:
4290        RETVAL = PmmNodeToSv(PmmNODE(PmmOWNERPO(PmmPROXYNODE(self))), NULL);
4291    OUTPUT:
4292        RETVAL
4293
4294
4295int
4296normalize( self )
4297        xmlNodePtr self
4298    CODE:
4299        RETVAL = domNodeNormalize( self );
4300    OUTPUT:
4301        RETVAL
4302
4303
4304SV*
4305insertBefore( self, nNode, ref )
4306        xmlNodePtr self
4307        xmlNodePtr nNode
4308        SV * ref
4309    PREINIT:
4310        xmlNodePtr oNode=NULL, rNode;
4311    INIT:
4312        oNode = PmmSvNode(ref);
4313    CODE:
4314        if ( self->type    == XML_DOCUMENT_NODE
4315             && nNode->type == XML_ELEMENT_NODE ) {
4316            xs_warn( "NOT_SUPPORTED_ERR\n" );
4317            XSRETURN_UNDEF;
4318        }
4319        else {
4320            rNode = domInsertBefore( self, nNode, oNode );
4321            if ( rNode != NULL ) {
4322                RETVAL = PmmNodeToSv( rNode,
4323                                      PmmOWNERPO(PmmPROXYNODE(self)) );
4324                PmmFixOwner(PmmOWNERPO(SvPROXYNODE(RETVAL)),
4325                            PmmOWNERPO(PmmPROXYNODE(self)) );
4326            }
4327            else {
4328                 XSRETURN_UNDEF;
4329            }
4330        }
4331    OUTPUT:
4332        RETVAL
4333
4334SV*
4335insertAfter( self, nNode, ref )
4336        xmlNodePtr self
4337        xmlNodePtr nNode
4338        SV* ref
4339    PREINIT:
4340        xmlNodePtr oNode = NULL, rNode;
4341    INIT:
4342        oNode = PmmSvNode(ref);
4343    CODE:
4344        if ( self->type    == XML_DOCUMENT_NODE
4345             && nNode->type == XML_ELEMENT_NODE ) {
4346            xs_warn( "NOT_SUPPORTED_ERR\n" );
4347            XSRETURN_UNDEF;
4348        }
4349        else {
4350            rNode = domInsertAfter( self, nNode, oNode );
4351            if ( rNode != NULL ) {
4352                RETVAL = PmmNodeToSv( rNode,
4353                                      PmmOWNERPO(PmmPROXYNODE(self)) );
4354                PmmFixOwner(PmmOWNERPO(SvPROXYNODE(RETVAL)),
4355                            PmmOWNERPO(PmmPROXYNODE(self)) );
4356            }
4357            else {
4358                XSRETURN_UNDEF;
4359            }
4360        }
4361    OUTPUT:
4362        RETVAL
4363
4364SV*
4365replaceChild( self, nNode, oNode )
4366        xmlNodePtr self
4367        xmlNodePtr nNode
4368        xmlNodePtr oNode
4369    PREINIT:
4370        xmlNodePtr ret = NULL;
4371        ProxyNodePtr docfrag = NULL;
4372    CODE:
4373       if ( self->type == XML_DOCUMENT_NODE ) {
4374                switch ( nNode->type ) {
4375                case XML_ELEMENT_NODE:
4376                case XML_DOCUMENT_FRAG_NODE:
4377                case XML_TEXT_NODE:
4378                case XML_CDATA_SECTION_NODE:
4379                    XSRETURN_UNDEF;
4380                    break;
4381                default:
4382                    break;
4383                }
4384        }
4385        ret = domReplaceChild( self, nNode, oNode );
4386        if (ret == NULL) {
4387            XSRETURN_UNDEF;
4388        }
4389        else {
4390                docfrag = PmmNewFragment( self->doc );
4391                /* create document fragment */
4392                xmlAddChild( PmmNODE(docfrag), ret );
4393                RETVAL = PmmNodeToSv(ret, docfrag);
4394
4395                if ( nNode->_private != NULL ) {
4396                    PmmFixOwner( PmmPROXYNODE(nNode),
4397                                 PmmOWNERPO(PmmPROXYNODE(self)) );
4398                }
4399                PmmFixOwner( SvPROXYNODE(RETVAL), docfrag );
4400        }
4401    OUTPUT:
4402        RETVAL
4403
4404SV*
4405replaceNode( self,nNode )
4406        xmlNodePtr self
4407        xmlNodePtr nNode
4408    PREINIT:
4409        xmlNodePtr ret = NULL;
4410        ProxyNodePtr docfrag = NULL;
4411    CODE:
4412        if ( domIsParent( self, nNode ) == 1 ) {
4413            XSRETURN_UNDEF;
4414        }
4415        if ( self->doc != nNode->doc ) {
4416            domImportNode( self->doc, nNode, 1, 1 );
4417        }
4418
4419        if ( self->type != XML_ATTRIBUTE_NODE ) {
4420              ret = domReplaceChild( self->parent, nNode, self);
4421        }
4422        else {
4423             ret = xmlReplaceNode( self, nNode );
4424        }
4425        if ( ret ) {
4426            if ( ret->type == XML_ATTRIBUTE_NODE ) {
4427                docfrag = NULL;
4428            }
4429            else {
4430                /* create document fragment */
4431                docfrag = PmmNewFragment( self->doc );
4432                xmlAddChild( PmmNODE(docfrag), ret );
4433            }
4434
4435            RETVAL = PmmNodeToSv(ret, docfrag);
4436            if ( nNode->_private != NULL ) {
4437                PmmFixOwner( PmmPROXYNODE(nNode),
4438                             PmmOWNERPO(PmmPROXYNODE(self)));
4439            }
4440            PmmFixOwner( SvPROXYNODE(RETVAL), docfrag );
4441        }
4442        else {
4443            croak( "replacement failed" );
4444            XSRETURN_UNDEF;
4445        }
4446    OUTPUT:
4447        RETVAL
4448
4449SV*
4450removeChild( self, node )
4451        xmlNodePtr self
4452        xmlNodePtr node
4453    PREINIT:
4454        xmlNodePtr ret;
4455    CODE:
4456        ret = domRemoveChild( self, node );
4457        if (ret == NULL) {
4458            XSRETURN_UNDEF;
4459        }
4460        else {
4461                ProxyNodePtr docfrag = PmmNewFragment( ret->doc );
4462                xmlAddChild( PmmNODE(docfrag), ret );
4463                RETVAL = PmmNodeToSv(ret,NULL);
4464                PmmFixOwner( SvPROXYNODE(RETVAL), docfrag );
4465        }
4466    OUTPUT:
4467        RETVAL
4468
4469void
4470removeChildNodes( self )
4471        xmlNodePtr self
4472    PREINIT:
4473        xmlNodePtr elem, fragment;
4474        ProxyNodePtr docfrag;
4475    CODE:
4476        docfrag  = PmmNewFragment( self->doc );
4477        fragment = PmmNODE( docfrag );
4478        elem = self->children;
4479        while ( elem ) {
4480            xmlUnlinkNode( elem );
4481            /* this following piece is the function of domAppendChild()
4482             * but in this special case we can avoid most of the logic of
4483             * that function.
4484             */
4485            if ( fragment->children != NULL ) {
4486                xs_warn("unlink node!\n");
4487                domAddNodeToList( elem, fragment->last, NULL );
4488            }
4489            else {
4490                fragment->children = elem;
4491                fragment->last     = elem;
4492                elem->parent= fragment;
4493            }
4494            PmmFixOwnerNode( elem, docfrag );
4495            elem = elem->next;
4496        }
4497
4498        self->children = self->last = NULL;
4499        if ( PmmREFCNT(docfrag) <= 0 ) {
4500            xs_warn( "have not references left" );
4501            PmmREFCNT_inc( docfrag );
4502            PmmREFCNT_dec( docfrag );
4503        }
4504
4505void
4506unbindNode( self )
4507        xmlNodePtr self
4508    ALIAS:
4509        XML::LibXML::Node::unlink = 1
4510        XML::LibXML::Node::unlinkNode = 2
4511    PREINIT:
4512        ProxyNodePtr docfrag     = NULL;
4513    CODE:
4514        if ( self->type != XML_DOCUMENT_NODE
4515             || self->type != XML_DOCUMENT_FRAG_NODE ) {
4516            xmlUnlinkNode( self );
4517            if ( self->type != XML_ATTRIBUTE_NODE ) {
4518                docfrag = PmmNewFragment( self->doc );
4519                xmlAddChild( PmmNODE(docfrag), self );
4520            }
4521            PmmFixOwner( PmmPROXYNODE(self), docfrag );
4522        }
4523
4524SV*
4525appendChild( self, nNode )
4526        xmlNodePtr self
4527        xmlNodePtr nNode
4528    PREINIT:
4529        xmlNodePtr rNode;
4530    CODE:
4531        if (self->type == XML_DOCUMENT_NODE ) {
4532            /* NOT_SUPPORTED_ERR
4533             */
4534            switch ( nNode->type ) {
4535            case XML_ELEMENT_NODE:
4536            case XML_DOCUMENT_FRAG_NODE:
4537            case XML_TEXT_NODE:
4538            case XML_CDATA_SECTION_NODE:
4539                XSRETURN_UNDEF;
4540                break;
4541            default:
4542                break;
4543            }
4544        }
4545
4546        rNode = domAppendChild( self, nNode );
4547
4548        if ( rNode == NULL ) {
4549            XSRETURN_UNDEF;
4550        }
4551
4552        RETVAL = PmmNodeToSv( nNode,
4553                              PmmOWNERPO(PmmPROXYNODE(self)) );
4554        PmmFixOwner( SvPROXYNODE(RETVAL), PmmPROXYNODE(self) );
4555    OUTPUT:
4556        RETVAL
4557
4558SV*
4559addChild( self, nNode )
4560        xmlNodePtr self
4561        xmlNodePtr nNode
4562    PREINIT:
4563        xmlNodePtr retval = NULL;
4564        ProxyNodePtr proxy;
4565    CODE:
4566        xmlUnlinkNode(nNode);
4567        proxy = PmmPROXYNODE(nNode);
4568        retval = xmlAddChild( self, nNode );
4569
4570        if ( retval == NULL ) {
4571            croak( "ERROR!\n" );
4572        }
4573
4574        if ( retval != nNode ) {
4575            xs_warn( "node was lost during operation\n" );
4576            PmmNODE(proxy) = NULL;
4577        }
4578
4579        RETVAL = PmmNodeToSv( retval,
4580                              PmmOWNERPO(PmmPROXYNODE(self)) );
4581        if ( retval != self ) {
4582            PmmFixOwner( SvPROXYNODE(RETVAL), PmmPROXYNODE(self) );
4583        }
4584    OUTPUT:
4585        RETVAL
4586
4587
4588SV*
4589addSibling( self, nNode )
4590        xmlNodePtr self
4591        xmlNodePtr nNode
4592    PREINIT:
4593        xmlNodePtr ret = NULL;
4594    CODE:
4595        if ( nNode->type == XML_DOCUMENT_FRAG_NODE ) {
4596            XSRETURN_UNDEF;
4597        }
4598
4599        ret = xmlAddSibling( self, nNode );
4600
4601        if ( ret ) {
4602            RETVAL = PmmNodeToSv(ret,NULL);
4603            PmmFixOwner( SvPROXYNODE(RETVAL), PmmOWNERPO(PmmPROXYNODE(self)) );
4604        }
4605        else {
4606            XSRETURN_UNDEF;
4607        }
4608    OUTPUT:
4609        RETVAL
4610
4611SV*
4612cloneNode( self, deep=0 )
4613        xmlNodePtr self
4614        int deep
4615    PREINIT:
4616        xmlNodePtr ret;
4617        xmlDocPtr doc = NULL;
4618        ProxyNodePtr docfrag = NULL;
4619    CODE:
4620        ret = PmmCloneNode( self, deep );
4621        if ( ret == NULL ) {
4622            XSRETURN_UNDEF;
4623        }
4624
4625        if ( ret->type  == XML_DTD_NODE ) {
4626            RETVAL = PmmNodeToSv(ret, NULL);
4627        }
4628        else {
4629            doc = self->doc;
4630
4631            if ( doc != NULL ) {
4632                xmlSetTreeDoc(ret, doc);
4633            }
4634
4635            docfrag = PmmNewFragment( doc );
4636            xmlAddChild( PmmNODE(docfrag), ret );
4637            RETVAL = PmmNodeToSv(ret, docfrag);
4638        }
4639    OUTPUT:
4640        RETVAL
4641
4642int
4643isSameNode( self, oNode )
4644        xmlNodePtr self
4645        xmlNodePtr oNode
4646    ALIAS:
4647        XML::LibXML::Node::isEqual = 1
4648    CODE:
4649        RETVAL = ( self == oNode ) ? 1 : 0;
4650    OUTPUT:
4651        RETVAL
4652
4653SV *
4654baseURI( self )
4655        xmlNodePtr self
4656    PREINIT:
4657        xmlChar * uri;
4658    CODE:
4659        uri = xmlNodeGetBase( self->doc, self );
4660        RETVAL = C2Sv( uri, NULL );
4661        xmlFree( uri );
4662    OUTPUT:
4663        RETVAL
4664
4665void
4666setBaseURI( self, URI )
4667        xmlNodePtr self
4668        SV * URI
4669    PREINIT:
4670        xmlChar * uri;
4671    CODE:
4672        uri = nodeSv2C( URI, self );
4673        if ( uri != NULL ) {
4674            xmlNodeSetBase( self, uri );
4675        }
4676
4677SV*
4678toString( self, format=0, useDomEncoding = &PL_sv_undef )
4679        xmlNodePtr self
4680        SV * useDomEncoding
4681        int format
4682    ALIAS:
4683        XML::LibXML::Node::serialize = 1
4684    PREINIT:
4685        xmlBufferPtr buffer;
4686        const xmlChar *ret = NULL;
4687        SV* internalFlag = NULL;
4688        int oldTagFlag = xmlSaveNoEmptyTags;
4689    CODE:
4690        internalFlag = perl_get_sv("XML::LibXML::setTagCompression", 0);
4691
4692        if ( internalFlag ) {
4693            xmlSaveNoEmptyTags = SvTRUE(internalFlag);
4694        }
4695        buffer = xmlBufferCreate();
4696
4697        if ( format <= 0 ) {
4698            xmlNodeDump( buffer,
4699                         self->doc,
4700                         self, 0, format);
4701        }
4702        else {
4703            int t_indent_var = xmlIndentTreeOutput;
4704            xmlIndentTreeOutput = 1;
4705            xmlNodeDump( buffer,
4706                         self->doc,
4707                         self, 0, format);
4708            xmlIndentTreeOutput = t_indent_var;
4709        }
4710
4711        ret = xmlBufferContent( buffer );
4712
4713        xmlSaveNoEmptyTags = oldTagFlag;
4714
4715        if ( ret != NULL ) {
4716            if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
4717                RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(self))) ;
4718                SvUTF8_off(RETVAL);
4719            }
4720            else {
4721                RETVAL = C2Sv((xmlChar*)ret, NULL) ;
4722            }
4723            xmlBufferFree( buffer );
4724        }
4725        else {
4726            xmlBufferFree( buffer );
4727            xs_warn("Failed to convert node to string");
4728            XSRETURN_UNDEF;
4729        }
4730    OUTPUT:
4731        RETVAL
4732
4733
4734SV *
4735_toStringC14N(self, comments=0, xpath=&PL_sv_undef, exclusive=0, inc_prefix_list=NULL)
4736        xmlNodePtr self
4737        int comments
4738        SV * xpath
4739        int exclusive
4740        char** inc_prefix_list
4741
4742    PREINIT:
4743        SV * saved_error = sv_2mortal(newSVpv("",0));
4744        xmlChar *result               = NULL;
4745        xmlChar *nodepath             = NULL;
4746        xmlXPathContextPtr child_ctxt = NULL;
4747        xmlXPathObjectPtr child_xpath = NULL;
4748        xmlNodeSetPtr nodelist        = NULL;
4749        xmlNodePtr refNode            = NULL;
4750    INIT:
4751        /* due to how c14n is implemented, the nodeset it receives must
4752          include child nodes; ie, child nodes aren't assumed to be rendered.
4753          so we use an xpath expression to find all of the child nodes. */
4754
4755        if ( self->doc == NULL ) {
4756            croak("Node passed to toStringC14N must be part of a document");
4757        }
4758
4759        refNode = self;
4760    CODE:
4761        if ( xpath != NULL && xpath != &PL_sv_undef ) {
4762            nodepath = Sv2C( xpath, NULL );
4763        }
4764
4765        if ( nodepath != NULL && xmlStrlen( nodepath ) == 0 ) {
4766            xmlFree( nodepath );
4767            nodepath = NULL;
4768        }
4769
4770        if ( nodepath == NULL
4771             && self->type != XML_DOCUMENT_NODE
4772             && self->type != XML_HTML_DOCUMENT_NODE
4773             && self->type != XML_DOCB_DOCUMENT_NODE
4774           ) {
4775            if (comments)
4776	      nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)" );
4777            else
4778                nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)[not(self::comment())]" );
4779        }
4780
4781        if ( nodepath != NULL ) {
4782            if ( self->type == XML_DOCUMENT_NODE
4783                 || self->type == XML_HTML_DOCUMENT_NODE
4784                 || self->type == XML_DOCB_DOCUMENT_NODE ) {
4785                refNode = xmlDocGetRootElement( self->doc );
4786            }
4787
4788            child_ctxt = xmlXPathNewContext(self->doc);
4789            if (!child_ctxt) {
4790                if ( nodepath != NULL ) {
4791                    xmlFree( nodepath );
4792                }
4793                croak("Failed to create xpath context");
4794            }
4795
4796            child_ctxt->node = self;
4797            /* get the namespace information */
4798            if (self->type == XML_DOCUMENT_NODE) {
4799                child_ctxt->namespaces = xmlGetNsList( self->doc,
4800                                                       xmlDocGetRootElement( self->doc ) );
4801            }
4802            else {
4803                child_ctxt->namespaces = xmlGetNsList(self->doc, self);
4804            }
4805            child_ctxt->nsNr = 0;
4806            if (child_ctxt->namespaces != NULL) {
4807                while (child_ctxt->namespaces[child_ctxt->nsNr] != NULL)
4808                child_ctxt->nsNr++;
4809            }
4810
4811            child_xpath = xmlXPathEval(nodepath, child_ctxt);
4812            if (child_xpath == NULL) {
4813                if (child_ctxt->namespaces != NULL) {
4814                    xmlFree( child_ctxt->namespaces );
4815                }
4816                xmlXPathFreeContext(child_ctxt);
4817                if ( nodepath != NULL ) {
4818                    xmlFree( nodepath );
4819                }
4820                croak("2 Failed to compile xpath expression");
4821            }
4822
4823            nodelist = child_xpath->nodesetval;
4824            if ( nodelist == NULL ) {
4825                xmlFree( nodepath );
4826                xmlXPathFreeObject(child_xpath);
4827                if (child_ctxt->namespaces != NULL) {
4828                    xmlFree( child_ctxt->namespaces );
4829                }
4830                xmlXPathFreeContext(child_ctxt);
4831                croak( "cannot canonize empty nodeset!" );
4832            }
4833        }
4834
4835        LibXML_init_error_ctx(saved_error);
4836
4837        xmlC14NDocDumpMemory( self->doc,
4838                              nodelist,
4839                              exclusive, (xmlChar **) inc_prefix_list,
4840                              comments,
4841                              &result );
4842
4843        if ( child_xpath ) {
4844            xmlXPathFreeObject(child_xpath);
4845        }
4846        if ( child_ctxt ) {
4847            if (child_ctxt->namespaces != NULL) {
4848                xmlFree( child_ctxt->namespaces );
4849            }
4850            xmlXPathFreeContext(child_ctxt);
4851        }
4852        if ( nodepath != NULL ) {
4853            xmlFree( nodepath );
4854        }
4855
4856        LibXML_report_error_ctx(saved_error, 0);
4857
4858        if (result == NULL) {
4859             croak("Failed to convert doc to string in doc->toStringC14N");
4860        } else {
4861            RETVAL = C2Sv( result, NULL );
4862            xmlFree(result);
4863        }
4864    OUTPUT:
4865        RETVAL
4866
4867SV*
4868string_value ( self, useDomEncoding = &PL_sv_undef )
4869        xmlNodePtr self
4870        SV * useDomEncoding
4871    ALIAS:
4872        to_literal = 1
4873        textContent = 2
4874    PREINIT:
4875         xmlChar * string = NULL;
4876    CODE:
4877        /* we can't just return a string, because of UTF8! */
4878        string = xmlXPathCastNodeToString(self);
4879        if ( SvTRUE(useDomEncoding) ) {
4880            RETVAL = nodeC2Sv(string,
4881                              self);
4882        }
4883        else {
4884            RETVAL = C2Sv(string,
4885                          NULL);
4886        }
4887        xmlFree(string);
4888    OUTPUT:
4889        RETVAL
4890
4891double
4892to_number ( self )
4893        xmlNodePtr self
4894    CODE:
4895        RETVAL = xmlXPathCastNodeToNumber(self);
4896    OUTPUT:
4897        RETVAL
4898
4899
4900void
4901_find( pnode, pxpath )
4902        SV* pnode
4903        SV * pxpath
4904    PREINIT:
4905        SV * saved_error = sv_2mortal(newSVpv("",0));
4906        xmlNodePtr node = PmmSvNode(pnode);
4907        ProxyNodePtr owner = NULL;
4908        xmlXPathObjectPtr found = NULL;
4909        xmlNodeSetPtr nodelist = NULL;
4910        STRLEN len = 0 ;
4911        xmlChar * xpath = nodeSv2C(pxpath, node);
4912    INIT:
4913        if ( node == NULL ) {
4914            croak( "lost node" );
4915        }
4916        if ( !(xpath && xmlStrlen(xpath)) ) {
4917            xs_warn( "bad xpath\n" );
4918            if ( xpath )
4919                xmlFree(xpath);
4920            croak( "empty XPath found" );
4921            XSRETURN_UNDEF;
4922        }
4923    PPCODE:
4924        if ( node->doc ) {
4925            domNodeNormalize( xmlDocGetRootElement( node->doc ) );
4926        }
4927        else {
4928            domNodeNormalize( PmmOWNER(SvPROXYNODE(pnode)) );
4929        }
4930
4931        LibXML_init_error_ctx(saved_error);
4932
4933        found = domXPathFind( node, xpath );
4934        xmlFree( xpath );
4935
4936        if (found) {
4937            switch (found->type) {
4938                case XPATH_NODESET:
4939                    /* return as a NodeList */
4940                    /* access ->nodesetval */
4941                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
4942                    nodelist = found->nodesetval;
4943                    if ( nodelist ) {
4944                        if ( nodelist->nodeNr > 0 ) {
4945                            int i;
4946                            const char * cls = "XML::LibXML::Node";
4947                            xmlNodePtr tnode;
4948                            SV * element;
4949
4950                            owner = PmmOWNERPO(SvPROXYNODE(pnode));
4951                            len = nodelist->nodeNr;
4952                            for( i=0 ; i < len; i++){
4953                                /* we have to create a new instance of an
4954                                 * objectptr. and then
4955                                 * place the current node into the new
4956                                 * object. afterwards we can
4957                                 * push the object to the array!
4958                                 */
4959                                tnode = nodelist->nodeTab[i];
4960
4961                                /* let's be paranoid */
4962                                if (tnode->type == XML_NAMESPACE_DECL) {
4963                                     xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
4964                                    if ( newns != NULL ) {
4965                                        element = NEWSV(0,0);
4966                                        cls = PmmNodeTypeName( tnode );
4967                                        element = sv_setref_pv( element,
4968                                                                (const char *)cls,
4969                                                                (void*)newns
4970                                                          );
4971                                    }
4972                                    else {
4973                                        continue;
4974                                    }
4975                                }
4976                                else {
4977                                    element = PmmNodeToSv(tnode, owner);
4978                                }
4979
4980                                XPUSHs( sv_2mortal(element) );
4981                            }
4982                        }
4983                        xmlXPathFreeNodeSet( found->nodesetval );
4984                        found->nodesetval = NULL;
4985                    }
4986                    break;
4987                case XPATH_BOOLEAN:
4988                    /* return as a Boolean */
4989                    /* access ->boolval */
4990                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
4991                    XPUSHs(sv_2mortal(newSViv(found->boolval)));
4992                    break;
4993                case XPATH_NUMBER:
4994                    /* return as a Number */
4995                    /* access ->floatval */
4996                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
4997                    XPUSHs(sv_2mortal(newSVnv(found->floatval)));
4998                    break;
4999                case XPATH_STRING:
5000                    /* access ->stringval */
5001                    /* return as a Literal */
5002                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
5003                    XPUSHs(sv_2mortal(C2Sv(found->stringval, NULL)));
5004                    break;
5005                default:
5006                    croak("Unknown XPath return type");
5007            }
5008            xmlXPathFreeObject(found);
5009        }
5010
5011        LibXML_report_error_ctx(saved_error, 0);
5012
5013void
5014_findnodes( pnode, perl_xpath )
5015        SV* pnode
5016        SV * perl_xpath
5017    PREINIT:
5018        SV * saved_error = sv_2mortal(newSVpv("",0));
5019        xmlNodePtr node = PmmSvNode(pnode);
5020        ProxyNodePtr owner = NULL;
5021        xmlNodeSetPtr nodelist = NULL;
5022        SV * element = NULL ;
5023        STRLEN len = 0 ;
5024        xmlChar * xpath = nodeSv2C(perl_xpath, node);
5025    INIT:
5026        if ( node == NULL ) {
5027            croak( "lost node" );
5028        }
5029        if ( !(xpath && xmlStrlen(xpath)) ) {
5030            xs_warn( "bad xpath\n" );
5031            if ( xpath )
5032                xmlFree(xpath);
5033            croak( "empty XPath found" );
5034            XSRETURN_UNDEF;
5035        }
5036    PPCODE:
5037        if ( node->doc ) {
5038            domNodeNormalize( xmlDocGetRootElement(node->doc ) );
5039        }
5040        else {
5041            domNodeNormalize( PmmOWNER(SvPROXYNODE(pnode)) );
5042        }
5043
5044        LibXML_init_error_ctx(saved_error);
5045
5046        nodelist = domXPathSelect( node, xpath );
5047        xmlFree(xpath);
5048
5049        if ( nodelist ) {
5050            if ( nodelist->nodeNr > 0 ) {
5051                int i;
5052                const char * cls = "XML::LibXML::Node";
5053                xmlNodePtr tnode;
5054                owner = PmmOWNERPO(SvPROXYNODE(pnode));
5055                len = nodelist->nodeNr;
5056                for(i=0 ; i < len; i++){
5057                    /* we have to create a new instance of an objectptr.
5058                     * and then place the current node into the new object.
5059                     * afterwards we can push the object to the array!
5060                     */
5061                    element = NULL;
5062                    tnode = nodelist->nodeTab[i];
5063                    if (tnode->type == XML_NAMESPACE_DECL) {
5064                        xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
5065                        if ( newns != NULL ) {
5066                            element = NEWSV(0,0);
5067                            cls = PmmNodeTypeName( tnode );
5068                            element = sv_setref_pv( element,
5069                                                    (const char *)cls,
5070                                                    newns
5071                                                  );
5072                        }
5073                        else {
5074                            continue;
5075                        }
5076                    }
5077                    else {
5078                        element = PmmNodeToSv(tnode, owner);
5079                    }
5080
5081                    XPUSHs( sv_2mortal(element) );
5082                }
5083            }
5084            xmlXPathFreeNodeSet( nodelist );
5085        }
5086
5087        LibXML_report_error_ctx(saved_error, 0);
5088
5089void
5090getNamespaces( pnode )
5091        SV * pnode
5092    ALIAS:
5093        namespaces = 1
5094    PREINIT:
5095        xmlNodePtr node;
5096        xmlNsPtr ns = NULL;
5097        xmlNsPtr newns = NULL;
5098        SV* element = &PL_sv_undef;
5099        const char * class = "XML::LibXML::Namespace";
5100    INIT:
5101        node = PmmSvNode(pnode);
5102        if ( node == NULL ) {
5103            croak( "lost node" );
5104        }
5105    PPCODE:
5106        ns = node->nsDef;
5107        while ( ns != NULL ) {
5108		if (ns->prefix != NULL || ns->href != NULL) {
5109		    newns = xmlCopyNamespace(ns);
5110		    if ( newns != NULL ) {
5111			  element = NEWSV(0,0);
5112			  element = sv_setref_pv( element,
5113							  (const char *)class,
5114							  (void*)newns
5115				);
5116			  XPUSHs( sv_2mortal(element) );
5117		    }
5118		}
5119            ns = ns->next;
5120        }
5121
5122SV *
5123getNamespace( node )
5124        xmlNodePtr node
5125    ALIAS:
5126        localNamespace = 1
5127        localNS        = 2
5128    PREINIT:
5129        xmlNsPtr ns = NULL;
5130        xmlNsPtr newns = NULL;
5131        const char * class = "XML::LibXML::Namespace";
5132    CODE:
5133        ns = node->ns;
5134        if ( ns != NULL ) {
5135            newns = xmlCopyNamespace(ns);
5136            if ( newns != NULL ) {
5137                RETVAL = NEWSV(0,0);
5138                RETVAL = sv_setref_pv( RETVAL,
5139                                       (const char *)class,
5140                                       (void*)newns
5141                                      );
5142            } else {
5143                XSRETURN_UNDEF;
5144	    }
5145        }
5146        else {
5147            XSRETURN_UNDEF;
5148        }
5149    OUTPUT:
5150        RETVAL
5151
5152
5153SV *
5154nodePath( self )
5155        xmlNodePtr self
5156    PREINIT:
5157        xmlChar * path = NULL;
5158    CODE:
5159        path = xmlGetNodePath( self );
5160        if ( path == NULL ) {
5161            croak( "cannot calculate path for the given node" );
5162        }
5163        RETVAL = nodeC2Sv( path, self );
5164        xmlFree(path);
5165    OUTPUT:
5166        RETVAL
5167
5168int
5169line_number( self )
5170        xmlNodePtr self
5171    CODE:
5172        RETVAL = xmlGetLineNo( self );
5173    OUTPUT:
5174        RETVAL
5175
5176MODULE = XML::LibXML         PACKAGE = XML::LibXML::Element
5177
5178SV*
5179new(CLASS, name )
5180        char * CLASS
5181        char * name
5182    PREINIT:
5183        xmlNodePtr newNode;
5184        ProxyNodePtr docfrag;
5185    CODE:
5186        docfrag = PmmNewFragment(NULL);
5187        newNode = xmlNewNode( NULL, (const xmlChar*)name );
5188        newNode->doc = NULL;
5189        xmlAddChild(PmmNODE(docfrag), newNode);
5190        RETVAL = PmmNodeToSv(newNode, docfrag );
5191    OUTPUT:
5192        RETVAL
5193
5194int
5195_setNamespace(self, namespaceURI, namespacePrefix = &PL_sv_undef, flag = 1 )
5196        SV * self
5197        SV * namespaceURI
5198        SV * namespacePrefix
5199        int flag
5200    PREINIT:
5201        xmlNodePtr node = PmmSvNode(self);
5202        xmlChar * nsURI = nodeSv2C(namespaceURI,node);
5203        xmlChar * nsPrefix = NULL;
5204        xmlNsPtr ns = NULL;
5205    INIT:
5206        if ( node == NULL ) {
5207            croak( "lost node" );
5208        }
5209    CODE:
5210       /* if ( !nsURI ){
5211            XSRETURN_UNDEF;
5212		} */
5213
5214        nsPrefix = nodeSv2C(namespacePrefix, node);
5215        if ( xmlStrlen( nsPrefix ) == 0 ) {
5216            xmlFree(nsPrefix);
5217            nsPrefix = NULL;
5218        }
5219        if ( xmlStrlen( nsURI ) == 0 ) {
5220            xmlFree(nsURI);
5221            nsURI = NULL;
5222        }
5223        if ( nsPrefix == NULL && nsURI == NULL ) {
5224	    /* special case: empty namespace */
5225	    if ( (ns = xmlSearchNs(node->doc, node, NULL)) &&
5226		 ( ns->href && xmlStrlen( ns->href ) != 0 ) ) {
5227		/* won't take it */
5228		RETVAL = 0;
5229	    } else if ( flag ) {
5230		/* no namespace */
5231		xmlSetNs(node, NULL);
5232		RETVAL = 1;
5233	    } else {
5234		RETVAL = 0;
5235	    }
5236	}
5237        else if ( flag && (ns = xmlSearchNs(node->doc, node, nsPrefix)) ) {
5238	  /* user just wants to set the namespace for the node */
5239	  /* try to reuse an existing declaration for the prefix */
5240            if ( xmlStrEqual( ns->href, nsURI ) ) {
5241                RETVAL = 1;
5242            }
5243            else if ( (ns = xmlNewNs( node, nsURI, nsPrefix )) ) {
5244                RETVAL = 1;
5245            }
5246            else {
5247                RETVAL = 0;
5248            }
5249        }
5250        else if ( (ns = xmlNewNs( node, nsURI, nsPrefix )) )
5251	  RETVAL = 1;
5252	else
5253	  RETVAL = 0;
5254
5255        if ( flag && ns ) {
5256            xmlSetNs(node, ns);
5257        }
5258        if ( nsPrefix ) xmlFree(nsPrefix);
5259        if ( nsURI ) xmlFree(nsURI);
5260    OUTPUT:
5261        RETVAL
5262
5263
5264SV*
5265_getNamespaceDeclURI( self, ns_prefix )
5266        xmlNodePtr self
5267        SV * ns_prefix
5268    PREINIT:
5269        xmlChar * prefix;
5270        xmlNsPtr ns;
5271    CODE:
5272        prefix = nodeSv2C(ns_prefix, self );
5273        if ( prefix != NULL && xmlStrlen(prefix) == 0) {
5274		xmlFree( prefix );
5275		prefix = NULL;
5276	  }
5277        RETVAL = &PL_sv_undef;
5278        ns = self->nsDef;
5279        while ( ns != NULL ) {
5280		if ( (ns->prefix != NULL || ns->href != NULL) &&
5281		     xmlStrcmp( ns->prefix, prefix ) == 0 ) {
5282		    RETVAL = C2Sv(ns->href, NULL);
5283		    break;
5284		} else {
5285		    ns = ns->next;
5286		}
5287	  }
5288        if ( prefix != NULL ) {
5289		xmlFree( prefix );
5290	  }
5291
5292    OUTPUT:
5293        RETVAL
5294
5295int
5296hasAttribute( self, attr_name )
5297        xmlNodePtr self
5298        SV * attr_name
5299    PREINIT:
5300        xmlChar * name;
5301    CODE:
5302        name  = nodeSv2C(attr_name, self );
5303        if ( ! name ) {
5304            XSRETURN_UNDEF;
5305        }
5306        if ( domGetAttrNode( self, name ) ) {
5307            RETVAL = 1;
5308        }
5309        else {
5310            RETVAL = 0;
5311        }
5312        xmlFree(name);
5313    OUTPUT:
5314        RETVAL
5315
5316int
5317hasAttributeNS( self, namespaceURI, attr_name )
5318        xmlNodePtr self
5319        SV * namespaceURI
5320        SV * attr_name
5321    PREINIT:
5322        xmlChar * name;
5323        xmlChar * nsURI;
5324	xmlNodePtr attr;
5325    CODE:
5326        name = nodeSv2C(attr_name, self );
5327        nsURI = nodeSv2C(namespaceURI, self );
5328
5329        if ( name == NULL ) {
5330            if ( nsURI != NULL ) {
5331              xmlFree(nsURI);
5332            }
5333            XSRETURN_UNDEF;
5334        }
5335        if ( nsURI != NULL && xmlStrlen(nsURI) == 0 ){
5336            xmlFree(nsURI);
5337            nsURI = NULL;
5338        }
5339        attr = (xmlNodePtr) xmlHasNsProp( self, name, nsURI );
5340        if ( attr && attr->type == XML_ATTRIBUTE_NODE ) {
5341            RETVAL = 1;
5342        }
5343        else {
5344            RETVAL = 0;
5345        }
5346
5347        xmlFree(name);
5348        if ( nsURI != NULL ){
5349            xmlFree(nsURI);
5350        }
5351    OUTPUT:
5352        RETVAL
5353
5354SV*
5355_getAttribute( self, attr_name, doc_enc = 0 )
5356        xmlNodePtr self
5357        SV * attr_name
5358        int doc_enc
5359    PREINIT:
5360        xmlChar * name;
5361        xmlChar * prefix    = NULL;
5362        xmlChar * localname = NULL;
5363        xmlChar * ret = NULL;
5364        xmlNsPtr ns = NULL;
5365    CODE:
5366        name = nodeSv2C(attr_name, self );
5367        if( !name ) {
5368            XSRETURN_UNDEF;
5369        }
5370
5371        ret = xmlGetNoNsProp(self, name);
5372        if ( ret == NULL ) {
5373            localname = xmlSplitQName2(name, &prefix);
5374            if ( localname != NULL ) {
5375		    ns = xmlSearchNs( self->doc, self, prefix );
5376		    if ( ns != NULL ) {
5377			  ret = xmlGetNsProp(self, localname, ns->href);
5378		    }
5379		    if ( prefix != NULL) {
5380			  xmlFree( prefix );
5381		    }
5382		    xmlFree( localname );
5383		}
5384        }
5385        xmlFree(name);
5386        if ( ret ) {
5387            if ( doc_enc == 1 ) {
5388                RETVAL = nodeC2Sv(ret, self);
5389            }
5390            else {
5391                RETVAL = C2Sv(ret, NULL);
5392            }
5393            xmlFree( ret );
5394        }
5395        else {
5396            XSRETURN_UNDEF;
5397	}
5398
5399    OUTPUT:
5400        RETVAL
5401
5402void
5403_setAttribute( self, attr_name, attr_value )
5404        xmlNodePtr self
5405        SV * attr_name
5406        SV * attr_value
5407    PREINIT:
5408        xmlChar * name  = NULL;
5409        xmlChar * value = NULL;
5410#if LIBXML_VERSION < 20621
5411        xmlChar * prefix    = NULL;
5412        xmlChar * localname = NULL;
5413#endif
5414    CODE:
5415        name  = nodeSv2C(attr_name, self );
5416
5417        if ( !LibXML_test_node_name(name) ) {
5418            xmlFree(name);
5419            croak( "bad name" );
5420        }
5421        value = nodeSv2C(attr_value, self );
5422#if LIBXML_VERSION >= 20621
5423	/*
5424	 * For libxml2-2.6.21 and later we can use just xmlSetProp
5425         */
5426        xmlSetProp(self,name,value);
5427#else
5428        /*
5429         * but xmlSetProp does not work correctly for older libxml2 versions
5430	 * The following is copied from libxml2 source
5431         * with xmlSplitQName3 replaced by xmlSplitQName2 for compatibility
5432         * with older libxml2 versions
5433         */
5434        localname = xmlSplitQName2(name, &prefix);
5435        if (localname != NULL) {
5436          xmlNsPtr ns;
5437	  ns = xmlSearchNs(self->doc, self, prefix);
5438	  if (prefix != NULL)
5439	      xmlFree(prefix);
5440	  if (ns != NULL)
5441	      xmlSetNsProp(self, ns, localname, value);
5442	  else
5443              xmlSetNsProp(self, NULL, name, value);
5444          xmlFree(localname);
5445        } else {
5446            xmlSetNsProp(self, NULL, name, value);
5447        }
5448#endif
5449        xmlFree(name);
5450        xmlFree(value);
5451
5452
5453void
5454removeAttribute( self, attr_name )
5455        xmlNodePtr self
5456        SV * attr_name
5457    PREINIT:
5458        xmlChar * name;
5459        xmlAttrPtr xattr = NULL;
5460    CODE:
5461        name  = nodeSv2C(attr_name, self );
5462        if ( name ) {
5463            xattr = domGetAttrNode( self, name );
5464
5465            if ( xattr ) {
5466                xmlUnlinkNode((xmlNodePtr)xattr);
5467                if ( xattr->_private ) {
5468                    PmmFixOwner((ProxyNodePtr)xattr->_private, NULL);
5469                }
5470                else {
5471                    xmlFreeProp(xattr);
5472                }
5473            }
5474            xmlFree(name);
5475        }
5476
5477SV*
5478getAttributeNode( self, attr_name )
5479        xmlNodePtr self
5480        SV * attr_name
5481    PREINIT:
5482        xmlChar * name;
5483        xmlAttrPtr ret = NULL;
5484    CODE:
5485        name = nodeSv2C(attr_name, self );
5486        if ( !name ) {
5487            XSRETURN_UNDEF;
5488        }
5489
5490        ret = domGetAttrNode( self, name );
5491        xmlFree(name);
5492        if ( ret ) {
5493            RETVAL = PmmNodeToSv( (xmlNodePtr)ret,
5494                                   PmmOWNERPO(PmmPROXYNODE(self)) );
5495        }
5496        else {
5497            XSRETURN_UNDEF;
5498        }
5499    OUTPUT:
5500        RETVAL
5501
5502SV *
5503setAttributeNode( self, attr_node )
5504        xmlNodePtr self
5505        SV * attr_node
5506    PREINIT:
5507        xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
5508        xmlAttrPtr ret = NULL;
5509    INIT:
5510        if ( attr == NULL ) {
5511            croak( "lost attribute" );
5512        }
5513    CODE:
5514        if ( attr != NULL && attr->type != XML_ATTRIBUTE_NODE ) {
5515            XSRETURN_UNDEF;
5516        }
5517        if ( attr->doc != self->doc ) {
5518	    domImportNode( self->doc, (xmlNodePtr)attr, 1, 1);
5519        }
5520        ret = domGetAttrNode( self, attr->name );
5521        if ( ret != NULL ) {
5522            if ( ret != attr ) {
5523                xmlReplaceNode( (xmlNodePtr)ret, (xmlNodePtr)attr );
5524            }
5525            else {
5526                XSRETURN_UNDEF;
5527            }
5528        }
5529        else {
5530            xmlAddChild( self, (xmlNodePtr)attr );
5531        }
5532
5533        if ( attr->_private != NULL ) {
5534            PmmFixOwner( SvPROXYNODE(attr_node), PmmPROXYNODE(self) );
5535        }
5536
5537        if ( ret == NULL ) {
5538            XSRETURN_UNDEF;
5539        }
5540
5541        RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
5542        PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
5543    OUTPUT:
5544        RETVAL
5545
5546SV *
5547_getAttributeNS( self, namespaceURI, attr_name )
5548        xmlNodePtr self
5549        SV * namespaceURI
5550        SV * attr_name
5551    PREINIT:
5552        xmlChar * name;
5553        xmlChar * nsURI;
5554        xmlChar * ret = NULL;
5555    CODE:
5556        name = nodeSv2C( attr_name, self );
5557        nsURI = nodeSv2C( namespaceURI, self );
5558        if ( !name ) {
5559            xmlFree(nsURI);
5560            XSRETURN_UNDEF;
5561        }
5562        if ( nsURI && xmlStrlen(nsURI) ) {
5563            ret = xmlGetNsProp( self, name, nsURI );
5564        }
5565        else {
5566            ret = xmlGetProp( self, name );
5567        }
5568
5569        xmlFree( name );
5570        if ( nsURI ) {
5571            xmlFree( nsURI );
5572        }
5573        if ( ret ) {
5574            RETVAL = nodeC2Sv( ret, self );
5575            xmlFree( ret );
5576        }
5577        else {
5578            XSRETURN_UNDEF;
5579        }
5580    OUTPUT:
5581        RETVAL
5582
5583void
5584_setAttributeNS( self, namespaceURI, attr_name, attr_value )
5585        xmlNodePtr self
5586        SV * namespaceURI
5587        SV * attr_name
5588        SV * attr_value
5589    PREINIT:
5590        xmlChar * nsURI;
5591        xmlChar * name  = NULL;
5592        xmlChar * value = NULL;
5593        xmlNsPtr ns         = NULL;
5594        xmlChar * localname = NULL;
5595        xmlChar * prefix    = NULL;
5596    INIT:
5597        name  = nodeSv2C( attr_name, self );
5598
5599        if ( !LibXML_test_node_name(name) ) {
5600            xmlFree(name);
5601            croak( "bad name" );
5602        }
5603
5604        nsURI = nodeSv2C( namespaceURI, self );
5605        localname = xmlSplitQName2(name, &prefix);
5606        if ( localname ) {
5607            xmlFree( name );
5608            name = localname;
5609        }
5610    CODE:
5611        value = nodeSv2C( attr_value, self );
5612
5613        if ( nsURI && xmlStrlen(nsURI) ) {
5614            xs_warn( "found uri" );
5615
5616            ns = xmlSearchNsByHref( self->doc, self, nsURI );
5617            if ( !ns ) {
5618                /* create new ns */
5619                 if ( prefix && xmlStrlen( prefix ) ) {
5620                    ns = xmlNewNs(self, nsURI , prefix );
5621                 }
5622                 else {
5623                    ns = NULL;
5624                 }
5625            }
5626            else if ( !ns->prefix ) {
5627                if ( ns->next && ns->next->prefix ) {
5628                    ns = ns->next;
5629                }
5630                else if ( prefix && xmlStrlen( prefix ) ) {
5631                    ns = xmlNewNs(self, nsURI , prefix );
5632                }
5633                else {
5634                    ns = NULL;
5635                }
5636            }
5637        }
5638
5639        if ( nsURI && xmlStrlen(nsURI) && !ns ) {
5640	  if ( prefix ) xmlFree( prefix );
5641	  if ( nsURI ) xmlFree( nsURI );
5642	  xmlFree( name );
5643	  xmlFree( value );
5644	  croak( "bad ns attribute!" );
5645        }
5646        else {
5647            /* warn( "set attribute %s->%s", name, value ); */
5648            xmlSetNsProp( self, ns, name, value );
5649        }
5650
5651        if ( prefix ) {
5652            xmlFree( prefix );
5653        }
5654        if ( nsURI ) {
5655            xmlFree( nsURI );
5656        }
5657        xmlFree( name );
5658        xmlFree( value );
5659
5660void
5661removeAttributeNS( self, namespaceURI, attr_name )
5662        xmlNodePtr self
5663        SV * namespaceURI
5664        SV * attr_name
5665    PREINIT:
5666        xmlChar * nsURI;
5667        xmlChar * name  = NULL;
5668        xmlAttrPtr xattr = NULL;
5669    CODE:
5670        nsURI = nodeSv2C( namespaceURI, self );
5671        name  = nodeSv2C( attr_name, self );
5672        if ( ! name ) {
5673            xmlFree(nsURI);
5674            XSRETURN_UNDEF;
5675        }
5676
5677        if ( nsURI && xmlStrlen(nsURI) ) {
5678            xattr = xmlHasNsProp( self, name, nsURI );
5679        }
5680        else {
5681            xattr = xmlHasNsProp( self, name, NULL );
5682        }
5683        if ( xattr && xattr->type == XML_ATTRIBUTE_NODE ) {
5684            xmlUnlinkNode((xmlNodePtr)xattr);
5685            if ( xattr->_private ) {
5686                PmmFixOwner((ProxyNodePtr)xattr->_private, NULL);
5687            }
5688            else {
5689                xmlFreeProp(xattr);
5690            }
5691        }
5692        xmlFree(nsURI);
5693        xmlFree( name );
5694
5695
5696SV*
5697getAttributeNodeNS( self,namespaceURI, attr_name )
5698        xmlNodePtr self
5699        SV * namespaceURI
5700        SV * attr_name
5701    PREINIT:
5702        xmlChar * nsURI;
5703        xmlChar * name;
5704        xmlAttrPtr ret = NULL;
5705    CODE:
5706        nsURI = nodeSv2C(namespaceURI, self );
5707        name = nodeSv2C(attr_name, self );
5708        if ( !name ) {
5709            xmlFree(nsURI);
5710            XSRETURN_UNDEF;
5711        }
5712        if ( nsURI && xmlStrlen(nsURI) ) {
5713            ret = xmlHasNsProp( self, name, nsURI );
5714        }
5715        else {
5716            ret = xmlHasNsProp( self, name, NULL );
5717        }
5718        xmlFree(name);
5719        if ( nsURI ) {
5720            xmlFree(nsURI);
5721        }
5722        if ( ret &&
5723	     ret->type == XML_ATTRIBUTE_NODE /* we don't want fixed attribute decls */
5724	   ) {
5725            RETVAL = PmmNodeToSv( (xmlNodePtr)ret,
5726                                   PmmOWNERPO(PmmPROXYNODE(self)) );
5727        }
5728        else {
5729            /* warn("no prop\n"); */
5730            XSRETURN_UNDEF;
5731        }
5732    OUTPUT:
5733        RETVAL
5734
5735SV *
5736setAttributeNodeNS( self, attr_node )
5737        xmlNodePtr self
5738        SV * attr_node
5739    PREINIT:
5740        xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
5741        xmlNsPtr ns = NULL;
5742        xmlAttrPtr ret = NULL;
5743    INIT:
5744        if ( attr == NULL ) {
5745            croak( "lost attribute node" );
5746        }
5747    CODE:
5748        if ( attr->type != XML_ATTRIBUTE_NODE ) {
5749            XSRETURN_UNDEF;
5750        }
5751
5752        if ( attr->doc != self->doc ) {
5753           domImportNode( self->doc, (xmlNodePtr)attr, 1,1);
5754        }
5755
5756
5757        ns = attr->ns;
5758        if ( ns != NULL ) {
5759            ret = xmlHasNsProp( self, ns->href, attr->name );
5760        }
5761        else {
5762            ret = xmlHasNsProp( self, NULL, attr->name );
5763        }
5764
5765        if ( ret && ret->type == XML_ATTRIBUTE_NODE ) {
5766            if ( ret != attr ) {
5767                xmlReplaceNode( (xmlNodePtr)ret, (xmlNodePtr)attr );
5768            }
5769            else {
5770                XSRETURN_UNDEF;
5771            }
5772        }
5773        else {
5774            xmlAddChild( self, (xmlNodePtr)attr );
5775            xmlReconciliateNs(self->doc, self);
5776        }
5777        if ( attr->_private != NULL ) {
5778            PmmFixOwner( SvPROXYNODE(attr_node), PmmPROXYNODE(self) );
5779        }
5780        if ( ret != NULL && ret->type == XML_ATTRIBUTE_NODE ) {
5781	    RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
5782	    PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
5783	} else {
5784            XSRETURN_UNDEF;
5785        }
5786    OUTPUT:
5787        RETVAL
5788
5789SV *
5790removeAttributeNode( self, attr_node )
5791        xmlNodePtr self
5792        SV * attr_node
5793    PREINIT:
5794        xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
5795        xmlAttrPtr ret;
5796    INIT:
5797        if ( attr == NULL ) {
5798            croak( "lost attribute node" );
5799        }
5800    CODE:
5801        if ( attr->type != XML_ATTRIBUTE_NODE ) {
5802            XSRETURN_UNDEF;
5803        }
5804        if ( attr->parent != self ) {
5805            XSRETURN_UNDEF;
5806        }
5807        ret = attr;
5808        xmlUnlinkNode( (xmlNodePtr)attr );
5809        RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
5810        PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
5811    OUTPUT:
5812        RETVAL
5813
5814void
5815appendText( self, string )
5816        xmlNodePtr self
5817        SV * string
5818    ALIAS:
5819        appendTextNode = 1
5820        XML::LibXML::DocumentFragment::appendText = 2
5821        XML::LibXML::DocumentFragment::appendTextNode = 3
5822    PREINIT:
5823        xmlChar * content = NULL;
5824    INIT:
5825        content = nodeSv2C( string, self );
5826        if ( content == NULL ) {
5827            XSRETURN_UNDEF;
5828        }
5829        if ( xmlStrlen(content) == 0 ) {
5830            xmlFree( content );
5831            XSRETURN_UNDEF;
5832        }
5833    CODE:
5834        xmlNodeAddContent( self, content );
5835        xmlFree(content);
5836
5837
5838void
5839appendTextChild( self, strname, strcontent=&PL_sv_undef, nsURI=&PL_sv_undef )
5840        xmlNodePtr self
5841        SV * strname
5842        SV * strcontent
5843        SV * nsURI
5844    PREINIT:
5845        xmlChar * name;
5846        xmlChar * content = NULL;
5847        xmlChar * encstr  = NULL;
5848    INIT:
5849        name    = nodeSv2C( strname, self );
5850        if ( xmlStrlen(name) == 0 ) {
5851            xmlFree(name);
5852            XSRETURN_UNDEF;
5853        }
5854    CODE:
5855        content = nodeSv2C(strcontent, self);
5856        if ( content &&  xmlStrlen( content ) == 0 ) {
5857            xmlFree(content);
5858            content=NULL;
5859        }
5860        else if ( content ) {
5861            encstr = xmlEncodeEntitiesReentrant( self->doc, content );
5862            xmlFree(content);
5863        }
5864
5865        xmlNewChild( self, NULL, name, encstr );
5866
5867        if ( encstr )
5868            xmlFree(encstr);
5869        xmlFree(name);
5870
5871SV *
5872addNewChild( self, namespaceURI, nodename )
5873        xmlNodePtr self
5874        SV * namespaceURI
5875        SV * nodename
5876    ALIAS:
5877        XML::LibXML::DocumentFragment::addNewChild = 1
5878    PREINIT:
5879        xmlChar * nsURI = NULL;
5880        xmlChar * name  = NULL;
5881        xmlChar * localname  = NULL;
5882        xmlChar * prefix     = NULL;
5883        xmlNodePtr newNode = NULL;
5884        xmlNodePtr prev = NULL;
5885        xmlNsPtr ns = NULL;
5886    CODE:
5887        name = nodeSv2C(nodename, self);
5888        if ( name &&  xmlStrlen( name ) == 0 ) {
5889            xmlFree(name);
5890            XSRETURN_UNDEF;
5891        }
5892
5893        nsURI = nodeSv2C(namespaceURI, self);
5894        if ( nsURI &&  xmlStrlen( nsURI ) == 0 ) {
5895            xmlFree(nsURI);
5896            nsURI=NULL;
5897        }
5898
5899        if ( nsURI != NULL ) {
5900            localname = xmlSplitQName2(name, &prefix);
5901            ns = xmlSearchNsByHref(self->doc, self, nsURI);
5902
5903            newNode = xmlNewDocNode(self->doc,
5904                                ns,
5905                                localname?localname:name,
5906                                NULL);
5907            if ( ns == NULL )  {
5908	        xmlSetNs(newNode,xmlNewNs(newNode, nsURI, prefix));
5909            }
5910
5911            xmlFree(localname);
5912            xmlFree(prefix);
5913            xmlFree(nsURI);
5914        }
5915        else {
5916            newNode = xmlNewDocNode(self->doc,
5917                                    NULL,
5918                                    name,
5919                                    NULL);
5920        }
5921        xmlFree(name);
5922        /* add the node to the parent node */
5923        newNode->type = XML_ELEMENT_NODE;
5924        newNode->parent = self;
5925        newNode->doc = self->doc;
5926
5927        if (self->children == NULL) {
5928            self->children = newNode;
5929            self->last = newNode;
5930        } else {
5931            prev = self->last;
5932            prev->next = newNode;
5933            newNode->prev = prev;
5934            self->last = newNode;
5935        }
5936        RETVAL = PmmNodeToSv(newNode, PmmOWNERPO(PmmPROXYNODE(self)) );
5937    OUTPUT:
5938        RETVAL
5939
5940MODULE = XML::LibXML         PACKAGE = XML::LibXML::Text
5941
5942SV *
5943new( CLASS, content )
5944        const char * CLASS
5945        SV * content
5946    PREINIT:
5947        xmlChar * data;
5948        xmlNodePtr newNode;
5949        ProxyNodePtr docfrag = NULL;
5950    CODE:
5951        data = Sv2C(content, NULL);
5952        newNode = xmlNewText( data );
5953        xmlFree(data);
5954        if( newNode != NULL ) {
5955            docfrag = PmmNewFragment( NULL );
5956            xmlAddChild(PmmNODE(docfrag), newNode);
5957            RETVAL = PmmNodeToSv(newNode,docfrag);
5958        }
5959        else {
5960            XSRETURN_UNDEF;
5961        }
5962    OUTPUT:
5963        RETVAL
5964
5965SV *
5966substringData( self, offset, length )
5967        xmlNodePtr self
5968        int offset
5969        int length
5970    PREINIT:
5971        xmlChar * data = NULL;
5972        xmlChar * substr = NULL;
5973        int len = 0;
5974        int dl = 0;
5975    CODE:
5976        if ( offset >= 0 && length > 0 ) {
5977            dl = offset + length - 1 ;
5978            data = domGetNodeValue( self );
5979            len = xmlStrlen( data );
5980            if ( data != NULL && len > 0 && len > offset ) {
5981                if ( dl > len )
5982                    dl = offset + len;
5983
5984                substr = xmlStrsub( data, offset, dl );
5985                RETVAL = C2Sv( (const xmlChar*)substr, NULL );
5986                xmlFree( substr );
5987            }
5988            else {
5989                XSRETURN_UNDEF;
5990            }
5991        }
5992        else {
5993            XSRETURN_UNDEF;
5994        }
5995    OUTPUT:
5996        RETVAL
5997
5998void
5999setData( self, value )
6000        xmlNodePtr self
6001        SV * value
6002    ALIAS:
6003        XML::LibXML::Attr::setValue = 1
6004        XML::LibXML::PI::_setData = 2
6005    PREINIT:
6006        xmlChar * encstr = NULL;
6007    CODE:
6008        encstr = nodeSv2C(value,self);
6009        domSetNodeValue( self, encstr );
6010        xmlFree(encstr);
6011
6012void
6013appendData( self, value )
6014        xmlNodePtr self
6015        SV * value
6016    PREINIT:
6017        xmlChar * encstring = NULL;
6018        int strlen = 0;
6019    CODE:
6020        encstring = Sv2C( value,
6021                          self->doc!=NULL ? self->doc->encoding : NULL );
6022
6023       if ( encstring != NULL ) {
6024            strlen = xmlStrlen( encstring );
6025            xmlTextConcat( self, encstring, strlen );
6026            xmlFree( encstring );
6027        }
6028
6029void
6030insertData( self, offset, value )
6031        xmlNodePtr self
6032        int offset
6033        SV * value
6034    PREINIT:
6035        xmlChar * after= NULL;
6036        xmlChar * data = NULL;
6037        xmlChar * new  = NULL;
6038        xmlChar * encstring = NULL;
6039        int dl = 0;
6040    CODE:
6041        if ( offset >= 0 ) {
6042            encstring = Sv2C( value,
6043                              self->doc!=NULL ? self->doc->encoding : NULL );
6044            if ( encstring != NULL && xmlStrlen( encstring ) > 0 ) {
6045                data = domGetNodeValue(self);
6046                if ( data != NULL && xmlStrlen( data ) > 0 ) {
6047                    if ( xmlStrlen( data ) < offset ) {
6048                        data = xmlStrcat( data, encstring );
6049                        domSetNodeValue( self, data );
6050                    }
6051                    else {
6052                        dl = xmlStrlen( data ) - offset;
6053
6054                        if ( offset > 0 )
6055                            new   = xmlStrsub(data, 0, offset );
6056
6057                        after = xmlStrsub(data, offset, dl );
6058
6059                        if ( new != NULL ) {
6060                            new = xmlStrcat(new, encstring );
6061                        }
6062                        else {
6063                            new = xmlStrdup( encstring );
6064                        }
6065
6066                        if ( after != NULL )
6067                            new = xmlStrcat(new, after );
6068
6069                        domSetNodeValue( self, new );
6070
6071                        xmlFree( new );
6072                        xmlFree( after );
6073                    }
6074                    xmlFree( data );
6075                }
6076                else {
6077                    domSetNodeValue( self, encstring );
6078                }
6079                xmlFree(encstring);
6080            }
6081        }
6082
6083void
6084deleteData( self, offset, length )
6085        xmlNodePtr self
6086        int offset
6087        int length
6088    PREINIT:
6089        xmlChar * data  = NULL;
6090        xmlChar * after = NULL;
6091        xmlChar * new   = NULL;
6092        int len = 0;
6093        int dl1 = 0;
6094        int dl2 = 0;
6095    CODE:
6096        if ( length > 0 && offset >= 0 ) {
6097            data = domGetNodeValue(self);
6098            len = xmlStrlen( data );
6099            if ( data != NULL
6100                 && len > 0
6101                 && len > offset ) {
6102                dl1 = offset + length;
6103                if ( offset > 0 )
6104                    new = xmlStrsub( data, 0, offset );
6105
6106                if ( len > dl1 ) {
6107                    dl2 = len - dl1;
6108                    after = xmlStrsub( data, dl1, dl2 );
6109                    if ( new != NULL ) {
6110                        new = xmlStrcat( new, after );
6111                        xmlFree(after);
6112                    }
6113                    else {
6114                        new = after;
6115                    }
6116                }
6117
6118                domSetNodeValue( self, new );
6119                xmlFree(new);
6120            }
6121        }
6122
6123void
6124replaceData( self, offset,length, value )
6125        xmlNodePtr self
6126        int offset
6127        int length
6128        SV * value
6129    PREINIT:
6130        xmlChar * after= NULL;
6131        xmlChar * data = NULL;
6132        xmlChar * new  = NULL;
6133        xmlChar * encstring = NULL;
6134        int len = 0;
6135        int dl1 = 0;
6136        int dl2 = 0;
6137    CODE:
6138        if ( offset >= 0 ) {
6139            encstring = Sv2C( value,
6140                              self->doc!=NULL ? self->doc->encoding : NULL );
6141
6142            if ( encstring != NULL && xmlStrlen( encstring ) > 0 ) {
6143                data = domGetNodeValue(self);
6144                len = xmlStrlen( data );
6145
6146                if ( data != NULL
6147                     && len > 0
6148                     && len > offset  ) {
6149
6150                    dl1 = offset + length;
6151                    if ( dl1 < len ) {
6152                        dl2 = xmlStrlen( data ) - dl1;
6153                        if ( offset > 0 ) {
6154                            new = xmlStrsub(data, 0, offset );
6155                            new = xmlStrcat(new, encstring );
6156                        }
6157                        else {
6158                            new   = xmlStrdup( encstring );
6159                        }
6160
6161                        after = xmlStrsub(data, dl1, dl2 );
6162                        new = xmlStrcat(new, after );
6163
6164                        domSetNodeValue( self, new );
6165
6166                        xmlFree( new );
6167                        xmlFree( after );
6168                    }
6169                    else {
6170                        /* replace until end! */
6171                        if ( offset > 0 ) {
6172                            new = xmlStrsub(data, 0, offset );
6173                            new = xmlStrcat(new, encstring );
6174                        }
6175                        else {
6176                            new   = xmlStrdup( encstring );
6177                        }
6178                        domSetNodeValue( self, new );
6179                        xmlFree( new );
6180                    }
6181                    xmlFree( data );
6182                }
6183
6184                xmlFree(encstring);
6185            }
6186        }
6187
6188MODULE = XML::LibXML         PACKAGE = XML::LibXML::Comment
6189
6190SV *
6191new( CLASS, content )
6192        const char * CLASS
6193        SV * content
6194    PREINIT:
6195        xmlChar * encstring;
6196        xmlNodePtr newNode;
6197        ProxyNodePtr docfrag = NULL;
6198    CODE:
6199        encstring = Sv2C(content, NULL);
6200        newNode = xmlNewComment( encstring );
6201        xmlFree(encstring);
6202        if( newNode != NULL ) {
6203            docfrag = PmmNewFragment( NULL );
6204            xmlAddChild(PmmNODE(docfrag), newNode);
6205            RETVAL = PmmNodeToSv(newNode,docfrag);
6206        }
6207        else {
6208            XSRETURN_UNDEF;
6209        }
6210    OUTPUT:
6211        RETVAL
6212
6213MODULE = XML::LibXML         PACKAGE = XML::LibXML::CDATASection
6214
6215SV *
6216new( CLASS , content )
6217        const char * CLASS
6218        SV * content
6219    PREINIT:
6220        xmlChar * encstring;
6221        xmlNodePtr newNode;
6222        ProxyNodePtr docfrag = NULL;
6223    CODE:
6224        encstring = Sv2C(content, NULL);
6225        newNode = xmlNewCDataBlock( NULL , encstring, xmlStrlen( encstring ) );
6226        xmlFree(encstring);
6227        if ( newNode != NULL ){
6228            docfrag = PmmNewFragment( NULL );
6229            xmlAddChild(PmmNODE(docfrag), newNode);
6230            RETVAL = PmmNodeToSv(newNode,docfrag);
6231        }
6232        else {
6233            XSRETURN_UNDEF;
6234        }
6235    OUTPUT:
6236        RETVAL
6237
6238MODULE = XML::LibXML         PACKAGE = XML::LibXML::DocumentFragment
6239
6240SV*
6241new( CLASS )
6242        char * CLASS
6243    PREINIT:
6244        xmlNodePtr real_doc=NULL;
6245    CODE:
6246        real_doc = xmlNewDocFragment( NULL );
6247        RETVAL = PmmNodeToSv( real_doc, NULL );
6248    OUTPUT:
6249        RETVAL
6250
6251MODULE = XML::LibXML         PACKAGE = XML::LibXML::Attr
6252
6253SV*
6254new( CLASS, pname, pvalue )
6255        char * CLASS
6256        SV * pname
6257        SV * pvalue
6258    PREINIT:
6259        xmlNodePtr attr = NULL;
6260        xmlChar * name;
6261        xmlChar * value;
6262    CODE:
6263        name  = Sv2C(pname,NULL);
6264        value = Sv2C(pvalue,NULL);
6265        if ( name == NULL ) {
6266            XSRETURN_UNDEF;
6267        }
6268        attr =  (xmlNodePtr)xmlNewProp( NULL, name, value );
6269        attr->doc = NULL;
6270        RETVAL = PmmNodeToSv(attr,NULL);
6271    OUTPUT:
6272        RETVAL
6273
6274
6275SV*
6276parentElement( attrnode )
6277        SV * attrnode
6278    ALIAS:
6279        XML::LibXML::Attr::getParentNode = 1
6280        XML::LibXML::Attr::getNextSibling = 2
6281        XML::LibXML::Attr::getPreviousSibling = 3
6282        XML::LibXML::Attr::nextSibling = 4
6283        XML::LibXML::Attr::previousSibling = 5
6284    CODE:
6285        /* override the original parentElement(), since this an attribute is
6286         * not part of the main tree
6287         */
6288
6289        XSRETURN_UNDEF;
6290    OUTPUT:
6291        RETVAL
6292
6293SV*
6294serializeContent( self, useDomEncoding = &PL_sv_undef )
6295        SV * self
6296        SV * useDomEncoding
6297    PREINIT:
6298        xmlBufferPtr buffer;
6299        const xmlChar *ret = NULL;
6300        xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
6301    CODE:
6302        buffer = xmlBufferCreate();
6303        domAttrSerializeContent(buffer, node);
6304        if ( xmlBufferLength(buffer) > 0 ) {
6305            ret = xmlBufferContent( buffer );
6306        }
6307        if ( ret != NULL ) {
6308            if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
6309                RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(node))) ;
6310            }
6311            else {
6312                RETVAL = C2Sv((xmlChar*)ret, NULL) ;
6313            }
6314            xmlBufferFree( buffer );
6315        }
6316        else {
6317            xmlBufferFree( buffer );
6318            xs_warn("Failed to convert attribute to string");
6319            XSRETURN_UNDEF;
6320        }
6321    OUTPUT:
6322        RETVAL
6323
6324SV*
6325toString(self , format=0, useDomEncoding = &PL_sv_undef )
6326	SV * self
6327        SV * useDomEncoding
6328	int format
6329    ALIAS:
6330        XML::LibXML::Attr::serialize = 1
6331    PREINIT:
6332        xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
6333        xmlBufferPtr buffer;
6334        const xmlChar *ret = NULL;
6335    CODE:
6336        /* we add an extra method for serializing attributes since
6337           XML::LibXML::Node::toString causes segmentation fault inside
6338           libxml2
6339	 */
6340        buffer = xmlBufferCreate();
6341        xmlBufferAdd(buffer, BAD_CAST " ", 1);
6342        if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6343	  xmlBufferAdd(buffer, node->ns->prefix, xmlStrlen(node->ns->prefix));
6344	  xmlBufferAdd(buffer, BAD_CAST ":", 1);
6345	}
6346        xmlBufferAdd(buffer, node->name, xmlStrlen(node->name));
6347        xmlBufferAdd(buffer, BAD_CAST "=\"", 2);
6348        domAttrSerializeContent(buffer, node);
6349        xmlBufferAdd(buffer, BAD_CAST "\"", 1);
6350
6351        if ( xmlBufferLength(buffer) > 0 ) {
6352            ret = xmlBufferContent( buffer );
6353        }
6354        if ( ret != NULL ) {
6355            if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
6356                RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(node))) ;
6357            }
6358            else {
6359                RETVAL = C2Sv((xmlChar*)ret, NULL) ;
6360            }
6361            xmlBufferFree( buffer );
6362        }
6363        else {
6364            xmlBufferFree( buffer );
6365            xs_warn("Failed to convert attribute to string");
6366            XSRETURN_UNDEF;
6367        }
6368    OUTPUT:
6369        RETVAL
6370
6371
6372int
6373_setNamespace(self, namespaceURI, namespacePrefix = &PL_sv_undef )
6374        SV * self
6375        SV * namespaceURI
6376        SV * namespacePrefix
6377    PREINIT:
6378        xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
6379        xmlChar * nsURI = nodeSv2C(namespaceURI,(xmlNodePtr)node);
6380        xmlChar * nsPrefix = NULL;
6381        xmlNsPtr ns = NULL;
6382    INIT:
6383        if ( node == NULL ) {
6384            croak( "lost node" );
6385        }
6386    CODE:
6387        if ( !nsURI || xmlStrlen(nsURI)==0 ){
6388	    xmlSetNs((xmlNodePtr)node, NULL);
6389            RETVAL = 1;
6390        }
6391        if ( !node->parent ) {
6392            XSRETURN_UNDEF;
6393        }
6394        nsPrefix = nodeSv2C(namespacePrefix, (xmlNodePtr)node);
6395        if ( (ns = xmlSearchNs(node->doc, node->parent, nsPrefix)) &&
6396             xmlStrEqual( ns->href, nsURI) ) {
6397	    /* same uri and prefix */
6398	    RETVAL = 1;
6399	}
6400	else if ( (ns = xmlSearchNsByHref(node->doc, node->parent, nsURI)) ) {
6401	    /* set uri, but with a different prefix */
6402            RETVAL = 1;
6403	}
6404        else
6405            RETVAL = 0;
6406
6407        if ( ns ) {
6408	    if ( ns->prefix ) {
6409		xmlSetNs((xmlNodePtr)node, ns);
6410	    } else {
6411                RETVAL = 0;
6412	    }
6413	}
6414        xmlFree(nsPrefix);
6415        xmlFree(nsURI);
6416    OUTPUT:
6417        RETVAL
6418
6419int
6420isId( self )
6421        SV * self
6422    PREINIT:
6423        xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode(self);
6424	xmlNodePtr elem;
6425    CODE:
6426        if ( attr == NULL ) {
6427          XSRETURN_UNDEF;
6428        }
6429	elem = attr->parent;
6430	if ( elem == NULL || elem->doc == NULL ) {
6431	  XSRETURN_UNDEF;
6432        }
6433        RETVAL = xmlIsID( elem->doc, elem, attr );
6434    OUTPUT:
6435        RETVAL
6436
6437MODULE = XML::LibXML         PACKAGE = XML::LibXML::Namespace
6438
6439SV*
6440new(CLASS, namespaceURI, namespacePrefix=&PL_sv_undef)
6441        const char * CLASS
6442        SV * namespaceURI
6443        SV * namespacePrefix
6444    PREINIT:
6445        xmlNsPtr ns = NULL;
6446        xmlChar* nsURI;
6447        xmlChar* nsPrefix;
6448    CODE:
6449        RETVAL = &PL_sv_undef;
6450
6451        nsURI = Sv2C(namespaceURI,NULL);
6452        if ( !nsURI ) {
6453            XSRETURN_UNDEF;
6454        }
6455        nsPrefix = Sv2C(namespacePrefix, NULL);
6456        ns = xmlNewNs(NULL, nsURI, nsPrefix);
6457        if ( ns ) {
6458            RETVAL = sv_newmortal();
6459            RETVAL = sv_setref_pv( RETVAL,
6460                                   CLASS,
6461                                   (void*)ns);
6462	}
6463        xmlFree(nsURI);
6464        if ( nsPrefix )
6465            xmlFree(nsPrefix);
6466    OUTPUT:
6467        RETVAL
6468
6469void
6470DESTROY(self)
6471        SV * self
6472    PREINIT:
6473        xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
6474    CODE:
6475        xs_warn( "DESTROY NS" );
6476        if (ns) {
6477            xmlFreeNs(ns);
6478        }
6479
6480int
6481nodeType(self)
6482        SV * self
6483    ALIAS:
6484        getType = 1
6485    PREINIT:
6486        xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
6487    CODE:
6488        RETVAL = ns->type;
6489    OUTPUT:
6490        RETVAL
6491
6492SV*
6493declaredURI(self)
6494        SV * self
6495    ALIAS:
6496        value = 1
6497        nodeValue = 2
6498        getData = 3
6499        getValue = 4
6500        value = 5
6501	href = 6
6502    PREINIT:
6503        xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
6504        xmlChar * href;
6505    CODE:
6506        href = xmlStrdup(ns->href);
6507        RETVAL = C2Sv(href, NULL);
6508        xmlFree(href);
6509    OUTPUT:
6510        RETVAL
6511
6512SV*
6513declaredPrefix(self)
6514        SV * self
6515    ALIAS:
6516	localname = 1
6517        getLocalName = 2
6518    PREINIT:
6519        xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
6520        xmlChar * prefix;
6521    CODE:
6522        prefix = xmlStrdup(ns->prefix);
6523        RETVAL = C2Sv(prefix, NULL);
6524        xmlFree(prefix);
6525    OUTPUT:
6526        RETVAL
6527
6528int
6529_isEqual(self, ref)
6530       SV * self
6531       SV * ref
6532    PREINIT:
6533       xmlNsPtr ns  = (xmlNsPtr)SvIV(SvRV(self));
6534       xmlNsPtr ons = (xmlNsPtr)SvIV(SvRV(ref));
6535    CODE:
6536       RETVAL = 0;
6537       if ( ns == ons ) {
6538           RETVAL = 1;
6539       }
6540       else if ( xmlStrEqual(ns->href, ons->href)
6541            && xmlStrEqual(ns->prefix, ons->prefix) ) {
6542           RETVAL = 1;
6543       }
6544    OUTPUT:
6545       RETVAL
6546
6547
6548MODULE = XML::LibXML         PACKAGE = XML::LibXML::Dtd
6549
6550SV *
6551new(CLASS, external, system)
6552        char * CLASS
6553        char * external
6554        char * system
6555    ALIAS:
6556        parse_uri = 1
6557    PREINIT:
6558        SV * saved_error = sv_2mortal(newSVpv("",0));
6559        xmlDtdPtr dtd = NULL;
6560    CODE:
6561        LibXML_init_error_ctx(saved_error);
6562        dtd = xmlParseDTD((const xmlChar*)external, (const xmlChar*)system);
6563        if ( dtd == NULL ) {
6564            LibXML_report_error_ctx(saved_error, 0);
6565            XSRETURN_UNDEF;
6566        } else {
6567            xmlSetTreeDoc((xmlNodePtr)dtd, NULL);
6568            RETVAL = PmmNodeToSv( (xmlNodePtr) dtd, NULL );
6569            LibXML_report_error_ctx(saved_error, 0);
6570        }
6571    OUTPUT:
6572        RETVAL
6573
6574SV*
6575systemId( self )
6576        xmlDtdPtr self
6577    ALIAS:
6578        getSystemId = 1
6579    CODE:
6580	if ( self->SystemID == NULL ) {
6581            XSRETURN_UNDEF;
6582	} else {
6583            RETVAL = C2Sv(self->SystemID,NULL);
6584	}
6585    OUTPUT:
6586        RETVAL
6587
6588SV*
6589publicId( self )
6590        xmlDtdPtr self
6591    ALIAS:
6592        getPublicId = 1
6593    CODE:
6594	if ( self->ExternalID == NULL ) {
6595            XSRETURN_UNDEF;
6596	} else {
6597            RETVAL = C2Sv(self->ExternalID,NULL);
6598	}
6599    OUTPUT:
6600        RETVAL
6601
6602void
6603DESTROY( node )
6604        SV * node
6605    CODE:
6606        xs_warn("DESTROY DTD NODE\n");
6607        PmmREFCNT_dec(SvPROXYNODE(node));
6608
6609SV *
6610parse_string(CLASS, str, ...)
6611        char * CLASS
6612        char * str
6613    PREINIT:
6614        SV * saved_error = sv_2mortal(newSVpv("",0));
6615        xmlDtdPtr res;
6616        SV * encoding_sv;
6617        xmlParserInputBufferPtr buffer;
6618        xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
6619        xmlChar * new_string;
6620    CODE:
6621        LibXML_init_error_ctx(saved_error);
6622        if (items > 2) {
6623            encoding_sv = ST(2);
6624            if (items > 3) {
6625                croak("parse_string: too many parameters");
6626            }
6627            /* warn("getting encoding...\n"); */
6628            enc = xmlParseCharEncoding(SvPV_nolen(encoding_sv));
6629            if (enc == XML_CHAR_ENCODING_ERROR) {
6630                LibXML_report_error_ctx(saved_error, 1);
6631                croak("Parse of encoding %s failed", SvPV_nolen(encoding_sv));
6632            }
6633        }
6634        buffer = xmlAllocParserInputBuffer(enc);
6635        /* buffer = xmlParserInputBufferCreateMem(str, xmlStrlen(str), enc); */
6636        if ( !buffer)
6637            croak("cannot create buffer!\n" );
6638
6639        new_string = xmlStrdup((const xmlChar*)str);
6640        xmlParserInputBufferPush(buffer, xmlStrlen(new_string), (const char*)new_string);
6641
6642        res = xmlIOParseDTD(NULL, buffer, enc);
6643
6644        /* NOTE: xmlIOParseDTD is documented to free its InputBuffer */
6645        xmlFree(new_string);
6646        if ( res && LibXML_will_die_ctx(saved_error, 0) )
6647	    xmlFreeDtd( res );
6648        LibXML_report_error_ctx(saved_error, 0);
6649        if (res == NULL) {
6650            croak("no DTD parsed!");
6651        }
6652        RETVAL = PmmNodeToSv((xmlNodePtr)res, NULL);
6653    OUTPUT:
6654        RETVAL
6655
6656
6657#ifdef HAVE_SCHEMAS
6658
6659MODULE = XML::LibXML         PACKAGE = XML::LibXML::RelaxNG
6660
6661void
6662DESTROY( self )
6663        xmlRelaxNGPtr self
6664    CODE:
6665        xmlRelaxNGFree( self );
6666
6667
6668xmlRelaxNGPtr
6669parse_location( self, url )
6670        SV * self
6671        char * url
6672    PREINIT:
6673        SV * saved_error = sv_2mortal(newSVpv("",0));
6674        const char * CLASS = "XML::LibXML::RelaxNG";
6675        xmlRelaxNGParserCtxtPtr rngctxt = NULL;
6676    CODE:
6677        LibXML_init_error_ctx(saved_error);
6678
6679        rngctxt = xmlRelaxNGNewParserCtxt( url );
6680        if ( rngctxt == NULL ) {
6681            croak( "failed to initialize RelaxNG parser" );
6682        }
6683
6684        /* Register Error callbacks */
6685        xmlRelaxNGSetParserErrors( rngctxt,
6686                                  (xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
6687                                  (xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
6688                                  saved_error );
6689
6690        RETVAL = xmlRelaxNGParse( rngctxt );
6691        xmlRelaxNGFreeParserCtxt( rngctxt );
6692
6693        LibXML_report_error_ctx(saved_error, (RETVAL != NULL));
6694    OUTPUT:
6695        RETVAL
6696
6697
6698xmlRelaxNGPtr
6699parse_buffer( self, perlstring )
6700        SV * self
6701        SV * perlstring
6702    PREINIT:
6703        SV * saved_error = sv_2mortal(newSVpv("",0));
6704        const char * CLASS = "XML::LibXML::RelaxNG";
6705        xmlRelaxNGParserCtxtPtr rngctxt = NULL;
6706        char * string = NULL;
6707        STRLEN len    = 0;
6708    INIT:
6709        string = SvPV( perlstring, len );
6710        if ( string == NULL ) {
6711            croak( "cannot parse empty string" );
6712        }
6713    CODE:
6714        LibXML_init_error_ctx(saved_error);
6715
6716        rngctxt = xmlRelaxNGNewMemParserCtxt( string,len );
6717        if ( rngctxt == NULL ) {
6718            croak( "failed to initialize RelaxNG parser" );
6719        }
6720
6721        /* Register Error callbacks */
6722        xmlRelaxNGSetParserErrors( rngctxt,
6723                                  (xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
6724                                  (xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
6725                                  saved_error );
6726
6727        RETVAL = xmlRelaxNGParse( rngctxt );
6728        xmlRelaxNGFreeParserCtxt( rngctxt );
6729
6730        LibXML_report_error_ctx(saved_error, (RETVAL != NULL));
6731    OUTPUT:
6732        RETVAL
6733
6734
6735xmlRelaxNGPtr
6736parse_document( self, doc )
6737        SV * self
6738        xmlDocPtr doc
6739    PREINIT:
6740        SV * saved_error = sv_2mortal(newSVpv("",0));
6741        const char * CLASS = "XML::LibXML::RelaxNG";
6742        xmlRelaxNGParserCtxtPtr rngctxt = NULL;
6743    CODE:
6744        LibXML_init_error_ctx(saved_error);
6745
6746        rngctxt = xmlRelaxNGNewDocParserCtxt( doc );
6747        if ( rngctxt == NULL ) {
6748            croak( "failed to initialize RelaxNG parser" );
6749        }
6750
6751        /* Register Error callbacks */
6752        xmlRelaxNGSetParserErrors( rngctxt,
6753                                  (xmlRelaxNGValidityErrorFunc)  LibXML_error_handler_ctx,
6754                                  (xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
6755                                  saved_error );
6756
6757        RETVAL = xmlRelaxNGParse( rngctxt );
6758        xmlRelaxNGFreeParserCtxt( rngctxt );
6759
6760        LibXML_report_error_ctx(saved_error, (RETVAL != NULL));
6761    OUTPUT:
6762        RETVAL
6763
6764int
6765validate( self, doc )
6766        xmlRelaxNGPtr self
6767        xmlDocPtr doc
6768    PREINIT:
6769        SV * saved_error = sv_2mortal(newSVpv("",0));
6770        xmlRelaxNGValidCtxtPtr vctxt = NULL;
6771    CODE:
6772        LibXML_init_error_ctx(saved_error);
6773
6774        vctxt  = xmlRelaxNGNewValidCtxt( self );
6775        if ( vctxt == NULL ) {
6776            croak( "cannot initialize the validation context" );
6777        }
6778
6779        /* Register Error callbacks */
6780        xmlRelaxNGSetValidErrors( vctxt,
6781                                  (xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
6782                                  (xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
6783                                  saved_error );
6784	/* ** test only **
6785          xmlRelaxNGSetValidErrors( vctxt,
6786                                    (xmlRelaxNGValidityErrorFunc)fprintf,
6787                                    (xmlRelaxNGValidityWarningFunc)fprintf,
6788                                    stderr );
6789	*/
6790        RETVAL = xmlRelaxNGValidateDoc( vctxt, doc );
6791        xmlRelaxNGFreeValidCtxt( vctxt );
6792
6793        LibXML_report_error_ctx(saved_error, 0);
6794        if ( RETVAL == 1 ) {
6795            XSRETURN_UNDEF;
6796        }
6797        if ( RETVAL == -1 ) {
6798            croak( "API Error" );
6799            XSRETURN_UNDEF;
6800        }
6801    OUTPUT:
6802        RETVAL
6803
6804
6805MODULE = XML::LibXML         PACKAGE = XML::LibXML::Schema
6806
6807void
6808DESTROY( self )
6809        xmlSchemaPtr self
6810    CODE:
6811        xmlSchemaFree( self );
6812
6813
6814xmlSchemaPtr
6815parse_location( self, url )
6816        SV * self
6817        char * url
6818    PREINIT:
6819        SV * saved_error = sv_2mortal(newSVpv("",0));
6820        const char * CLASS = "XML::LibXML::Schema";
6821        xmlSchemaParserCtxtPtr rngctxt = NULL;
6822    CODE:
6823        LibXML_init_error_ctx(saved_error);
6824
6825        rngctxt = xmlSchemaNewParserCtxt( url );
6826        if ( rngctxt == NULL ) {
6827            croak( "failed to initialize Schema parser" );
6828        }
6829
6830        /* Register Error callbacks */
6831        xmlSchemaSetParserErrors( rngctxt,
6832                                  (xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
6833                                  (xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
6834                                  saved_error );
6835
6836        RETVAL = xmlSchemaParse( rngctxt );
6837        xmlSchemaFreeParserCtxt( rngctxt );
6838
6839        LibXML_report_error_ctx(saved_error, (RETVAL != NULL));
6840    OUTPUT:
6841        RETVAL
6842
6843
6844xmlSchemaPtr
6845parse_buffer( self, perlstring )
6846        SV * self
6847        SV * perlstring
6848    PREINIT:
6849        SV * saved_error = sv_2mortal(newSVpv("",0));
6850        const char * CLASS = "XML::LibXML::Schema";
6851        xmlSchemaParserCtxtPtr rngctxt = NULL;
6852        char * string = NULL;
6853        STRLEN len    = 0;
6854    INIT:
6855        string = SvPV( perlstring, len );
6856        if ( string == NULL ) {
6857            croak( "cannot parse empty string" );
6858        }
6859    CODE:
6860        LibXML_init_error_ctx(saved_error);
6861
6862        rngctxt = xmlSchemaNewMemParserCtxt( string,len );
6863        if ( rngctxt == NULL ) {
6864            croak( "failed to initialize Schema parser" );
6865        }
6866
6867        /* Register Error callbacks */
6868        xmlSchemaSetParserErrors( rngctxt,
6869                                  (xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
6870                                  (xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
6871                                  saved_error );
6872
6873        RETVAL = xmlSchemaParse( rngctxt );
6874        xmlSchemaFreeParserCtxt( rngctxt );
6875
6876        LibXML_report_error_ctx(saved_error, (RETVAL != NULL));
6877    OUTPUT:
6878        RETVAL
6879
6880
6881int
6882validate( self, doc )
6883        xmlSchemaPtr self
6884        xmlDocPtr doc
6885    PREINIT:
6886        SV * saved_error = sv_2mortal(newSVpv("",0));
6887        xmlSchemaValidCtxtPtr vctxt = NULL;
6888    CODE:
6889        LibXML_init_error_ctx(saved_error);
6890
6891        vctxt  = xmlSchemaNewValidCtxt( self );
6892        if ( vctxt == NULL ) {
6893            croak( "cannot initialize the validation context" );
6894        }
6895
6896        /* Register Error callbacks */
6897        xmlSchemaSetValidErrors( vctxt,
6898                                  (xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
6899                                  (xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
6900                                  saved_error );
6901
6902        RETVAL = xmlSchemaValidateDoc( vctxt, doc );
6903        xmlSchemaFreeValidCtxt( vctxt );
6904
6905        LibXML_report_error_ctx(saved_error, 0);
6906        if ( RETVAL > 0 ) {
6907            XSRETURN_UNDEF;
6908        }
6909        if ( RETVAL == -1 ) {
6910            croak( "API Error" );
6911            XSRETURN_UNDEF;
6912        }
6913    OUTPUT:
6914        RETVAL
6915
6916#endif /* HAVE_SCHEMAS */
6917
6918MODULE = XML::LibXML::XPathContext     PACKAGE = XML::LibXML::XPathContext
6919
6920# PROTOTYPES: DISABLE
6921
6922SV*
6923new( CLASS, ... )
6924        const char * CLASS
6925    PREINIT:
6926        SV * pnode = &PL_sv_undef;
6927    INIT:
6928        xmlXPathContextPtr ctxt;
6929    CODE:
6930        if( items > 1 )
6931            pnode = ST(1);
6932
6933        ctxt = xmlXPathNewContext( NULL );
6934        ctxt->namespaces = NULL;
6935
6936        New(0, ctxt->user, sizeof(XPathContextData), XPathContextData);
6937        if (ctxt->user == NULL) {
6938            croak("XPathContext: failed to allocate proxy object\n");
6939        }
6940
6941        if (SvOK(pnode)) {
6942          XPathContextDATA(ctxt)->node = newSVsv(pnode);
6943        } else {
6944          XPathContextDATA(ctxt)->node = &PL_sv_undef;
6945        }
6946
6947        XPathContextDATA(ctxt)->pool = NULL;
6948        XPathContextDATA(ctxt)->varLookup = NULL;
6949        XPathContextDATA(ctxt)->varData = NULL;
6950
6951        xmlXPathRegisterFunc(ctxt,
6952                             (const xmlChar *) "document",
6953                             perlDocumentFunction);
6954
6955        RETVAL = NEWSV(0,0),
6956        RETVAL = sv_setref_pv( RETVAL,
6957                               CLASS,
6958                               (void*)ctxt );
6959    OUTPUT:
6960        RETVAL
6961
6962void
6963DESTROY( self )
6964        SV * self
6965    INIT:
6966        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
6967    CODE:
6968        xs_warn( "DESTROY XPATH CONTEXT" );
6969        if (ctxt) {
6970            if (XPathContextDATA(ctxt) != NULL) {
6971                if (XPathContextDATA(ctxt)->node != NULL &&
6972                    SvOK(XPathContextDATA(ctxt)->node)) {
6973                    SvREFCNT_dec(XPathContextDATA(ctxt)->node);
6974                }
6975                if (XPathContextDATA(ctxt)->varLookup != NULL &&
6976                    SvOK(XPathContextDATA(ctxt)->varLookup)) {
6977                    SvREFCNT_dec(XPathContextDATA(ctxt)->varLookup);
6978                }
6979                if (XPathContextDATA(ctxt)->varData != NULL &&
6980                    SvOK(XPathContextDATA(ctxt)->varData)) {
6981                    SvREFCNT_dec(XPathContextDATA(ctxt)->varData);
6982                }
6983                if (XPathContextDATA(ctxt)->pool != NULL &&
6984                    SvOK(XPathContextDATA(ctxt)->pool)) {
6985                    SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
6986                }
6987                Safefree(XPathContextDATA(ctxt));
6988            }
6989
6990            if (ctxt->namespaces != NULL) {
6991                xmlFree( ctxt->namespaces );
6992            }
6993            if (ctxt->funcLookupData != NULL && SvROK((SV*)ctxt->funcLookupData)
6994                && SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
6995                SvREFCNT_dec((SV *)ctxt->funcLookupData);
6996            }
6997
6998            xmlXPathFreeContext(ctxt);
6999        }
7000
7001SV*
7002getContextNode( self )
7003        SV * self
7004    INIT:
7005        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7006        if ( ctxt == NULL ) {
7007            croak("XPathContext: missing xpath context\n");
7008        }
7009    CODE:
7010        if(XPathContextDATA(ctxt)->node != NULL) {
7011            RETVAL = newSVsv(XPathContextDATA(ctxt)->node);
7012        } else {
7013            RETVAL = &PL_sv_undef;
7014        }
7015    OUTPUT:
7016        RETVAL
7017
7018int
7019getContextPosition( self )
7020        SV * self
7021    INIT:
7022        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7023        if ( ctxt == NULL ) {
7024            croak("XPathContext: missing xpath context\n");
7025        }
7026    CODE:
7027        RETVAL = ctxt->proximityPosition;
7028    OUTPUT:
7029	RETVAL
7030
7031int
7032getContextSize( self )
7033        SV * self
7034    INIT:
7035        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7036        if ( ctxt == NULL ) {
7037            croak("XPathContext: missing xpath context\n");
7038        }
7039    CODE:
7040        RETVAL = ctxt->contextSize;
7041    OUTPUT:
7042	RETVAL
7043
7044void
7045setContextNode( self , pnode )
7046        SV * self
7047        SV * pnode
7048    INIT:
7049        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7050        if ( ctxt == NULL ) {
7051            croak("XPathContext: missing xpath context\n");
7052        }
7053    PPCODE:
7054        if (XPathContextDATA(ctxt)->node != NULL) {
7055            SvREFCNT_dec(XPathContextDATA(ctxt)->node);
7056        }
7057        if (SvOK(pnode)) {
7058            XPathContextDATA(ctxt)->node = newSVsv(pnode);
7059        } else {
7060            XPathContextDATA(ctxt)->node = NULL;
7061        }
7062
7063void
7064setContextPosition( self , position )
7065        SV * self
7066        int position
7067    INIT:
7068        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7069        if ( ctxt == NULL )
7070            croak("XPathContext: missing xpath context\n");
7071        if ( position < -1 || position > ctxt->contextSize )
7072	    croak("XPathContext: invalid position\n");
7073    PPCODE:
7074        ctxt->proximityPosition = position;
7075
7076void
7077setContextSize( self , size )
7078        SV * self
7079        int size
7080    INIT:
7081        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7082        if ( ctxt == NULL )
7083            croak("XPathContext: missing xpath context\n");
7084        if ( size < -1 )
7085	    croak("XPathContext: invalid size\n");
7086    PPCODE:
7087        ctxt->contextSize = size;
7088        if ( size == 0 )
7089	    ctxt->proximityPosition = 0;
7090	else if ( size > 0 )
7091	    ctxt->proximityPosition = 1;
7092        else
7093	    ctxt->proximityPosition = -1;
7094
7095void
7096registerNs( pxpath_context, prefix, ns_uri )
7097        SV * pxpath_context
7098        SV * prefix
7099        SV * ns_uri
7100    PREINIT:
7101        xmlXPathContextPtr ctxt = NULL;
7102    INIT:
7103        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7104        if ( ctxt == NULL ) {
7105            croak("XPathContext: missing xpath context\n");
7106        }
7107        LibXML_configure_xpathcontext(ctxt);
7108    PPCODE:
7109        if(SvOK(ns_uri)) {
7110	    if(xmlXPathRegisterNs(ctxt, (xmlChar *) SvPV_nolen(prefix),
7111                                  (xmlChar *) SvPV_nolen(ns_uri)) == -1) {
7112                croak("XPathContext: cannot register namespace\n");
7113            }
7114        } else {
7115	    if(xmlXPathRegisterNs(ctxt, (xmlChar *) SvPV_nolen(prefix), NULL) == -1) {
7116                croak("XPathContext: cannot unregister namespace\n");
7117            }
7118        }
7119
7120SV*
7121lookupNs( pxpath_context, prefix )
7122        SV * pxpath_context
7123        SV * prefix
7124    PREINIT:
7125        xmlXPathContextPtr ctxt = NULL;
7126    INIT:
7127        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7128        if ( ctxt == NULL ) {
7129            croak("XPathContext: missing xpath context\n");
7130        }
7131        LibXML_configure_xpathcontext(ctxt);
7132    CODE:
7133        RETVAL = C2Sv(xmlXPathNsLookup(ctxt, (xmlChar *) SvPV_nolen(prefix)), NULL);
7134    OUTPUT:
7135        RETVAL
7136
7137SV*
7138getVarLookupData( self )
7139        SV * self
7140    INIT:
7141        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7142        if ( ctxt == NULL ) {
7143            croak("XPathContext: missing xpath context\n");
7144        }
7145    CODE:
7146        if(XPathContextDATA(ctxt)->varData != NULL) {
7147            RETVAL = newSVsv(XPathContextDATA(ctxt)->varData);
7148        } else {
7149            RETVAL = &PL_sv_undef;
7150        }
7151    OUTPUT:
7152        RETVAL
7153
7154SV*
7155getVarLookupFunc( self )
7156        SV * self
7157    INIT:
7158        xmlXPathContextPtr ctxt = (xmlXPathContextPtr)SvIV(SvRV(self));
7159        if ( ctxt == NULL ) {
7160            croak("XPathContext: missing xpath context\n");
7161        }
7162    CODE:
7163        if(XPathContextDATA(ctxt)->varData != NULL) {
7164            RETVAL = newSVsv(XPathContextDATA(ctxt)->varLookup);
7165        } else {
7166            RETVAL = &PL_sv_undef;
7167        }
7168    OUTPUT:
7169        RETVAL
7170
7171void
7172registerVarLookupFunc( pxpath_context, lookup_func, lookup_data )
7173        SV * pxpath_context
7174        SV * lookup_func
7175        SV * lookup_data
7176    PREINIT:
7177        xmlXPathContextPtr ctxt = NULL;
7178        XPathContextDataPtr data = NULL;
7179    INIT:
7180        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7181        if ( ctxt == NULL )
7182            croak("XPathContext: missing xpath context\n");
7183        data = XPathContextDATA(ctxt);
7184        if ( data == NULL )
7185            croak("XPathContext: missing xpath context private data\n");
7186        LibXML_configure_xpathcontext(ctxt);
7187        /* free previous lookup function and data */
7188        if (data->varLookup && SvOK(data->varLookup))
7189            SvREFCNT_dec(data->varLookup);
7190        if (data->varData && SvOK(data->varData))
7191            SvREFCNT_dec(data->varData);
7192        data->varLookup=NULL;
7193        data->varData=NULL;
7194    PPCODE:
7195        if (SvOK(lookup_func)) {
7196            if ( SvROK(lookup_func) && SvTYPE(SvRV(lookup_func)) == SVt_PVCV ) {
7197		data->varLookup = newSVsv(lookup_func);
7198		if (SvOK(lookup_data))
7199		    data->varData = newSVsv(lookup_data);
7200		xmlXPathRegisterVariableLookup(ctxt,
7201					       LibXML_generic_variable_lookup, ctxt);
7202		if (ctxt->varLookupData==NULL || ctxt->varLookupData != ctxt) {
7203		    croak( "XPathContext: registration failure\n" );
7204		}
7205            } else {
7206                croak("XPathContext: 1st argument is not a CODE reference\n");
7207            }
7208        } else {
7209            /* unregister */
7210            xmlXPathRegisterVariableLookup(ctxt, NULL, NULL);
7211        }
7212
7213void
7214registerFunctionNS( pxpath_context, name, uri, func)
7215        SV * pxpath_context
7216        char * name
7217        SV * uri
7218        SV * func
7219    PREINIT:
7220        xmlXPathContextPtr ctxt = NULL;
7221        SV * pfdr;
7222        SV * key;
7223        STRLEN len;
7224        char *strkey;
7225
7226    INIT:
7227        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7228        if ( ctxt == NULL ) {
7229            croak("XPathContext: missing xpath context\n");
7230        }
7231        LibXML_configure_xpathcontext(ctxt);
7232        if ( !SvOK(func) ||
7233             (SvOK(func) && ((SvROK(func) && SvTYPE(SvRV(func)) == SVt_PVCV )
7234                || SvPOK(func)))) {
7235            if (ctxt->funcLookupData == NULL) {
7236                if (SvOK(func)) {
7237                    pfdr = newRV_inc((SV*) newHV());
7238                    ctxt->funcLookupData = pfdr;
7239                } else {
7240                    /* looks like no perl function was never registered, */
7241                    /* nothing to unregister */
7242                    warn("XPathContext: nothing to unregister\n");
7243                    return;
7244                }
7245            } else {
7246                if (SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
7247                    /* good, it's a HV */
7248                    pfdr = (SV *)ctxt->funcLookupData;
7249                } else {
7250                    croak ("XPathContext: cannot register: funcLookupData structure occupied\n");
7251                }
7252            }
7253            key = newSVpvn("",0);
7254            if (SvOK(uri)) {
7255                sv_catpv(key, "{");
7256                sv_catsv(key, uri);
7257                sv_catpv(key, "}");
7258            }
7259            sv_catpv(key, (const char*)name);
7260            strkey = SvPV(key, len);
7261            /* warn("Trying to store function '%s' in %d\n", strkey, pfdr); */
7262            if (SvOK(func)) {
7263                hv_store((HV *)SvRV(pfdr),strkey, len, newSVsv(func), 0);
7264            } else {
7265                /* unregister */
7266                hv_delete((HV *)SvRV(pfdr),strkey, len, G_DISCARD);
7267            }
7268            SvREFCNT_dec(key);
7269        } else {
7270            croak("XPathContext: 3rd argument is not a CODE reference or function name\n");
7271        }
7272    PPCODE:
7273        if (SvOK(uri)) {
7274	    xmlXPathRegisterFuncNS(ctxt, (xmlChar *) name,
7275                                   (xmlChar *) SvPV(uri, len),
7276                                    (SvOK(func) ?
7277                                    LibXML_generic_extension_function : NULL));
7278        } else {
7279            xmlXPathRegisterFunc(ctxt, (xmlChar *) name,
7280                                 (SvOK(func) ?
7281                                 LibXML_generic_extension_function : NULL));
7282        }
7283
7284void
7285_free_node_pool( pxpath_context )
7286        SV * pxpath_context
7287    PREINIT:
7288        xmlXPathContextPtr ctxt = NULL;
7289    INIT:
7290        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7291        if ( ctxt == NULL ) {
7292            croak("XPathContext: missing xpath context\n");
7293        }
7294    PPCODE:
7295        if (XPathContextDATA(ctxt)->pool != NULL) {
7296            SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
7297            XPathContextDATA(ctxt)->pool = NULL;
7298        }
7299
7300void
7301_findnodes( pxpath_context, perl_xpath )
7302        SV * pxpath_context
7303        SV * perl_xpath
7304        SV * saved_error = sv_2mortal(newSVpv("",0));
7305    PREINIT:
7306        xmlXPathContextPtr ctxt = NULL;
7307        ProxyNodePtr owner = NULL;
7308        xmlXPathObjectPtr found = NULL;
7309        xmlNodeSetPtr nodelist = NULL;
7310        SV * element = NULL ;
7311        STRLEN len = 0 ;
7312        xmlChar * xpath = NULL;
7313    INIT:
7314        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7315        if ( ctxt == NULL ) {
7316            croak("XPathContext: missing xpath context\n");
7317        }
7318        LibXML_configure_xpathcontext(ctxt);
7319        if ( ctxt->node == NULL ) {
7320            croak("XPathContext: lost current node\n");
7321        }
7322        xpath = nodeSv2C(perl_xpath, ctxt->node);
7323        if ( !(xpath && xmlStrlen(xpath)) ) {
7324            if ( xpath )
7325                xmlFree(xpath);
7326            croak("XPathContext: empty XPath found\n");
7327            XSRETURN_UNDEF;
7328        }
7329    PPCODE:
7330        if ( ctxt->node->doc ) {
7331            domNodeNormalize( xmlDocGetRootElement(ctxt->node->doc) );
7332        }
7333        else {
7334            domNodeNormalize( PmmOWNER(PmmNewNode(ctxt->node)) );
7335        }
7336
7337        LibXML_init_error_ctx(saved_error);
7338
7339        PUTBACK ;
7340        found = domXPathFindCtxt( ctxt, xpath );
7341        SPAGAIN ;
7342
7343        if (found != NULL) {
7344          nodelist = found->nodesetval;
7345        } else {
7346          nodelist = NULL;
7347        }
7348        xmlFree(xpath);
7349
7350        if ( nodelist ) {
7351            if ( nodelist->nodeNr > 0 ) {
7352                int i;
7353                const char * cls = "XML::LibXML::Node";
7354                xmlNodePtr tnode;
7355                len = nodelist->nodeNr;
7356                for( i = 0  ; i < len; i++){
7357                    /* we have to create a new instance of an objectptr.
7358                     * and then place the current node into the new object.
7359                     * afterwards we can push the object to the array!
7360                     */
7361                    element = NULL;
7362                    tnode = nodelist->nodeTab[i];
7363                    if (tnode->type == XML_NAMESPACE_DECL) {
7364                        xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
7365                        if ( newns != NULL ) {
7366                            element = NEWSV(0,0);
7367                            cls = PmmNodeTypeName( tnode );
7368                            element = sv_setref_pv( element,
7369                                                    (const char *)cls,
7370                                                    newns
7371                                                  );
7372                        }
7373                        else {
7374                            continue;
7375                        }
7376                    }
7377                    else {
7378                        if (tnode->doc) {
7379                            owner = PmmOWNERPO(PmmNewNode((xmlNodePtr) tnode->doc));
7380                        } else {
7381                            owner = NULL; /* self contained node */
7382                        }
7383                        element = PmmNodeToSv(tnode, owner);
7384                    }
7385                    XPUSHs( sv_2mortal(element) );
7386                }
7387            }
7388            /* prevent libxml2 from freeing the actual nodes */
7389            if (found->boolval) found->boolval=0;
7390            xmlXPathFreeObject(found);
7391	    LibXML_report_error_ctx(saved_error, 1);
7392        }
7393        else {
7394            xmlXPathFreeObject(found);
7395	    LibXML_report_error_ctx(saved_error, 0);
7396        }
7397
7398void
7399_find( pxpath_context, pxpath )
7400        SV * pxpath_context
7401        SV * pxpath
7402    PREINIT:
7403        xmlXPathContextPtr ctxt = NULL;
7404        ProxyNodePtr owner = NULL;
7405        xmlXPathObjectPtr found = NULL;
7406        xmlNodeSetPtr nodelist = NULL;
7407        STRLEN len = 0 ;
7408        xmlChar * xpath = NULL;
7409        SV * saved_error = sv_2mortal(newSVpv("",0));
7410    INIT:
7411        ctxt = (xmlXPathContextPtr)SvIV(SvRV(pxpath_context));
7412        if ( ctxt == NULL ) {
7413            croak("XPathContext: missing xpath context\n");
7414        }
7415        LibXML_configure_xpathcontext(ctxt);
7416        if ( ctxt->node == NULL ) {
7417            croak("XPathContext: lost current node\n");
7418        }
7419        xpath = nodeSv2C(pxpath, ctxt->node);
7420        if ( !(xpath && xmlStrlen(xpath)) ) {
7421            if ( xpath )
7422                xmlFree(xpath);
7423            croak("XPathContext: empty XPath found\n");
7424            XSRETURN_UNDEF;
7425        }
7426
7427    PPCODE:
7428        if ( ctxt->node->doc ) {
7429            domNodeNormalize( xmlDocGetRootElement( ctxt->node->doc ) );
7430        }
7431        else {
7432            domNodeNormalize( PmmOWNER(PmmNewNode(ctxt->node)) );
7433        }
7434
7435        LibXML_init_error_ctx(saved_error);
7436
7437        PUTBACK ;
7438        found = domXPathFindCtxt( ctxt, xpath );
7439        SPAGAIN ;
7440
7441        xmlFree( xpath );
7442
7443        if (found) {
7444            switch (found->type) {
7445                case XPATH_NODESET:
7446                    /* return as a NodeList */
7447                    /* access ->nodesetval */
7448                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
7449                    nodelist = found->nodesetval;
7450                    if ( nodelist ) {
7451                        if ( nodelist->nodeNr > 0 ) {
7452                            int i;
7453                            const char * cls = "XML::LibXML::Node";
7454                            xmlNodePtr tnode;
7455                            SV * element;
7456
7457                            len = nodelist->nodeNr;
7458                            for( i = 0 ; i < len; i++){
7459                                /* we have to create a new instance of an
7460                                 * objectptr. and then
7461                                 * place the current node into the new
7462                                 * object. afterwards we can
7463                                 * push the object to the array!
7464                                 */
7465                                tnode = nodelist->nodeTab[i];
7466
7467                                /* let's be paranoid */
7468                                if (tnode->type == XML_NAMESPACE_DECL) {
7469                                     xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
7470                                    if ( newns != NULL ) {
7471                                        element = NEWSV(0,0);
7472                                        cls = PmmNodeTypeName( tnode );
7473                                        element = sv_setref_pv( element,
7474                                                                (const char *)cls,
7475                                                                (void*)newns
7476                                                          );
7477                                    }
7478                                    else {
7479                                        continue;
7480                                    }
7481                                }
7482                                else {
7483                                    if (tnode->doc) {
7484                                        owner = PmmOWNERPO(PmmNewNode((xmlNodePtr) tnode->doc));
7485                                    } else {
7486                                        owner = NULL; /* self contained node */
7487                                    }
7488                                    element = PmmNodeToSv(tnode, owner);
7489                                }
7490                                XPUSHs( sv_2mortal(element) );
7491                            }
7492                        }
7493                    }
7494                    /* prevent libxml2 from freeing the actual nodes */
7495                    if (found->boolval) found->boolval=0;
7496                    break;
7497                case XPATH_BOOLEAN:
7498                    /* return as a Boolean */
7499                    /* access ->boolval */
7500                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
7501                    XPUSHs(sv_2mortal(newSViv(found->boolval)));
7502                    break;
7503                case XPATH_NUMBER:
7504                    /* return as a Number */
7505                    /* access ->floatval */
7506                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
7507                    XPUSHs(sv_2mortal(newSVnv(found->floatval)));
7508                    break;
7509                case XPATH_STRING:
7510                    /* access ->stringval */
7511                    /* return as a Literal */
7512                    XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
7513                    XPUSHs(sv_2mortal(C2Sv(found->stringval, NULL)));
7514                    break;
7515                default:
7516                    croak("Unknown XPath return type");
7517            }
7518            xmlXPathFreeObject(found);
7519	    LibXML_report_error_ctx(saved_error, 1);
7520        }
7521        else {
7522	    LibXML_report_error_ctx(saved_error, 0);
7523        }
7524
7525MODULE = XML::LibXML         PACKAGE = XML::LibXML::InputCallback
7526
7527void
7528lib_cleanup_callbacks( self )
7529        SV * self
7530    CODE:
7531        xmlCleanupInputCallbacks();
7532        xmlRegisterDefaultInputCallbacks();
7533
7534void
7535lib_init_callbacks( self )
7536        SV * self
7537    CODE:
7538        xmlRegisterDefaultInputCallbacks(); /* important */
7539        xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
7540                                  (xmlInputOpenCallback) LibXML_input_open,
7541                                  (xmlInputReadCallback) LibXML_input_read,
7542                                  (xmlInputCloseCallback) LibXML_input_close);
7543
7544#ifdef HAVE_READER_SUPPORT
7545
7546MODULE = XML::LibXML	PACKAGE = XML::LibXML::Reader
7547
7548xmlTextReaderPtr
7549_newForFile(CLASS, filename, encoding, options)
7550	const char* CLASS
7551	const char* filename
7552	const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7553	int options = SvOK($arg) ? SvIV($arg) : 0;
7554    CODE:
7555        RETVAL = xmlReaderForFile(filename, encoding, options);
7556        if (RETVAL) {
7557          xmlTextReaderSetErrorHandler(RETVAL, LibXML_reader_error_handler,newSVpv("",0));
7558        }
7559    OUTPUT:
7560	RETVAL
7561
7562xmlTextReaderPtr
7563_newForIO(CLASS, fh, url, encoding, options)
7564	const char* CLASS
7565	SV * fh
7566	const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7567	const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7568	int options = SvOK($arg) ? SvIV($arg) : 0;
7569    CODE:
7570        SvREFCNT_inc(fh); /* _dec'd by LibXML_close_perl */
7571        RETVAL = xmlReaderForIO((xmlInputReadCallback) LibXML_read_perl,
7572				(xmlInputCloseCallback) LibXML_close_perl,
7573				(void *) fh, url, encoding, options);
7574        if (RETVAL) {
7575	  xmlTextReaderSetErrorHandler(RETVAL, LibXML_reader_error_handler,newSVpv("",0));
7576        }
7577    OUTPUT:
7578	RETVAL
7579
7580xmlTextReaderPtr
7581_newForString(CLASS, string, url, encoding, options)
7582	const char* CLASS
7583	SV * string
7584	const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7585	const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7586	int options = SvOK($arg) ? SvIV($arg) : 0;
7587    CODE:
7588        if (encoding == NULL && SvUTF8( string )) {
7589	  encoding = "UTF-8";
7590        }
7591        RETVAL = xmlReaderForDoc((xmlChar* )SvPV_nolen(string), url, encoding, options);
7592        if (RETVAL) {
7593	  xmlTextReaderSetErrorHandler(RETVAL, LibXML_reader_error_handler,newSVpv("",0));
7594        }
7595    OUTPUT:
7596	RETVAL
7597
7598xmlTextReaderPtr
7599_newForFd(CLASS, fd, url, encoding, options)
7600	const char* CLASS
7601	int fd
7602	const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7603	const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7604	int options = SvOK($arg) ? SvIV($arg) : 0;
7605    CODE:
7606        RETVAL = xmlReaderForFd(fd, url, encoding, options);
7607        if (RETVAL) {
7608          xmlTextReaderSetErrorHandler(RETVAL, LibXML_reader_error_handler,newSVpv("",0));
7609        }
7610    OUTPUT:
7611	RETVAL
7612
7613xmlTextReaderPtr
7614_newForDOM(CLASS, perl_doc)
7615	const char* CLASS
7616	SV * perl_doc
7617    CODE:
7618        PmmREFCNT_inc(SvPROXYNODE(perl_doc)); /* _dec in DESTROY */
7619        RETVAL = xmlReaderWalker((xmlDocPtr) PmmSvNode(perl_doc));
7620    OUTPUT:
7621	RETVAL
7622
7623int
7624attributeCount(reader)
7625	xmlTextReaderPtr reader
7626    CODE:
7627	RETVAL = xmlTextReaderAttributeCount(reader);
7628    OUTPUT:
7629	RETVAL
7630
7631SV *
7632baseURI(reader)
7633	xmlTextReaderPtr reader
7634    PREINIT:
7635	const xmlChar *result = NULL;
7636    CODE:
7637	result = xmlTextReaderConstBaseUri(reader);
7638	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7639    OUTPUT:
7640	RETVAL
7641
7642int
7643byteConsumed(reader)
7644	xmlTextReaderPtr reader
7645    CODE:
7646	RETVAL = xmlTextReaderByteConsumed(reader);
7647    OUTPUT:
7648	RETVAL
7649
7650int
7651_close(reader)
7652	xmlTextReaderPtr reader
7653    CODE:
7654	RETVAL = xmlTextReaderClose(reader);
7655    OUTPUT:
7656	RETVAL
7657
7658SV *
7659encoding(reader)
7660	xmlTextReaderPtr reader
7661    PREINIT:
7662	const xmlChar *result = NULL;
7663    CODE:
7664	result = xmlTextReaderConstEncoding(reader);
7665	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7666    OUTPUT:
7667	RETVAL
7668
7669SV *
7670localName(reader)
7671	xmlTextReaderPtr reader
7672    PREINIT:
7673	const xmlChar *result = NULL;
7674    CODE:
7675	result = xmlTextReaderConstLocalName(reader);
7676	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7677    OUTPUT:
7678	RETVAL
7679
7680SV *
7681name(reader)
7682	xmlTextReaderPtr reader
7683    PREINIT:
7684	const xmlChar *result = NULL;
7685    CODE:
7686	result = xmlTextReaderConstName(reader);
7687	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7688    OUTPUT:
7689	RETVAL
7690
7691SV *
7692namespaceURI(reader)
7693	xmlTextReaderPtr reader
7694    PREINIT:
7695	const xmlChar *result = NULL;
7696    CODE:
7697	result = xmlTextReaderConstNamespaceUri(reader);
7698	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7699    OUTPUT:
7700	RETVAL
7701
7702SV *
7703prefix(reader)
7704	xmlTextReaderPtr reader
7705    PREINIT:
7706	const xmlChar *result = NULL;
7707    CODE:
7708	result = xmlTextReaderConstPrefix(reader);
7709	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7710    OUTPUT:
7711	RETVAL
7712
7713SV *
7714value(reader)
7715	xmlTextReaderPtr reader
7716    PREINIT:
7717	const xmlChar *result = NULL;
7718    CODE:
7719	result = xmlTextReaderConstValue(reader);
7720	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7721    OUTPUT:
7722	RETVAL
7723
7724SV *
7725xmlLang(reader)
7726	xmlTextReaderPtr reader
7727    PREINIT:
7728	const xmlChar *result = NULL;
7729    CODE:
7730	result = xmlTextReaderConstXmlLang(reader);
7731	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7732    OUTPUT:
7733	RETVAL
7734
7735
7736SV *
7737xmlVersion(reader)
7738	xmlTextReaderPtr reader
7739    PREINIT:
7740	const xmlChar *result = NULL;
7741    CODE:
7742	result = xmlTextReaderConstXmlVersion(reader);
7743	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7744    OUTPUT:
7745	RETVAL
7746
7747
7748int
7749depth(reader)
7750	xmlTextReaderPtr reader
7751    CODE:
7752	RETVAL = xmlTextReaderDepth(reader);
7753    OUTPUT:
7754	RETVAL
7755
7756
7757SV *
7758getAttribute(reader, name)
7759	xmlTextReaderPtr reader
7760	char * name
7761    PREINIT:
7762	xmlChar *result = NULL;
7763    CODE:
7764	result = xmlTextReaderGetAttribute(reader, (xmlChar*) name);
7765	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7766        xmlFree(result);
7767    OUTPUT:
7768	RETVAL
7769
7770SV *
7771getAttributeNo(reader, no)
7772	xmlTextReaderPtr reader
7773	int no
7774    PREINIT:
7775	xmlChar *result = NULL;
7776    CODE:
7777	result = xmlTextReaderGetAttributeNo(reader, no);
7778	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7779        xmlFree(result);
7780    OUTPUT:
7781	RETVAL
7782
7783SV *
7784getAttributeNs(reader, localName, namespaceURI)
7785	xmlTextReaderPtr reader
7786	char * localName
7787        char * namespaceURI = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7788    PREINIT:
7789	xmlChar *result = NULL;
7790    CODE:
7791	result = xmlTextReaderGetAttributeNs(reader,  (xmlChar*) localName,
7792					     (xmlChar*) namespaceURI);
7793	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7794        xmlFree(result);
7795    OUTPUT:
7796	RETVAL
7797
7798int
7799columnNumber(reader)
7800	xmlTextReaderPtr reader
7801    CODE:
7802	RETVAL = xmlTextReaderGetParserColumnNumber(reader);
7803    OUTPUT:
7804	RETVAL
7805
7806int
7807lineNumber(reader)
7808	xmlTextReaderPtr reader
7809    CODE:
7810	RETVAL = xmlTextReaderGetParserLineNumber(reader);
7811    OUTPUT:
7812	RETVAL
7813
7814int
7815_getParserProp(reader, prop)
7816	xmlTextReaderPtr reader
7817	int prop
7818    CODE:
7819	RETVAL = xmlTextReaderGetParserProp(reader, prop);
7820    OUTPUT:
7821	RETVAL
7822
7823int
7824hasAttributes(reader)
7825	xmlTextReaderPtr reader
7826    CODE:
7827	RETVAL = xmlTextReaderHasAttributes(reader);
7828    OUTPUT:
7829	RETVAL
7830
7831int
7832hasValue(reader)
7833	xmlTextReaderPtr reader
7834    CODE:
7835	RETVAL = xmlTextReaderHasValue(reader);
7836    OUTPUT:
7837	RETVAL
7838
7839int
7840isDefault(reader)
7841	xmlTextReaderPtr reader
7842    CODE:
7843	RETVAL = xmlTextReaderIsDefault(reader);
7844    OUTPUT:
7845	RETVAL
7846
7847int
7848isEmptyElement(reader)
7849	xmlTextReaderPtr reader
7850    CODE:
7851	RETVAL = xmlTextReaderIsEmptyElement(reader);
7852    OUTPUT:
7853	RETVAL
7854
7855int
7856isNamespaceDecl(reader)
7857	xmlTextReaderPtr reader
7858    CODE:
7859	RETVAL = xmlTextReaderIsNamespaceDecl(reader);
7860    OUTPUT:
7861	RETVAL
7862
7863int
7864isValid(reader)
7865	xmlTextReaderPtr reader
7866    CODE:
7867	RETVAL = xmlTextReaderIsValid(reader);
7868    OUTPUT:
7869	RETVAL
7870
7871SV *
7872lookupNamespace(reader, prefix)
7873	xmlTextReaderPtr reader
7874	char * prefix = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7875    PREINIT:
7876	xmlChar *result = NULL;
7877    CODE:
7878	result = xmlTextReaderLookupNamespace(reader, (xmlChar*) prefix);
7879	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
7880        xmlFree(result);
7881    OUTPUT:
7882	RETVAL
7883
7884
7885int
7886moveToAttribute(reader, name)
7887	xmlTextReaderPtr reader
7888	char * name
7889    CODE:
7890	RETVAL = xmlTextReaderMoveToAttribute(reader, (xmlChar*) name);
7891    OUTPUT:
7892	RETVAL
7893
7894int
7895moveToAttributeNo(reader, no)
7896	xmlTextReaderPtr reader
7897	int no
7898    CODE:
7899	RETVAL = xmlTextReaderMoveToAttributeNo(reader, no);
7900    OUTPUT:
7901	RETVAL
7902
7903int
7904moveToAttributeNs(reader, localName, namespaceURI)
7905	xmlTextReaderPtr reader
7906	char * localName
7907	char * namespaceURI = SvOK($arg) ? SvPV_nolen($arg) : NULL;
7908    CODE:
7909	RETVAL = xmlTextReaderMoveToAttributeNs(reader,
7910						(xmlChar*) localName, (xmlChar*) namespaceURI);
7911    OUTPUT:
7912	RETVAL
7913
7914int
7915moveToElement(reader)
7916	xmlTextReaderPtr reader
7917    CODE:
7918	RETVAL = xmlTextReaderMoveToElement(reader);
7919    OUTPUT:
7920	RETVAL
7921
7922int
7923moveToFirstAttribute(reader)
7924	xmlTextReaderPtr reader
7925    CODE:
7926	RETVAL = xmlTextReaderMoveToFirstAttribute(reader);
7927    OUTPUT:
7928	RETVAL
7929
7930int
7931moveToNextAttribute(reader)
7932	xmlTextReaderPtr reader
7933    CODE:
7934	RETVAL = xmlTextReaderMoveToNextAttribute(reader);
7935    OUTPUT:
7936	RETVAL
7937
7938int
7939next(reader)
7940	xmlTextReaderPtr reader
7941    CODE:
7942	RETVAL = xmlTextReaderNext(reader);
7943        LibXML_report_reader_error(reader);
7944    OUTPUT:
7945	RETVAL
7946
7947#define LIBXML_READER_NEXT_SIBLING(ret,reader)	\
7948	ret = xmlTextReaderNextSibling(reader); \
7949        if (ret == -1)                          \
7950        {			                \
7951	  int depth;				\
7952          depth = xmlTextReaderDepth(reader);	\
7953	  ret = xmlTextReaderRead(reader);			   \
7954	  while (ret == 1 && xmlTextReaderDepth(reader) > depth) { \
7955	    ret = xmlTextReaderNext(reader);			   \
7956	  }							   \
7957	  if (ret == 1) {					   \
7958	    if (xmlTextReaderDepth(reader) != depth) {		   \
7959	      ret = 0;							\
7960	    } else if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) { \
7961	      ret = xmlTextReaderRead(reader);				\
7962	    }								\
7963	  }								\
7964        }
7965
7966int
7967nextSibling(reader)
7968	xmlTextReaderPtr reader
7969    CODE:
7970	LIBXML_READER_NEXT_SIBLING(RETVAL,reader)
7971        LibXML_report_reader_error(reader);
7972    OUTPUT:
7973	RETVAL
7974
7975int
7976nextSiblingElement(reader, name = NULL, nsURI = NULL)
7977	xmlTextReaderPtr reader
7978	const char * name
7979	const char * nsURI
7980    CODE:
7981	do {
7982	  LIBXML_READER_NEXT_SIBLING(RETVAL,reader)
7983	  if (LIBXML_READER_TEST_ELEMENT(reader,name,nsURI)) {
7984	    break;
7985	  }
7986	} while (RETVAL == 1);
7987        LibXML_report_reader_error(reader);
7988    OUTPUT:
7989	RETVAL
7990
7991int
7992nextElement(reader, name = NULL, nsURI = NULL)
7993	xmlTextReaderPtr reader
7994	const char * name
7995	const char * nsURI
7996    CODE:
7997	do {
7998	  RETVAL = xmlTextReaderRead(reader);
7999	  if (LIBXML_READER_TEST_ELEMENT(reader,name,nsURI)) {
8000	    break;
8001	  }
8002	} while (RETVAL == 1);
8003        LibXML_report_reader_error(reader);
8004    OUTPUT:
8005	RETVAL
8006
8007int
8008skipSiblings(reader)
8009	xmlTextReaderPtr reader
8010    PREINIT:
8011        int depth;
8012    CODE:
8013        depth = xmlTextReaderDepth(reader);
8014        RETVAL = -1;
8015        if (depth > 0) {
8016          do {
8017   	     RETVAL = xmlTextReaderNext(reader);
8018	  } while (RETVAL == 1 && xmlTextReaderDepth(reader) >= depth);
8019	  if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) {
8020	    RETVAL = -1;
8021	  }
8022        }
8023        LibXML_report_reader_error(reader);
8024    OUTPUT:
8025	RETVAL
8026
8027int
8028nodeType(reader)
8029	xmlTextReaderPtr reader
8030    CODE:
8031	RETVAL = xmlTextReaderNodeType(reader);
8032    OUTPUT:
8033	RETVAL
8034
8035SV*
8036quoteChar(reader)
8037	xmlTextReaderPtr reader
8038    PREINIT:
8039        int ret;
8040    CODE:
8041	ret = xmlTextReaderQuoteChar(reader);
8042        if (ret == -1) XSRETURN_UNDEF;
8043        RETVAL = newSVpvf("%c",ret);
8044    OUTPUT:
8045	RETVAL
8046
8047int
8048read(reader)
8049	xmlTextReaderPtr reader
8050    CODE:
8051	RETVAL = xmlTextReaderRead(reader);
8052        LibXML_report_reader_error(reader);
8053    OUTPUT:
8054	RETVAL
8055
8056int
8057readAttributeValue(reader)
8058	xmlTextReaderPtr reader
8059    CODE:
8060	RETVAL = xmlTextReaderReadAttributeValue(reader);
8061        LibXML_report_reader_error(reader);
8062    OUTPUT:
8063	RETVAL
8064
8065
8066SV *
8067readInnerXml(reader)
8068	xmlTextReaderPtr reader
8069    PREINIT:
8070	xmlChar *result = NULL;
8071    CODE:
8072	result = xmlTextReaderReadInnerXml(reader);
8073        if (!result) XSRETURN_UNDEF;
8074	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
8075        LibXML_report_reader_error(reader);
8076        xmlFree(result);
8077    OUTPUT:
8078	RETVAL
8079
8080SV *
8081readOuterXml(reader)
8082	xmlTextReaderPtr reader
8083    PREINIT:
8084	xmlChar *result = NULL;
8085    CODE:
8086	result = xmlTextReaderReadOuterXml(reader);
8087        if (!result) XSRETURN_UNDEF;
8088	RETVAL = C2Sv(result, xmlTextReaderConstEncoding(reader));
8089        xmlFree(result);
8090        LibXML_report_reader_error(reader);
8091    OUTPUT:
8092	RETVAL
8093
8094int
8095readState(reader)
8096	xmlTextReaderPtr reader
8097    CODE:
8098	RETVAL = xmlTextReaderReadState(reader);
8099    OUTPUT:
8100	RETVAL
8101
8102int
8103_setParserProp(reader, prop, value)
8104	xmlTextReaderPtr reader
8105	int prop
8106	int value
8107    CODE:
8108	RETVAL = xmlTextReaderSetParserProp(reader, prop, value);
8109    OUTPUT:
8110	RETVAL
8111
8112int
8113standalone(reader)
8114	xmlTextReaderPtr reader
8115    CODE:
8116	RETVAL = xmlTextReaderStandalone(reader);
8117    OUTPUT:
8118	RETVAL
8119
8120SV *
8121copyCurrentNode(reader,expand = 0)
8122	xmlTextReaderPtr reader
8123        int expand
8124    PREINIT:
8125	xmlNodePtr node = NULL;
8126	xmlNodePtr copy;
8127        xmlDocPtr  doc;
8128        SV * perl_doc;
8129    CODE:
8130	if (expand) {
8131	  node = xmlTextReaderExpand(reader);
8132        }
8133	else {
8134	  node = xmlTextReaderCurrentNode(reader);
8135	}
8136        LibXML_report_reader_error(reader);
8137        if (!node) XSRETURN_UNDEF;
8138
8139	doc = xmlTextReaderCurrentDoc(reader);
8140        if (!doc) XSRETURN_UNDEF;
8141        perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
8142        if ( PmmREFCNT(SvPROXYNODE(perl_doc))==1 ) {
8143	  /* will be decremented in Reader destructor */
8144	  PmmREFCNT_inc(SvPROXYNODE(perl_doc));
8145	}
8146
8147        copy = PmmCloneNode( node, expand );
8148        if ( copy == NULL ) {
8149            XSRETURN_UNDEF;
8150        }
8151        if ( copy->type  == XML_DTD_NODE ) {
8152            RETVAL = PmmNodeToSv(copy, NULL);
8153        }
8154        else {
8155	    ProxyNodePtr docfrag = NULL;
8156
8157            if ( doc != NULL ) {
8158                xmlSetTreeDoc(copy, doc);
8159            }
8160            docfrag = PmmNewFragment( doc );
8161            xmlAddChild( PmmNODE(docfrag), copy );
8162            RETVAL = PmmNodeToSv(copy, docfrag);
8163        }
8164    OUTPUT:
8165        RETVAL
8166
8167SV *
8168document(reader)
8169	xmlTextReaderPtr reader
8170    PREINIT:
8171	xmlDocPtr doc = NULL;
8172    CODE:
8173	doc = xmlTextReaderCurrentDoc(reader);
8174        if (!doc) XSRETURN_UNDEF;
8175        RETVAL = PmmNodeToSv((xmlNodePtr)doc, NULL);
8176        if ( PmmREFCNT(SvPROXYNODE(RETVAL))==1 ) {
8177	  /* will be decremented in Reader destructor */
8178	  PmmREFCNT_inc(SvPROXYNODE(RETVAL));
8179	}
8180    OUTPUT:
8181        RETVAL
8182
8183int
8184_preservePattern(reader,pattern,ns_map=NULL)
8185	xmlTextReaderPtr reader
8186        char * pattern
8187        AV * ns_map
8188    PREINIT:
8189        xmlChar** namespaces = NULL;
8190	SV** aux;
8191        int last,i;
8192    CODE:
8193        if (ns_map) {
8194          last = av_len(ns_map);
8195          New(0,namespaces, last+2, xmlChar*);
8196          for( i = 0; i <= last ; i++ ) {
8197              aux = av_fetch(ns_map,i,0);
8198	      namespaces[i]=(xmlChar*) SvPV_nolen(*aux);
8199          }
8200	  namespaces[i]=0;
8201	}
8202	RETVAL = xmlTextReaderPreservePattern(reader,(const xmlChar*) pattern,
8203					      (const xmlChar**)namespaces);
8204        Safefree(namespaces);
8205    OUTPUT:
8206        RETVAL
8207
8208SV *
8209preserveNode(reader)
8210	xmlTextReaderPtr reader
8211    PREINIT:
8212        xmlNodePtr node;
8213        xmlDocPtr doc;
8214        SV * perl_doc;
8215    CODE:
8216	doc = xmlTextReaderCurrentDoc(reader);
8217        if (!doc) XSRETURN_UNDEF;
8218        perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
8219        if ( PmmREFCNT(SvPROXYNODE(perl_doc))==1 ) {
8220	  /* will be decremented in Reader destructor */
8221	  PmmREFCNT_inc(SvPROXYNODE(perl_doc));
8222	}
8223	node = xmlTextReaderPreserve(reader);
8224        if (node) {
8225           RETVAL = PmmNodeToSv(node, PmmOWNERPO(PmmPROXYNODE(doc)));
8226	} else {
8227	    XSRETURN_UNDEF;
8228	}
8229    OUTPUT:
8230        RETVAL
8231
8232int
8233finish(reader)
8234	xmlTextReaderPtr reader
8235    CODE:
8236	while (1) {
8237	  RETVAL = xmlTextReaderRead(reader);
8238	  if (RETVAL!=1) break;
8239	}
8240        LibXML_report_reader_error(reader);
8241        RETVAL++; /* we want 0 - fail, 1- success */
8242    OUTPUT:
8243	RETVAL
8244
8245#ifdef HAVE_SCHEMAS
8246
8247int
8248_setRelaxNGFile(reader,rng)
8249	xmlTextReaderPtr reader
8250	char* rng
8251    CODE:
8252	RETVAL = xmlTextReaderRelaxNGValidate(reader,rng);
8253    OUTPUT:
8254	RETVAL
8255
8256int
8257_setRelaxNG(reader,rng_doc)
8258	xmlTextReaderPtr reader
8259	xmlRelaxNGPtr rng_doc
8260    CODE:
8261	RETVAL = xmlTextReaderRelaxNGSetSchema(reader,rng_doc);
8262    OUTPUT:
8263	RETVAL
8264
8265int
8266_setXSDFile(reader,xsd)
8267	xmlTextReaderPtr reader
8268	char* xsd
8269    CODE:
8270	RETVAL = xmlTextReaderSchemaValidate(reader,xsd);
8271    OUTPUT:
8272	RETVAL
8273
8274int
8275_setXSD(reader,xsd_doc)
8276	xmlTextReaderPtr reader
8277	xmlSchemaPtr xsd_doc
8278    CODE:
8279	RETVAL =  xmlTextReaderSetSchema(reader,xsd_doc);
8280    OUTPUT:
8281	RETVAL
8282
8283#endif
8284
8285void
8286_DESTROY(reader)
8287	xmlTextReaderPtr reader
8288    PREINIT:
8289        xmlDocPtr doc;
8290        SV * perl_doc;
8291	SV * error_sv = NULL;
8292	xmlTextReaderErrorFunc f = NULL;
8293    CODE:
8294	doc = xmlTextReaderCurrentDoc(reader);
8295        if (doc) {
8296          perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
8297          if ( PmmREFCNT(SvPROXYNODE(perl_doc))>1 ) {
8298	    /* was incremented in document() to pervent from PMM destruction */
8299	    PmmREFCNT_dec(SvPROXYNODE(perl_doc));
8300	  }
8301          SvREFCNT_dec(perl_doc);
8302	}
8303        if (xmlTextReaderReadState(reader) != XML_TEXTREADER_MODE_CLOSED) {
8304	  xmlTextReaderClose(reader);
8305	}
8306        xmlTextReaderGetErrorHandler(reader, &f, (void **) &error_sv);
8307        if (error_sv) {
8308           sv_2mortal(error_sv);
8309        }
8310	xmlFreeTextReader(reader);
8311
8312#endif /* HAVE_READER_SUPPORT */
8313