9714 lines
258 KiB
Plaintext
9714 lines
258 KiB
Plaintext
/* $Id$
|
|
*
|
|
* This is free software, you may use it and distribute it under the same terms as
|
|
* Perl itself.
|
|
*
|
|
* Copyright 2001-2003 AxKit.com Ltd., 2002-2006 Christian Glahn, 2006-2009 Petr Pajas
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#if defined(_MSC_VER)
|
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
|
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
|
#endif
|
|
|
|
/* perl stuff */
|
|
#include "EXTERN.h"
|
|
#include "perl.h"
|
|
#include "XSUB.h"
|
|
#define NEED_newRV_noinc_GLOBAL
|
|
#define NEED_sv_2pv_flags
|
|
#include "ppport.h"
|
|
#include "Av_CharPtrPtr.h" /* XS_*_charPtrPtr() */
|
|
|
|
#include <fcntl.h>
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/* libxml2 configuration properties */
|
|
#include <libxml/xmlversion.h>
|
|
|
|
#define DEBUG_C14N
|
|
|
|
/* libxml2 stuff */
|
|
#include <libxml/xmlversion.h>
|
|
#include <libxml/globals.h>
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/parserInternals.h>
|
|
#include <libxml/HTMLparser.h>
|
|
#include <libxml/HTMLtree.h>
|
|
#include <libxml/c14n.h>
|
|
#include <libxml/tree.h>
|
|
#include <libxml/xpath.h>
|
|
#include <libxml/xpathInternals.h>
|
|
#include <libxml/xmlIO.h>
|
|
/* #include <libxml/debugXML.h> */
|
|
#include <libxml/xmlerror.h>
|
|
#include <libxml/xinclude.h>
|
|
#include <libxml/valid.h>
|
|
|
|
#ifdef LIBXML_PATTERN_ENABLED
|
|
#include <libxml/pattern.h>
|
|
#endif
|
|
|
|
#ifdef LIBXML_REGEXP_ENABLED
|
|
#include <libxml/xmlregexp.h>
|
|
#endif
|
|
|
|
#if LIBXML_VERSION >= 20510
|
|
#define HAVE_SCHEMAS
|
|
#include <libxml/relaxng.h>
|
|
#include <libxml/xmlschemas.h>
|
|
#endif
|
|
|
|
#if LIBXML_VERSION >= 20621
|
|
#define WITH_SERRORS
|
|
#ifdef LIBXML_READER_ENABLED
|
|
#define HAVE_READER_SUPPORT
|
|
#include <libxml/xmlreader.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
#include <libxml/catalog.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_READER_SUPPORT
|
|
|
|
typedef enum {
|
|
XML_TEXTREADER_NONE = -1,
|
|
XML_TEXTREADER_START= 0,
|
|
XML_TEXTREADER_ELEMENT= 1,
|
|
XML_TEXTREADER_END= 2,
|
|
XML_TEXTREADER_EMPTY= 3,
|
|
XML_TEXTREADER_BACKTRACK= 4,
|
|
XML_TEXTREADER_DONE= 5,
|
|
XML_TEXTREADER_ERROR= 6
|
|
} xmlTextReaderState;
|
|
|
|
typedef enum {
|
|
XML_TEXTREADER_NOT_VALIDATE = 0,
|
|
XML_TEXTREADER_VALIDATE_DTD = 1,
|
|
XML_TEXTREADER_VALIDATE_RNG = 2,
|
|
XML_TEXTREADER_VALIDATE_XSD = 4
|
|
} xmlTextReaderValidate;
|
|
|
|
#endif /* HAVE_READER_SUPPORT */
|
|
|
|
/* GDOME support
|
|
* libgdome installs only the core functions to the system.
|
|
* this is not enough for XML::LibXML <-> XML::GDOME conversion.
|
|
* therefore there is the need to ship as well the GDOME core headers.
|
|
*/
|
|
#ifdef XML_LIBXML_GDOME_SUPPORT
|
|
|
|
#include <libgdome/gdome.h>
|
|
#include <libgdome/gdome-libxml-util.h>
|
|
|
|
#endif
|
|
|
|
|
|
#if LIBXML_VERSION < 20621
|
|
/* HTML_PARSE_RECOVER was added in libxml2 2.6.21 */
|
|
# define HTML_PARSE_RECOVER XML_PARSE_RECOVER
|
|
#endif
|
|
|
|
|
|
/* XML::LibXML stuff */
|
|
#include "perl-libxml-mm.h"
|
|
#include "perl-libxml-sax.h"
|
|
|
|
#include "dom.h"
|
|
#include "xpath.h"
|
|
#include "xpathcontext.h"
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
#define TEST_PERL_FLAG(flag) \
|
|
SvTRUE(get_sv(flag, FALSE)) ? 1 : 0
|
|
|
|
#ifdef HAVE_READER_SUPPORT
|
|
#define LIBXML_READER_TEST_ELEMENT(reader,name,nsURI) \
|
|
(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) && \
|
|
((!nsURI && !name) \
|
|
|| \
|
|
(!nsURI && xmlStrcmp((const xmlChar*)name, xmlTextReaderConstName(reader) ) == 0 ) \
|
|
|| \
|
|
(nsURI && xmlStrcmp((const xmlChar*)nsURI, xmlTextReaderConstNamespaceUri(reader))==0 \
|
|
&& \
|
|
(!name || xmlStrcmp((const xmlChar*)name, xmlTextReaderConstLocalName(reader)) == 0)))
|
|
#endif
|
|
|
|
/* this should keep the default */
|
|
static xmlExternalEntityLoader LibXML_old_ext_ent_loader = NULL;
|
|
|
|
/* global external entity loader */
|
|
SV *EXTERNAL_ENTITY_LOADER_FUNC = (SV *)NULL;
|
|
|
|
SV* PROXY_NODE_REGISTRY_MUTEX = NULL;
|
|
|
|
/* ****************************************************************
|
|
* Error handler
|
|
* **************************************************************** */
|
|
|
|
#ifdef WITH_SERRORS
|
|
|
|
#define INIT_READER_ERROR_HANDLER(reader)
|
|
|
|
#define PREINIT_SAVED_ERROR SV* saved_error = sv_2mortal(newSV(0));
|
|
|
|
#define INIT_ERROR_HANDLER \
|
|
xmlSetGenericErrorFunc((void *)saved_error, \
|
|
(xmlGenericErrorFunc) LibXML_flat_handler); \
|
|
xmlSetStructuredErrorFunc((void *)saved_error, \
|
|
(xmlStructuredErrorFunc)LibXML_struct_error_handler)
|
|
|
|
#define REPORT_ERROR(recover) LibXML_report_error_ctx(saved_error, recover)
|
|
|
|
#define CLEANUP_ERROR_HANDLER xmlSetGenericErrorFunc(NULL,NULL); \
|
|
xmlSetStructuredErrorFunc(NULL,NULL)
|
|
|
|
#else /* WITH_SERRORS */
|
|
|
|
#define INIT_READER_ERROR_HANDLER(reader) \
|
|
if (reader) \
|
|
xmlTextReaderSetErrorHandler(reader, LibXML_reader_error_handler, \
|
|
sv_2mortal(newSVpv("",0)));
|
|
|
|
#define PREINIT_SAVED_ERROR SV* saved_error = sv_2mortal(newSVpv("",0));
|
|
|
|
#define INIT_ERROR_HANDLER \
|
|
xmlSetGenericErrorFunc((void *) saved_error, \
|
|
(xmlGenericErrorFunc) LibXML_error_handler_ctx)
|
|
|
|
#define REPORT_ERROR(recover) LibXML_report_error_ctx(saved_error, recover)
|
|
|
|
#define CLEANUP_ERROR_HANDLER xmlSetGenericErrorFunc(NULL,NULL);
|
|
|
|
|
|
#endif /* WITH_SERRORS */
|
|
|
|
#ifdef WITH_SERRORS
|
|
void
|
|
LibXML_struct_error_callback(SV * saved_error, SV * libErr )
|
|
{
|
|
|
|
dTHX;
|
|
dSP;
|
|
|
|
if ( saved_error == NULL ) {
|
|
warn( "have no save_error\n" );
|
|
}
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
|
|
XPUSHs(sv_2mortal(libErr));
|
|
if ( saved_error != NULL && SvOK(saved_error) ) {
|
|
XPUSHs(saved_error);
|
|
}
|
|
PUTBACK;
|
|
|
|
if ( saved_error != NULL ) {
|
|
call_pv( "XML::LibXML::Error::_callback_error", G_SCALAR | G_EVAL );
|
|
} else {
|
|
call_pv( "XML::LibXML::Error::_instant_error_callback", G_SCALAR );
|
|
}
|
|
SPAGAIN;
|
|
|
|
if ( SvTRUE(ERRSV) ) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
} else {
|
|
sv_setsv(saved_error, POPs);
|
|
}
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
|
|
void
|
|
LibXML_struct_error_handler(SV * saved_error, xmlErrorPtr error )
|
|
{
|
|
const char * CLASS = "XML::LibXML::LibError";
|
|
SV* libErr;
|
|
|
|
libErr = NEWSV(0,0);
|
|
sv_setref_pv( libErr, CLASS, (void*)error );
|
|
LibXML_struct_error_callback( saved_error, libErr);
|
|
}
|
|
|
|
|
|
void
|
|
LibXML_flat_handler(SV * saved_error, const char * msg, ...)
|
|
{
|
|
SV* sv;
|
|
va_list args;
|
|
|
|
sv = newSVpv("",0);
|
|
va_start(args, msg);
|
|
sv_vcatpvf(sv, msg, &args);
|
|
va_end(args);
|
|
xs_warn("flat error\n");
|
|
LibXML_struct_error_callback( saved_error, sv);
|
|
}
|
|
|
|
#endif /* WITH_SERRORS */
|
|
|
|
|
|
/* If threads-support is working correctly in libxml2 then
|
|
* this method will be called with the correct thread-context */
|
|
void
|
|
LibXML_error_handler_ctx(void * ctxt, const char * msg, ...)
|
|
{
|
|
va_list args;
|
|
SV * saved_error = (SV *) ctxt;
|
|
|
|
/* If saved_error is null we croak with the error */
|
|
if( NULL == saved_error ) {
|
|
SV * sv = sv_2mortal(newSV(0));
|
|
va_start(args, msg);
|
|
/* vfprintf(stderr, msg, args); */
|
|
sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
croak("%s", SvPV_nolen(sv));
|
|
/* Otherwise, save the error */
|
|
} else {
|
|
va_start(args, msg);
|
|
/* vfprintf(stderr, msg, args); */
|
|
sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
static void
|
|
LibXML_validity_error_ctx(void * ctxt, const char *msg, ...)
|
|
{
|
|
va_list args;
|
|
SV * saved_error = (SV *) ctxt;
|
|
|
|
/* If saved_error is null we croak with the error */
|
|
if( NULL == saved_error ) {
|
|
SV * sv = sv_2mortal(newSV(0));
|
|
va_start(args, msg);
|
|
sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
croak("%s", SvPV_nolen(sv));
|
|
/* Otherwise, save the error */
|
|
} else {
|
|
va_start(args, msg);
|
|
sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
static void
|
|
LibXML_validity_warning_ctx(void * ctxt, const char *msg, ...)
|
|
{
|
|
va_list args;
|
|
SV * saved_error = (SV *) ctxt;
|
|
STRLEN len;
|
|
|
|
/* If saved_error is null we croak with the error */
|
|
if( NULL == saved_error ) {
|
|
SV * sv = sv_2mortal(newSV(0));
|
|
va_start(args, msg);
|
|
sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
croak("LibXML_validity_warning_ctx internal error: context was null (%s)", SvPV_nolen(sv));
|
|
/* Otherwise, give the warning */
|
|
} else {
|
|
va_start(args, msg);
|
|
sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
|
|
va_end(args);
|
|
warn("validation error: %s", SvPV(saved_error, len));
|
|
}
|
|
}
|
|
|
|
static int
|
|
LibXML_will_die_ctx(SV * saved_error, int recover)
|
|
{
|
|
#ifdef WITH_SERRORS
|
|
if( saved_error!=NULL && SvOK(saved_error) ) {
|
|
if ( recover == 0 ) {
|
|
return 1;
|
|
}
|
|
}
|
|
#else
|
|
if( 0 < SvCUR( saved_error ) ) {
|
|
if ( recover == 0 ) {
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
LibXML_report_error_ctx(SV * saved_error, int recover)
|
|
{
|
|
#ifdef WITH_SERRORS
|
|
if( saved_error!=NULL && SvOK( saved_error ) ) {
|
|
if (!recover || recover==1) {
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 1);
|
|
PUSHs(saved_error);
|
|
PUTBACK;
|
|
if (recover==1) {
|
|
call_pv( "XML::LibXML::Error::_report_warning", G_SCALAR | G_DISCARD);
|
|
} else {
|
|
call_pv( "XML::LibXML::Error::_report_error", G_SCALAR | G_DISCARD);
|
|
}
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
}
|
|
#else
|
|
if( 0 < SvCUR( saved_error ) ) {
|
|
if( recover ) {
|
|
if ( recover == 1 ) {
|
|
warn("%s", SvPV_nolen(saved_error));
|
|
} /* else recover silently */
|
|
} else {
|
|
croak("%s", SvPV_nolen(saved_error));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_READER_SUPPORT
|
|
|
|
#ifndef WITH_SERRORS
|
|
static void
|
|
LibXML_reader_error_handler(void * ctxt,
|
|
const char * msg,
|
|
xmlParserSeverities severity,
|
|
xmlTextReaderLocatorPtr locator)
|
|
{
|
|
int line = xmlTextReaderLocatorLineNumber(locator);
|
|
xmlChar * filename = xmlTextReaderLocatorBaseURI(locator);
|
|
SV * msg_sv = sv_2mortal(C2Sv((xmlChar*) msg,NULL));
|
|
SV * error = sv_2mortal(newSVpv("", 0));
|
|
|
|
switch (severity) {
|
|
case XML_PARSER_SEVERITY_VALIDITY_WARNING:
|
|
sv_catpv(error, "Validity WARNING");
|
|
break;
|
|
case XML_PARSER_SEVERITY_WARNING:
|
|
sv_catpv(error, "Reader WARNING");
|
|
break;
|
|
case XML_PARSER_SEVERITY_VALIDITY_ERROR:
|
|
sv_catpv(error, "Validity ERROR");
|
|
break;
|
|
case XML_PARSER_SEVERITY_ERROR:
|
|
sv_catpv(error, "Reader ERROR");
|
|
break;
|
|
}
|
|
if (filename) {
|
|
sv_catpvf(error, " in %s", filename);
|
|
xmlFree(filename);
|
|
}
|
|
if (line >= 0) {
|
|
sv_catpvf(error, " at line %d", line);
|
|
}
|
|
sv_catpvf(error, ": %s", SvPV_nolen(msg_sv));
|
|
if (severity == XML_PARSER_SEVERITY_VALIDITY_WARNING ||
|
|
severity == XML_PARSER_SEVERITY_WARNING ) {
|
|
warn("%s", SvPV_nolen(error));
|
|
} else {
|
|
SV * error_sv = (SV*) ctxt;
|
|
if (error_sv) {
|
|
sv_catpvf(error_sv, "%s ", SvPV_nolen(error));
|
|
} else {
|
|
croak("%s",SvPV_nolen(error));
|
|
}
|
|
}
|
|
}
|
|
#endif /* !defined WITH_SERRORS */
|
|
|
|
SV *
|
|
LibXML_get_reader_error_data(xmlTextReaderPtr reader)
|
|
{
|
|
SV * saved_error = NULL;
|
|
xmlTextReaderErrorFunc f = NULL;
|
|
xmlTextReaderGetErrorHandler(reader, &f, (void **) &saved_error);
|
|
return saved_error;
|
|
}
|
|
|
|
#ifndef WITH_SERRORS
|
|
static void
|
|
LibXML_report_reader_error(xmlTextReaderPtr reader)
|
|
{
|
|
SV * saved_error = NULL;
|
|
xmlTextReaderErrorFunc f = NULL;
|
|
xmlTextReaderGetErrorHandler(reader, &f, (void **) &saved_error);
|
|
if ( saved_error && SvOK( saved_error) && 0 < SvCUR( saved_error ) ) {
|
|
croak("%s", SvPV_nolen(saved_error));
|
|
}
|
|
}
|
|
#endif /* !defined WITH_SERRORS */
|
|
|
|
#endif /* HAVE_READER_SUPPORT */
|
|
|
|
static int
|
|
LibXML_get_recover(HV * real_obj)
|
|
{
|
|
SV** item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
|
|
return ( item != NULL && SvTRUE(*item) ) ? SvIV(*item) : 0;
|
|
}
|
|
|
|
static SV *
|
|
LibXML_NodeToSv(HV * real_obj, xmlNodePtr real_doc)
|
|
{
|
|
SV** item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
|
|
|
|
if ( item != NULL && SvTRUE(*item) ) {
|
|
return PmmNodeToGdomeSv(real_doc);
|
|
}
|
|
else {
|
|
return PmmNodeToSv(real_doc, NULL);
|
|
}
|
|
}
|
|
|
|
/* ****************************************************************
|
|
* IO callbacks
|
|
* **************************************************************** */
|
|
|
|
int
|
|
LibXML_read_perl (SV * ioref, char * buffer, int len)
|
|
{
|
|
dTHX;
|
|
dSP;
|
|
|
|
int cnt;
|
|
SV * read_results;
|
|
IV read_results_iv;
|
|
STRLEN read_length;
|
|
char * chars;
|
|
SV * tbuff = NEWSV(0,len);
|
|
SV * tsize = newSViv(len);
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 3);
|
|
PUSHs(ioref);
|
|
PUSHs(sv_2mortal(tbuff));
|
|
PUSHs(sv_2mortal(tsize));
|
|
PUTBACK;
|
|
|
|
if (sv_isobject(ioref)) {
|
|
cnt = call_method("read", G_SCALAR | G_EVAL);
|
|
}
|
|
else {
|
|
cnt = call_pv("XML::LibXML::__read", G_SCALAR | G_EVAL);
|
|
}
|
|
|
|
SPAGAIN;
|
|
|
|
if (cnt != 1) {
|
|
croak("read method call failed");
|
|
}
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
read_results = POPs;
|
|
|
|
if (!SvOK(read_results)) {
|
|
croak("read error");
|
|
}
|
|
|
|
read_results_iv = SvIV(read_results);
|
|
|
|
chars = SvPV(tbuff, read_length);
|
|
|
|
/*
|
|
* If the file handle uses an encoding layer, the length parameter is
|
|
* interpreted as character count, not as byte count. So it's possible
|
|
* that more than len bytes are read which would overflow the buffer.
|
|
* Check for this condition also by comparing the return value.
|
|
*/
|
|
if (read_results_iv != read_length || read_length > len) {
|
|
croak("Read more bytes than requested. Do you use an encoding-related"
|
|
" PerlIO layer?");
|
|
}
|
|
strncpy(buffer, chars, read_length);
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return read_length;
|
|
}
|
|
|
|
/* used only by Reader */
|
|
int
|
|
LibXML_close_perl (SV * ioref)
|
|
{
|
|
SvREFCNT_dec(ioref);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
LibXML_input_match(char const * filename)
|
|
{
|
|
int results;
|
|
int count;
|
|
SV * res;
|
|
|
|
results = 0;
|
|
|
|
{
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 1);
|
|
PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
|
|
PUTBACK;
|
|
|
|
count = call_pv("XML::LibXML::InputCallback::_callback_match",
|
|
G_SCALAR | G_EVAL);
|
|
|
|
SPAGAIN;
|
|
|
|
if (count != 1) {
|
|
croak("match callback must return a single value");
|
|
}
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
res = POPs;
|
|
|
|
if (SvTRUE(res)) {
|
|
results = 1;
|
|
}
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
return results;
|
|
}
|
|
|
|
void *
|
|
LibXML_input_open(char const * filename)
|
|
{
|
|
SV * results;
|
|
int count;
|
|
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 1);
|
|
PUSHs(sv_2mortal(newSVpv((char*)filename, 0)));
|
|
PUTBACK;
|
|
|
|
count = call_pv("XML::LibXML::InputCallback::_callback_open",
|
|
G_SCALAR | G_EVAL);
|
|
|
|
SPAGAIN;
|
|
|
|
if (count != 1) {
|
|
croak("open callback must return a single value");
|
|
}
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
results = POPs;
|
|
|
|
(void)SvREFCNT_inc(results);
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return (void *)results;
|
|
}
|
|
|
|
int
|
|
LibXML_input_read(void * context, char * buffer, int len)
|
|
{
|
|
STRLEN res_len;
|
|
const char * output;
|
|
SV * ctxt;
|
|
SV * output_sv;
|
|
|
|
res_len = 0;
|
|
ctxt = (SV *)context;
|
|
|
|
{
|
|
int count;
|
|
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 2);
|
|
PUSHs(ctxt);
|
|
PUSHs(sv_2mortal(newSViv(len)));
|
|
PUTBACK;
|
|
|
|
count = call_pv("XML::LibXML::InputCallback::_callback_read",
|
|
G_SCALAR | G_EVAL);
|
|
|
|
SPAGAIN;
|
|
|
|
if (count != 1) {
|
|
croak("read callback must return a single value");
|
|
}
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
/*
|
|
* Handle undef()s gracefully, to avoid using POPpx which warns upon $^W
|
|
* being set. See t/49callbacks_returning_undef.t and:
|
|
* https://rt.cpan.org/Ticket/Display.html?id=70321
|
|
* */
|
|
|
|
output_sv = POPs;
|
|
output = SvOK(output_sv) ? SvPV_nolen(output_sv) : NULL;
|
|
|
|
if (output != NULL) {
|
|
res_len = strlen(output);
|
|
if (res_len) {
|
|
strncpy(buffer, output, res_len);
|
|
}
|
|
else {
|
|
buffer[0] = 0;
|
|
}
|
|
}
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
return res_len;
|
|
}
|
|
|
|
void
|
|
LibXML_input_close(void * context)
|
|
{
|
|
SV * ctxt;
|
|
|
|
ctxt = (SV *)context;
|
|
|
|
{
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 1);
|
|
PUSHs(ctxt);
|
|
PUTBACK;
|
|
|
|
call_pv("XML::LibXML::InputCallback::_callback_close",
|
|
G_SCALAR | G_EVAL | G_DISCARD);
|
|
|
|
SvREFCNT_dec(ctxt);
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
croak_obj;
|
|
}
|
|
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
}
|
|
|
|
int
|
|
LibXML_output_write_handler(void * ioref, char * buffer, int len)
|
|
{
|
|
if ( buffer != NULL && len > 0) {
|
|
dTHX;
|
|
dSP;
|
|
|
|
SV * tbuff = newSVpv(buffer,len);
|
|
SV * tsize = newSViv(len);
|
|
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
EXTEND(SP, 3);
|
|
PUSHs((SV*)ioref);
|
|
PUSHs(sv_2mortal(tbuff));
|
|
PUSHs(sv_2mortal(tsize));
|
|
PUTBACK;
|
|
|
|
call_pv("XML::LibXML::__write", G_SCALAR | G_EVAL | G_DISCARD );
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
croak_obj;
|
|
}
|
|
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int
|
|
LibXML_output_close_handler( void * handler )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
xmlParserInputPtr
|
|
LibXML_load_external_entity(
|
|
const char * URL,
|
|
const char * ID,
|
|
xmlParserCtxtPtr ctxt)
|
|
{
|
|
SV ** func;
|
|
int count;
|
|
SV * results;
|
|
STRLEN results_len;
|
|
const char * results_pv;
|
|
xmlParserInputBufferPtr input_buf;
|
|
|
|
if (ctxt->_private == NULL && EXTERNAL_ENTITY_LOADER_FUNC == NULL)
|
|
{
|
|
return xmlNewInputFromFile(ctxt, URL);
|
|
}
|
|
|
|
if (URL == NULL) {
|
|
URL = "";
|
|
}
|
|
if (ID == NULL) {
|
|
ID = "";
|
|
}
|
|
|
|
/* fetch entity loader function */
|
|
if(EXTERNAL_ENTITY_LOADER_FUNC != NULL)
|
|
{
|
|
func = &EXTERNAL_ENTITY_LOADER_FUNC;
|
|
}
|
|
else
|
|
{
|
|
SV * self;
|
|
HV * real_obj;
|
|
|
|
self = (SV *)ctxt->_private;
|
|
real_obj = (HV *)SvRV(self);
|
|
func = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
|
|
}
|
|
|
|
if (func != NULL && SvTRUE(*func)) {
|
|
dTHX;
|
|
dSP;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP) ;
|
|
XPUSHs(sv_2mortal(newSVpv((char*)URL, 0)));
|
|
XPUSHs(sv_2mortal(newSVpv((char*)ID, 0)));
|
|
PUTBACK;
|
|
|
|
count = call_sv(*func, G_SCALAR | G_EVAL);
|
|
|
|
SPAGAIN;
|
|
|
|
if (count == 0) {
|
|
croak("external entity handler did not return a value");
|
|
}
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
results = POPs;
|
|
|
|
results_pv = SvPV(results, results_len);
|
|
input_buf = xmlParserInputBufferCreateMem(
|
|
results_pv,
|
|
results_len,
|
|
XML_CHAR_ENCODING_NONE
|
|
);
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return xmlNewIOInputStream(ctxt, input_buf, XML_CHAR_ENCODING_NONE);
|
|
}
|
|
else {
|
|
if (URL == NULL) {
|
|
return NULL;
|
|
}
|
|
return xmlNewInputFromFile(ctxt, URL);
|
|
}
|
|
}
|
|
|
|
/* ****************************************************************
|
|
* Helper functions
|
|
* **************************************************************** */
|
|
|
|
HV*
|
|
LibXML_init_parser( SV * self, xmlParserCtxtPtr ctxt ) {
|
|
/* we fetch all switches and callbacks from the hash */
|
|
HV* real_obj = NULL;
|
|
SV** item = NULL;
|
|
int parserOptions = XML_PARSE_NODICT;
|
|
|
|
/* A NOTE ABOUT xmlInitParser(); */
|
|
/* xmlInitParser() should be used only at startup and*/
|
|
/* not for initializing a single parser. libxml2's */
|
|
/* documentation is quite clear about this. If */
|
|
/* something fails it is a problem elsewhere. Simply */
|
|
/* resetting the entire module will lead to unwanted */
|
|
/* results in server environments, such as if */
|
|
/* mod_perl is used together with php's xml module. */
|
|
/* calling xmlInitParser() here is definitely wrong! */
|
|
/* xmlInitParser(); */
|
|
|
|
#ifndef WITH_SERRORS
|
|
xmlGetWarningsDefaultValue = 0;
|
|
#endif
|
|
if ( self != NULL ) {
|
|
/* first fetch the values from the hash */
|
|
real_obj = (HV *)SvRV(self);
|
|
|
|
item = hv_fetch( real_obj, "XML_LIBXML_PARSER_OPTIONS", 25, 0 );
|
|
if (item != NULL && SvOK(*item)) parserOptions = sv_2iv(*item);
|
|
|
|
/* compatibility with old implementation:
|
|
absence of XML_PARSE_DTDLOAD (load_ext_dtd) implies absence of
|
|
all DTD related flags
|
|
*/
|
|
if ((parserOptions & XML_PARSE_DTDLOAD) == 0) {
|
|
parserOptions &= ~(XML_PARSE_DTDVALID | XML_PARSE_DTDATTR | XML_PARSE_NOENT );
|
|
}
|
|
if (ctxt) xmlCtxtUseOptions(ctxt, parserOptions ); /* Note: sets ctxt->linenumbers = 1 */
|
|
|
|
/*
|
|
* Without this if/else conditional, NOBLANKS has no effect.
|
|
*
|
|
* For more information, see:
|
|
*
|
|
* https://rt.cpan.org/Ticket/Display.html?id=76696
|
|
*
|
|
* */
|
|
if (parserOptions & XML_PARSE_NOBLANKS) {
|
|
xmlKeepBlanksDefault(0);
|
|
}
|
|
else {
|
|
xmlKeepBlanksDefault(1);
|
|
}
|
|
|
|
item = hv_fetch( real_obj, "XML_LIBXML_LINENUMBERS", 22, 0 );
|
|
if ( item != NULL && SvTRUE(*item) ) {
|
|
if (ctxt) ctxt->linenumbers = 1;
|
|
}
|
|
else {
|
|
if (ctxt) ctxt->linenumbers = 0;
|
|
}
|
|
|
|
if(EXTERNAL_ENTITY_LOADER_FUNC == NULL)
|
|
{
|
|
item = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
|
|
if (item != NULL && SvTRUE(*item)) {
|
|
LibXML_old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
|
|
}
|
|
else
|
|
{
|
|
if (parserOptions & XML_PARSE_NONET)
|
|
{
|
|
LibXML_old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
/* LibXML_old_ext_ent_loader = NULL; */
|
|
}
|
|
}
|
|
}
|
|
|
|
return real_obj;
|
|
}
|
|
|
|
void
|
|
LibXML_cleanup_parser() {
|
|
#ifndef WITH_SERRORS
|
|
xmlGetWarningsDefaultValue = 0;
|
|
#endif
|
|
if (EXTERNAL_ENTITY_LOADER_FUNC == NULL && LibXML_old_ext_ent_loader != NULL)
|
|
{
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_old_ext_ent_loader );
|
|
}
|
|
}
|
|
|
|
int
|
|
LibXML_test_node_name( xmlChar * name )
|
|
{
|
|
xmlChar * cur = name;
|
|
int tc = 0;
|
|
int len = 0;
|
|
|
|
if ( cur == NULL || *cur == 0 ) {
|
|
/* warn("name is empty" ); */
|
|
return(0);
|
|
}
|
|
|
|
tc = domParseChar( cur, &len );
|
|
|
|
if ( !( IS_LETTER( tc ) || (tc == '_') || (tc == ':')) ) {
|
|
/* warn( "is not a letter\n" ); */
|
|
return(0);
|
|
}
|
|
|
|
tc = 0;
|
|
cur += len;
|
|
|
|
while (*cur != 0 ) {
|
|
tc = domParseChar( cur, &len );
|
|
|
|
if (!(IS_LETTER(tc) || IS_DIGIT(tc) || (tc == '_') ||
|
|
(tc == '-') || (tc == ':') || (tc == '.') ||
|
|
IS_COMBINING(tc) || IS_EXTENDER(tc)) ) {
|
|
/* warn( "is not a letter\n" ); */
|
|
return(0);
|
|
}
|
|
tc = 0;
|
|
cur += len;
|
|
}
|
|
|
|
/* warn("name is ok"); */
|
|
return(1);
|
|
}
|
|
|
|
/* Assumes that the node has a proxy. */
|
|
static void
|
|
LibXML_reparent_removed_node(xmlNodePtr node) {
|
|
/*
|
|
* Attribute nodes can't be added to document fragments. Adding
|
|
* DTD nodes would cause a memory leak.
|
|
*/
|
|
if (node->type != XML_ATTRIBUTE_NODE
|
|
&& node->type != XML_DTD_NODE) {
|
|
ProxyNodePtr docfrag = PmmNewFragment(node->doc);
|
|
xmlAddChild(PmmNODE(docfrag), node);
|
|
PmmFixOwner(PmmPROXYNODE(node), docfrag);
|
|
}
|
|
}
|
|
|
|
static void
|
|
LibXML_set_int_subset(xmlDocPtr doc, xmlNodePtr dtd) {
|
|
xmlNodePtr old_dtd = (xmlNodePtr)doc->intSubset;
|
|
if (old_dtd == dtd) {
|
|
return;
|
|
}
|
|
|
|
if (old_dtd != NULL) {
|
|
xmlUnlinkNode(old_dtd);
|
|
|
|
if (PmmPROXYNODE(old_dtd) == NULL) {
|
|
xmlFreeDtd((xmlDtdPtr)old_dtd);
|
|
}
|
|
}
|
|
|
|
doc->intSubset = (xmlDtdPtr)dtd;
|
|
}
|
|
|
|
/* ****************************************************************
|
|
* XPathContext helper functions
|
|
* **************************************************************** */
|
|
|
|
/* Temporary node pool: *
|
|
* Stores pnode in context node-pool hash table in order to preserve *
|
|
* at least one reference. *
|
|
* If pnode is NULL, only return current value for hashkey */
|
|
static SV*
|
|
LibXML_XPathContext_pool ( xmlXPathContextPtr ctxt, void * hashkey, SV * pnode ) {
|
|
SV ** value;
|
|
SV * key;
|
|
STRLEN len;
|
|
char * strkey;
|
|
dTHX;
|
|
|
|
if (XPathContextDATA(ctxt)->pool == NULL) {
|
|
if (pnode == NULL) {
|
|
return &PL_sv_undef;
|
|
} else {
|
|
xs_warn("initializing node pool");
|
|
XPathContextDATA(ctxt)->pool = newHV();
|
|
}
|
|
}
|
|
|
|
key = newSViv(PTR2IV(hashkey));
|
|
strkey = SvPV(key, len);
|
|
if (pnode != NULL && !hv_exists(XPathContextDATA(ctxt)->pool,strkey,len)) {
|
|
value = hv_store(XPathContextDATA(ctxt)->pool,strkey,len, SvREFCNT_inc(pnode),0);
|
|
} else {
|
|
value = hv_fetch(XPathContextDATA(ctxt)->pool,strkey,len, 0);
|
|
}
|
|
SvREFCNT_dec(key);
|
|
|
|
if (value == NULL) {
|
|
return &PL_sv_undef;
|
|
} else {
|
|
return *value;
|
|
}
|
|
}
|
|
|
|
/* convert perl result structures to LibXML structures */
|
|
static xmlXPathObjectPtr
|
|
LibXML_perldata_to_LibXMLdata(xmlXPathParserContextPtr ctxt,
|
|
SV* perl_result) {
|
|
dTHX;
|
|
|
|
if (!SvOK(perl_result)) {
|
|
return (xmlXPathObjectPtr)xmlXPathNewCString("");
|
|
}
|
|
if (SvROK(perl_result) &&
|
|
SvTYPE(SvRV(perl_result)) == SVt_PVAV) {
|
|
/* consider any array ref to be a nodelist */
|
|
int i;
|
|
int length;
|
|
SV ** pnode;
|
|
AV * array_result;
|
|
xmlXPathObjectPtr ret;
|
|
|
|
ret = (xmlXPathObjectPtr) xmlXPathNewNodeSet(INT2PTR(xmlNodePtr,NULL));
|
|
array_result = (AV*)SvRV(perl_result);
|
|
length = av_len(array_result);
|
|
for( i = 0; i <= length ; i++ ) {
|
|
pnode = av_fetch(array_result,i,0);
|
|
if (pnode != NULL && sv_isobject(*pnode) &&
|
|
sv_derived_from(*pnode,"XML::LibXML::Node")) {
|
|
xmlXPathNodeSetAdd(ret->nodesetval,
|
|
INT2PTR(xmlNodePtr,PmmSvNode(*pnode)));
|
|
if(ctxt) {
|
|
LibXML_XPathContext_pool(ctxt->context,
|
|
PmmSvNode(*pnode), *pnode);
|
|
}
|
|
} else {
|
|
warn("XPathContext: ignoring non-node member of a nodelist");
|
|
}
|
|
}
|
|
return ret;
|
|
} else if (sv_isobject(perl_result) &&
|
|
(SvTYPE(SvRV(perl_result)) == SVt_PVMG))
|
|
{
|
|
if (sv_derived_from(perl_result, "XML::LibXML::Node")) {
|
|
xmlNodePtr tmp_node;
|
|
xmlXPathObjectPtr ret;
|
|
|
|
ret = INT2PTR(xmlXPathObjectPtr,xmlXPathNewNodeSet(NULL));
|
|
tmp_node = INT2PTR(xmlNodePtr,PmmSvNode(perl_result));
|
|
xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
|
|
if(ctxt) {
|
|
LibXML_XPathContext_pool(ctxt->context, PmmSvNode(perl_result),
|
|
perl_result);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
else if (sv_isa(perl_result, "XML::LibXML::Boolean")) {
|
|
return (xmlXPathObjectPtr)
|
|
xmlXPathNewBoolean(SvIV(SvRV(perl_result)));
|
|
}
|
|
else if (sv_isa(perl_result, "XML::LibXML::Literal")) {
|
|
return (xmlXPathObjectPtr)
|
|
xmlXPathNewCString(SvPV_nolen(SvRV(perl_result)));
|
|
}
|
|
else if (sv_isa(perl_result, "XML::LibXML::Number")) {
|
|
return (xmlXPathObjectPtr)
|
|
xmlXPathNewFloat(SvNV(SvRV(perl_result)));
|
|
}
|
|
} else if (SvNOK(perl_result) || SvIOK(perl_result)) {
|
|
return (xmlXPathObjectPtr)xmlXPathNewFloat(SvNV(perl_result));
|
|
} else {
|
|
return (xmlXPathObjectPtr)
|
|
xmlXPathNewCString(SvPV_nolen(perl_result));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* save XPath context and XPathContextDATA for recursion */
|
|
static xmlXPathContextPtr
|
|
LibXML_save_context(xmlXPathContextPtr ctxt)
|
|
{
|
|
xmlXPathContextPtr copy;
|
|
copy = xmlMalloc(sizeof(xmlXPathContext));
|
|
if (copy) {
|
|
/* backup ctxt */
|
|
memcpy(copy, ctxt, sizeof(xmlXPathContext));
|
|
/* clear namespaces so that they are not freed and overwritten
|
|
by configure_namespaces */
|
|
ctxt->namespaces = NULL;
|
|
/* backup data */
|
|
copy->user = xmlMalloc(sizeof(XPathContextData));
|
|
if (XPathContextDATA(copy)) {
|
|
memcpy(XPathContextDATA(copy), XPathContextDATA(ctxt),sizeof(XPathContextData));
|
|
/* clear ctxt->pool, so that it is not used freed during re-entrance */
|
|
XPathContextDATA(ctxt)->pool = NULL;
|
|
}
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
/* restore XPath context and XPathContextDATA from a saved copy */
|
|
static void
|
|
LibXML_restore_context(xmlXPathContextPtr ctxt, xmlXPathContextPtr copy)
|
|
{
|
|
dTHX;
|
|
/* cleanup */
|
|
if (XPathContextDATA(ctxt)) {
|
|
/* cleanup newly created pool */
|
|
if (XPathContextDATA(ctxt)->pool != NULL &&
|
|
SvOK(XPathContextDATA(ctxt)->pool)) {
|
|
SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
|
|
}
|
|
}
|
|
if (ctxt->namespaces) {
|
|
/* free namespaces allocated during recursion */
|
|
xmlFree( ctxt->namespaces );
|
|
}
|
|
|
|
/* restore context */
|
|
if (copy) {
|
|
/* 1st restore our data */
|
|
if (XPathContextDATA(copy)) {
|
|
memcpy(XPathContextDATA(ctxt),XPathContextDATA(copy),sizeof(XPathContextData));
|
|
xmlFree(XPathContextDATA(copy));
|
|
copy->user = XPathContextDATA(ctxt);
|
|
}
|
|
/* now copy the rest */
|
|
memcpy(ctxt, copy, sizeof(xmlXPathContext));
|
|
xmlFree(copy);
|
|
}
|
|
}
|
|
|
|
|
|
/* ****************************************************************
|
|
* Variable Lookup
|
|
* **************************************************************** */
|
|
/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT */
|
|
static xmlXPathObjectPtr
|
|
LibXML_generic_variable_lookup(void* varLookupData,
|
|
const xmlChar *name,
|
|
const xmlChar *ns_uri)
|
|
{
|
|
xmlXPathObjectPtr ret;
|
|
xmlXPathContextPtr ctxt;
|
|
xmlXPathContextPtr copy;
|
|
XPathContextDataPtr data;
|
|
I32 count;
|
|
dTHX;
|
|
dSP;
|
|
|
|
ctxt = (xmlXPathContextPtr) varLookupData;
|
|
if ( ctxt == NULL )
|
|
croak("XPathContext: missing xpath context");
|
|
data = XPathContextDATA(ctxt);
|
|
if ( data == NULL )
|
|
croak("XPathContext: missing xpath context private data");
|
|
if ( data->varLookup == NULL || !SvROK(data->varLookup) ||
|
|
SvTYPE(SvRV(data->varLookup)) != SVt_PVCV )
|
|
croak("XPathContext: lost variable lookup function!");
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
|
|
XPUSHs( (data->varData != NULL) ? data->varData : &PL_sv_undef );
|
|
XPUSHs(sv_2mortal(C2Sv(name,NULL)));
|
|
XPUSHs(sv_2mortal(C2Sv(ns_uri,NULL)));
|
|
|
|
/* save context to allow recursive usage of XPathContext */
|
|
copy = LibXML_save_context(ctxt);
|
|
|
|
PUTBACK ;
|
|
count = call_sv(data->varLookup, G_SCALAR|G_EVAL);
|
|
SPAGAIN;
|
|
|
|
/* restore the xpath context */
|
|
LibXML_restore_context(ctxt, copy);
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
if (count != 1) croak("XPathContext: variable lookup function returned none or more than one argument!");
|
|
|
|
ret = LibXML_perldata_to_LibXMLdata(NULL, POPs);
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
return ret;
|
|
}
|
|
|
|
/* ****************************************************************
|
|
* Generic Extension Function
|
|
* **************************************************************** */
|
|
/* Much of the code is borrowed from Matt Sergeant's XML::LibXSLT */
|
|
static void
|
|
LibXML_generic_extension_function(xmlXPathParserContextPtr ctxt, int nargs)
|
|
{
|
|
xmlXPathObjectPtr obj,ret;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
int count;
|
|
SV * perl_dispatch;
|
|
int i;
|
|
STRLEN len;
|
|
ProxyNodePtr owner = NULL;
|
|
SV *key;
|
|
char *strkey;
|
|
const char *function, *uri;
|
|
SV **perl_function;
|
|
dTHX;
|
|
dSP;
|
|
SV * data;
|
|
xmlXPathContextPtr copy;
|
|
|
|
/* warn("entered LibXML_generic_extension_function for %s\n",ctxt->context->function); */
|
|
data = (SV *) ctxt->context->funcLookupData;
|
|
if (ctxt->context->funcLookupData == NULL || !SvROK(data) ||
|
|
SvTYPE(SvRV(data)) != SVt_PVHV) {
|
|
croak("XPathContext: lost function lookup data structure!");
|
|
}
|
|
|
|
function = (char*) ctxt->context->function;
|
|
uri = (char*) ctxt->context->functionURI;
|
|
|
|
key = newSVpvn("",0);
|
|
if (uri && *uri) {
|
|
sv_catpv(key, "{");
|
|
sv_catpv(key, (const char*)uri);
|
|
sv_catpv(key, "}");
|
|
}
|
|
sv_catpv(key, (const char*)function);
|
|
strkey = SvPV(key, len);
|
|
perl_function =
|
|
hv_fetch((HV*)SvRV(data), strkey, len, 0);
|
|
if ( perl_function == NULL || !SvOK(*perl_function) ||
|
|
!(SvPOK(*perl_function) ||
|
|
(SvROK(*perl_function) &&
|
|
SvTYPE(SvRV(*perl_function)) == SVt_PVCV))) {
|
|
croak("XPathContext: lost perl extension function!");
|
|
}
|
|
SvREFCNT_dec(key);
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
|
|
XPUSHs(*perl_function);
|
|
|
|
/* set up call to perl dispatcher function */
|
|
for (i = 0; i < nargs; i++) {
|
|
obj = (xmlXPathObjectPtr)valuePop(ctxt);
|
|
switch (obj->type) {
|
|
case XPATH_XSLT_TREE:
|
|
case XPATH_NODESET:
|
|
nodelist = obj->nodesetval;
|
|
if ( nodelist ) {
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
|
|
XPUSHs(sv_2mortal(newSViv(nodelist->nodeNr)));
|
|
if ( nodelist->nodeNr > 0 ) {
|
|
int j;
|
|
const char * cls = "XML::LibXML::Node";
|
|
xmlNodePtr tnode;
|
|
SV * element;
|
|
int l = nodelist->nodeNr;
|
|
|
|
for( j = 0 ; j < l; j++){
|
|
tnode = nodelist->nodeTab[j];
|
|
if( tnode != NULL && tnode->doc != NULL) {
|
|
owner = PmmOWNERPO(PmmNewNode(INT2PTR(xmlNodePtr,tnode->doc)));
|
|
} else {
|
|
owner = NULL;
|
|
}
|
|
if (tnode->type == XML_NAMESPACE_DECL) {
|
|
element = NEWSV(0,0);
|
|
cls = PmmNodeTypeName( tnode );
|
|
element = sv_setref_pv( element,
|
|
(const char *)cls,
|
|
(void *)xmlCopyNamespace((xmlNsPtr)tnode)
|
|
);
|
|
}
|
|
else {
|
|
element = PmmNodeToSv(tnode, owner);
|
|
}
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
} else {
|
|
/* PP: We can't simply leave out an empty nodelist as Matt does! */
|
|
/* PP: The number of arguments must match! */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
|
|
XPUSHs(sv_2mortal(newSViv(0)));
|
|
}
|
|
/* prevent libxml2 from freeing the actual nodes */
|
|
if (obj->boolval) obj->boolval=0;
|
|
break;
|
|
case XPATH_BOOLEAN:
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
|
|
XPUSHs(sv_2mortal(newSViv(obj->boolval)));
|
|
break;
|
|
case XPATH_NUMBER:
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
|
|
XPUSHs(sv_2mortal(newSVnv(obj->floatval)));
|
|
break;
|
|
case XPATH_STRING:
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
|
|
XPUSHs(sv_2mortal(C2Sv(obj->stringval, 0)));
|
|
break;
|
|
default:
|
|
warn("Unknown XPath return type (%d) in call to {%s}%s - assuming string", obj->type, uri, function);
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
|
|
XPUSHs(sv_2mortal(C2Sv(xmlXPathCastToString(obj), 0)));
|
|
}
|
|
xmlXPathFreeObject(obj);
|
|
}
|
|
|
|
/* save context to allow recursive usage of XPathContext */
|
|
copy = LibXML_save_context(ctxt->context);
|
|
|
|
/* call perl dispatcher */
|
|
PUTBACK;
|
|
perl_dispatch = sv_2mortal(newSVpv("XML::LibXML::XPathContext::_perl_dispatcher",0));
|
|
count = call_sv(perl_dispatch, G_SCALAR|G_EVAL);
|
|
SPAGAIN;
|
|
|
|
/* restore the xpath context */
|
|
LibXML_restore_context(ctxt->context, copy);
|
|
|
|
if (SvTRUE(ERRSV)) {
|
|
(void) POPs;
|
|
croak_obj;
|
|
}
|
|
|
|
if (count != 1) croak("XPathContext: perl-dispatcher in pm file returned none or more than one argument!");
|
|
|
|
ret = LibXML_perldata_to_LibXMLdata(ctxt, POPs);
|
|
|
|
valuePush(ctxt, ret);
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
}
|
|
|
|
static void
|
|
LibXML_configure_namespaces( xmlXPathContextPtr ctxt ) {
|
|
xmlNodePtr node = ctxt->node;
|
|
|
|
if (ctxt->namespaces != NULL) {
|
|
xmlFree( ctxt->namespaces );
|
|
ctxt->namespaces = NULL;
|
|
}
|
|
if (node != NULL) {
|
|
if (node->type == XML_DOCUMENT_NODE) {
|
|
ctxt->namespaces = xmlGetNsList( node->doc,
|
|
xmlDocGetRootElement( node->doc ) );
|
|
} else {
|
|
ctxt->namespaces = xmlGetNsList(node->doc, node);
|
|
}
|
|
ctxt->nsNr = 0;
|
|
if (ctxt->namespaces != NULL) {
|
|
int cur=0;
|
|
xmlNsPtr ns;
|
|
/* we now walk through the list and
|
|
drop every ns that was declared via registration */
|
|
while (ctxt->namespaces[cur] != NULL) {
|
|
ns = ctxt->namespaces[cur];
|
|
if (ns->prefix==NULL ||
|
|
xmlHashLookup(ctxt->nsHash, ns->prefix) != NULL) {
|
|
/* drop it */
|
|
ctxt->namespaces[cur]=NULL;
|
|
} else {
|
|
if (cur != ctxt->nsNr) {
|
|
/* move the item to the new tail */
|
|
ctxt->namespaces[ctxt->nsNr]=ns;
|
|
ctxt->namespaces[cur]=NULL;
|
|
}
|
|
ctxt->nsNr++;
|
|
}
|
|
cur++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
LibXML_configure_xpathcontext( xmlXPathContextPtr ctxt ) {
|
|
xmlNodePtr node = PmmSvNode(XPathContextDATA(ctxt)->node);
|
|
|
|
if (node != NULL) {
|
|
ctxt->doc = node->doc;
|
|
} else {
|
|
ctxt->doc = NULL;
|
|
}
|
|
ctxt->node = node;
|
|
LibXML_configure_namespaces(ctxt);
|
|
}
|
|
|
|
#ifdef HAVE_READER_SUPPORT
|
|
|
|
static void
|
|
LibXML_set_reader_preserve_flag( xmlTextReaderPtr reader ) {
|
|
HV *hash;
|
|
char key[32];
|
|
|
|
hash = get_hv("XML::LibXML::Reader::_preserve_flag", 0);
|
|
if (!hash) {
|
|
return;
|
|
}
|
|
|
|
(void) snprintf(key, sizeof(key), "%p", reader);
|
|
(void) hv_store(hash, key, strlen(key), newSV(0), 0);
|
|
}
|
|
|
|
static int
|
|
LibXML_get_reader_preserve_flag( xmlTextReaderPtr reader ) {
|
|
HV *hash;
|
|
char key[32];
|
|
|
|
hash = get_hv("XML::LibXML::Reader::_preserve_flag", 0);
|
|
if (!hash) {
|
|
return 0;
|
|
}
|
|
|
|
(void) snprintf(key, sizeof(key), "%p", reader);
|
|
if ( hv_exists(hash, key, strlen(key)) ) {
|
|
(void) hv_delete(hash, key, strlen(key), G_DISCARD);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* HAVE_READER_SUPPORT */
|
|
|
|
extern void boot_XML__LibXML__Devel(pTHX_ CV*);
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML
|
|
|
|
PROTOTYPES: DISABLE
|
|
|
|
BOOT:
|
|
/* Load Devel first, so debug_memory can
|
|
be called before any allocation. */
|
|
|
|
/* The ++ is a bit hacky, but boot_blahblah_Devel, being an
|
|
* XSUB body, will try to pop once more the mark we have just
|
|
* (implicitly) popped, this boot sector also being an XSUB body */
|
|
PL_markstack_ptr++;
|
|
boot_XML__LibXML__Devel(aTHX_ cv);
|
|
LIBXML_TEST_VERSION
|
|
xmlInitParser();
|
|
PmmSAXInitialize(aTHX);
|
|
#ifndef WITH_SERRORS
|
|
xmlGetWarningsDefaultValue = 0;
|
|
#endif
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
/* xmlCatalogSetDebug(10); */
|
|
xmlInitializeCatalog(); /* use catalog data */
|
|
#endif
|
|
|
|
|
|
void
|
|
_CLONE( class )
|
|
CODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
if( PmmUSEREGISTRY )
|
|
PmmCloneProxyNodes();
|
|
#endif
|
|
|
|
int
|
|
_leaked_nodes()
|
|
CODE:
|
|
RETVAL = 0;
|
|
#ifdef XML_LIBXML_THREADS
|
|
if( PmmUSEREGISTRY )
|
|
RETVAL = PmmProxyNodeRegistrySize();
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_dump_registry()
|
|
PPCODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
if( PmmUSEREGISTRY )
|
|
PmmDumpRegistry(PmmREGISTRY);
|
|
#endif
|
|
|
|
const char *
|
|
LIBXML_DOTTED_VERSION()
|
|
CODE:
|
|
RETVAL = LIBXML_DOTTED_VERSION;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
LIBXML_VERSION()
|
|
CODE:
|
|
RETVAL = LIBXML_VERSION;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
HAVE_STRUCT_ERRORS()
|
|
CODE:
|
|
#ifdef WITH_SERRORS
|
|
RETVAL = 1;
|
|
#else
|
|
RETVAL = 0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
HAVE_SCHEMAS()
|
|
CODE:
|
|
#ifdef HAVE_SCHEMAS
|
|
RETVAL = 1;
|
|
# if LIBXML_VERSION == 20904
|
|
/* exists but broken https://github.com/shlomif/libxml2-2.9.4-reader-schema-regression */
|
|
RETVAL = 0;
|
|
# endif
|
|
#else
|
|
RETVAL = 0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
HAVE_READER()
|
|
CODE:
|
|
#ifdef HAVE_READER_SUPPORT
|
|
RETVAL = 1;
|
|
#else
|
|
RETVAL = 0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
HAVE_THREAD_SUPPORT()
|
|
CODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
RETVAL = (PmmUSEREGISTRY ? 1 : 0);
|
|
#else
|
|
RETVAL = 0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
const char *
|
|
LIBXML_RUNTIME_VERSION()
|
|
CODE:
|
|
RETVAL = xmlParserVersion;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
END()
|
|
CODE:
|
|
xmlCleanupParser();
|
|
|
|
int
|
|
INIT_THREAD_SUPPORT()
|
|
CODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
SV *threads = get_sv("threads::threads", 0); /* no create */
|
|
if( threads && SvOK(threads) && SvTRUE(threads) ) {
|
|
PROXY_NODE_REGISTRY_MUTEX = get_sv("XML::LibXML::__PROXY_NODE_REGISTRY_MUTEX",0);
|
|
RETVAL = 1;
|
|
} else {
|
|
croak("XML::LibXML ':threads_shared' can only be used after 'use threads'");
|
|
}
|
|
#else
|
|
RETVAL = 0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DISABLE_THREAD_SUPPORT()
|
|
CODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
PROXY_NODE_REGISTRY_MUTEX = NULL;
|
|
#else
|
|
croak("XML::LibXML compiled without threads!");
|
|
#endif
|
|
|
|
SV*
|
|
_parse_string(self, string, dir = &PL_sv_undef)
|
|
SV * self
|
|
SV * string
|
|
SV * dir
|
|
PREINIT:
|
|
char * directory = NULL;
|
|
STRLEN len;
|
|
const char * ptr;
|
|
HV * real_obj;
|
|
int well_formed;
|
|
int valid;
|
|
int validate;
|
|
xmlDocPtr real_doc;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if (SvPOK(dir)) {
|
|
directory = SvPV(dir, len);
|
|
if (len <= 0) {
|
|
directory = NULL;
|
|
}
|
|
}
|
|
/* If string is a reference to a string - dereference it.
|
|
* See: https://rt.cpan.org/Ticket/Display.html?id=64051 (broke it)
|
|
* https://rt.cpan.org/Ticket/Display.html?id=77864 (fixed it) */
|
|
if (SvROK(string) && !SvOBJECT(SvRV(string))) {
|
|
string = SvRV(string);
|
|
}
|
|
ptr = SvPV_const(string, len);
|
|
if (len <= 0) {
|
|
croak("Empty string\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
{
|
|
xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(ptr, len);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(1);
|
|
croak("Could not create memory parser context!\n");
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
|
|
if ( directory != NULL ) {
|
|
ctxt->directory = directory;
|
|
}
|
|
ctxt->_private = (void*)self;
|
|
|
|
/* make libxml2-2.6 display line number on error */
|
|
if ( ctxt->input != NULL ) {
|
|
if (directory != NULL) {
|
|
ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) directory);
|
|
} else {
|
|
ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) "");
|
|
}
|
|
}
|
|
|
|
xs_warn( "context initialized\n" );
|
|
|
|
xmlParseDocument(ctxt);
|
|
xs_warn( "document parsed \n");
|
|
|
|
ctxt->directory = NULL;
|
|
well_formed = ctxt->wellFormed;
|
|
valid = ctxt->valid;
|
|
validate = ctxt->validate;
|
|
real_doc = ctxt->myDoc;
|
|
ctxt->myDoc = NULL;
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
if ( real_doc != NULL ) {
|
|
if (real_doc->URL != NULL) { /* free "" assigned above */
|
|
xmlFree((char*) real_doc->URL);
|
|
real_doc->URL = NULL;
|
|
}
|
|
|
|
if ( directory == NULL ) {
|
|
SV * newURI = sv_2mortal(newSVpvf("unknown-%p", (void*)real_doc));
|
|
real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
|
|
} else {
|
|
real_doc->URL = xmlStrdup((const xmlChar*)directory);
|
|
}
|
|
if ( ! LibXML_will_die_ctx(saved_error, recover) &&
|
|
(recover || ( well_formed &&
|
|
( !validate
|
|
|| ( valid || ( real_doc->intSubset == NULL
|
|
&& real_doc->extSubset == NULL )))))) {
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
} else {
|
|
xmlFreeDoc(real_doc);
|
|
real_doc=NULL;
|
|
}
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_parse_sax_string(self, string)
|
|
SV * self
|
|
SV * string
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * ptr;
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ptr = SvPV(string, len);
|
|
if (len <= 0) {
|
|
croak("Empty string\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = 0;
|
|
INIT_ERROR_HANDLER;
|
|
|
|
{
|
|
xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover ? recover : 1);
|
|
croak("Could not create memory parser context!\n");
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
PmmSAXInitContext( ctxt, self, saved_error );
|
|
xs_warn( "context initialized \n");
|
|
{
|
|
RETVAL = xmlParseDocument(ctxt);
|
|
xs_warn( "document parsed \n");
|
|
}
|
|
|
|
PmmSAXCloseContext(ctxt);
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_parse_fh(self, fh, dir = &PL_sv_undef)
|
|
SV * self
|
|
SV * fh
|
|
SV * dir
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * directory = NULL;
|
|
HV * real_obj;
|
|
int well_formed;
|
|
int valid;
|
|
int validate;
|
|
xmlDocPtr real_doc;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if (SvPOK(dir)) {
|
|
directory = SvPV(dir, len);
|
|
if (len <= 0) {
|
|
directory = NULL;
|
|
}
|
|
}
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
|
|
{
|
|
int read_length;
|
|
char buffer[1024];
|
|
xmlParserCtxtPtr ctxt;
|
|
|
|
read_length = LibXML_read_perl(fh, buffer, 4);
|
|
if (read_length <= 0) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
croak( "Empty Stream\n" );
|
|
}
|
|
|
|
ctxt = xmlCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(1);
|
|
croak("Could not create xml push parser context!\n");
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
#if LIBXML_VERSION > 20600
|
|
/* dictionaries not support yet */
|
|
ctxt->dictNames = 0;
|
|
#endif
|
|
if ( directory != NULL ) {
|
|
ctxt->directory = directory;
|
|
}
|
|
ctxt->_private = (void*)self;
|
|
xs_warn( "context initialized \n");
|
|
{
|
|
int ret;
|
|
while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
|
|
ret = xmlParseChunk(ctxt, buffer, read_length, 0);
|
|
if ( ret != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
ret = xmlParseChunk(ctxt, buffer, 0, 1);
|
|
xs_warn( "document parsed \n");
|
|
}
|
|
|
|
ctxt->directory = NULL;
|
|
well_formed = ctxt->wellFormed;
|
|
valid = ctxt->valid;
|
|
validate = ctxt->validate;
|
|
real_doc = ctxt->myDoc;
|
|
ctxt->myDoc = NULL;
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
|
|
if ( real_doc != NULL ) {
|
|
|
|
if ( directory == NULL ) {
|
|
SV * newURI = sv_2mortal(newSVpvf("unknown-%p", (void*)real_doc));
|
|
real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
|
|
} else {
|
|
real_doc->URL = xmlStrdup((const xmlChar*)directory);
|
|
}
|
|
|
|
if ( ! LibXML_will_die_ctx(saved_error, recover) &&
|
|
(recover || ( well_formed &&
|
|
( !validate
|
|
|| ( valid || ( real_doc->intSubset == NULL
|
|
&& real_doc->extSubset == NULL )))))) {
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
} else {
|
|
xmlFreeDoc(real_doc);
|
|
real_doc=NULL;
|
|
}
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_parse_sax_fh(self, fh, dir = &PL_sv_undef)
|
|
SV * self
|
|
SV * fh
|
|
SV * dir
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * directory = NULL;
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if (SvPOK(dir)) {
|
|
directory = SvPV(dir, len);
|
|
if (len <= 0) {
|
|
directory = NULL;
|
|
}
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
{
|
|
int read_length;
|
|
char buffer[1024];
|
|
xmlSAXHandlerPtr sax;
|
|
xmlParserCtxtPtr ctxt;
|
|
|
|
read_length = LibXML_read_perl(fh, buffer, 4);
|
|
if (read_length <= 0) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
croak( "Empty Stream\n" );
|
|
}
|
|
|
|
sax = PSaxGetHandler();
|
|
ctxt = xmlCreatePushParserCtxt(sax, NULL, buffer, read_length, NULL);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover ? recover : 1);
|
|
croak("Could not create xml push parser context!\n");
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
if ( directory != NULL ) {
|
|
ctxt->directory = directory;
|
|
}
|
|
PmmSAXInitContext( ctxt, self, saved_error );
|
|
xs_warn( "context initialized \n");
|
|
|
|
{
|
|
int ret;
|
|
while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
|
|
ret = xmlParseChunk(ctxt, buffer, read_length, 0);
|
|
if ( ret != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
ret = xmlParseChunk(ctxt, buffer, 0, 1);
|
|
xs_warn( "document parsed \n");
|
|
}
|
|
|
|
ctxt->directory = NULL;
|
|
xmlFree(ctxt->sax);
|
|
ctxt->sax = NULL;
|
|
xmlFree(sax);
|
|
PmmSAXCloseContext(ctxt);
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
LibXML_cleanup_parser();
|
|
REPORT_ERROR(recover);
|
|
|
|
SV*
|
|
_parse_file(self, filename_sv)
|
|
SV * self
|
|
SV * filename_sv
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * filename;
|
|
HV * real_obj;
|
|
int well_formed;
|
|
int valid;
|
|
int validate;
|
|
xmlDocPtr real_doc;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
filename = SvPV(filename_sv, len);
|
|
if (len <= 0) {
|
|
croak("Empty filename\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
|
|
{
|
|
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(1);
|
|
croak("Could not create file parser context for file \"%s\": %s\n",
|
|
filename, strerror(errno));
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
ctxt->_private = (void*)self;
|
|
|
|
xs_warn( "context initialized\n" );
|
|
xmlParseDocument(ctxt);
|
|
xs_warn( "document parsed \n");
|
|
|
|
well_formed = ctxt->wellFormed;
|
|
valid = ctxt->valid;
|
|
validate = ctxt->validate;
|
|
real_doc = ctxt->myDoc;
|
|
ctxt->myDoc = NULL;
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
|
|
if ( real_doc != NULL ) {
|
|
if ( ! LibXML_will_die_ctx(saved_error, recover) &&
|
|
(recover || ( well_formed &&
|
|
( !validate
|
|
|| ( valid || ( real_doc->intSubset == NULL
|
|
&& real_doc->extSubset == NULL )))))) {
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
} else {
|
|
xmlFreeDoc(real_doc);
|
|
real_doc=NULL;
|
|
}
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_parse_sax_file(self, filename_sv)
|
|
SV * self
|
|
SV * filename_sv
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * filename;
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
filename = SvPV(filename_sv, len);
|
|
if (len <= 0) {
|
|
croak("Empty filename\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
{
|
|
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover ? recover : 1);
|
|
croak("Could not create file parser context for file \"%s\": %s\n",
|
|
filename, strerror(errno));
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self, ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
ctxt->sax = PSaxGetHandler();
|
|
PmmSAXInitContext( ctxt, self, saved_error );
|
|
xs_warn( "context initialized \n");
|
|
|
|
{
|
|
xmlParseDocument(ctxt);
|
|
xs_warn( "document parsed \n");
|
|
}
|
|
|
|
PmmSAXCloseContext(ctxt);
|
|
xmlFreeParserCtxt(ctxt);
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
|
|
SV*
|
|
_parse_html_string(self, string, svURL, svEncoding, options = 0)
|
|
SV * self
|
|
SV * string
|
|
SV * svURL
|
|
SV * svEncoding
|
|
int options
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * ptr;
|
|
char* URL = NULL;
|
|
const char * encoding = NULL;
|
|
HV * real_obj;
|
|
htmlDocPtr real_doc;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
/* If string is a reference to a string - dereference it.
|
|
* See: https://rt.cpan.org/Ticket/Display.html?id=64051 (broke it)
|
|
* https://rt.cpan.org/Ticket/Display.html?id=77864 (fixed it) */
|
|
if (SvROK(string) && !SvOBJECT(SvRV(string))) {
|
|
string = SvRV(string);
|
|
}
|
|
ptr = SvPV(string, len);
|
|
if (len <= 0) {
|
|
croak("Empty string\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if (SvOK(svURL))
|
|
URL = SvPV_nolen( svURL );
|
|
if (SvOK(svEncoding))
|
|
encoding = SvPV_nolen( svEncoding );
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
if (encoding == NULL && SvUTF8( string )) {
|
|
encoding = "UTF-8";
|
|
}
|
|
if (options & HTML_PARSE_RECOVER) {
|
|
recover = ((options & HTML_PARSE_NOERROR) ? 2 : 1);
|
|
}
|
|
#if LIBXML_VERSION >= 20627
|
|
real_doc = htmlReadDoc((xmlChar*)ptr, URL, encoding, options);
|
|
#else
|
|
real_doc = htmlParseDoc((xmlChar*)ptr, encoding);
|
|
if ( real_doc ) {
|
|
if (real_doc->URL) xmlFree((xmlChar *)real_doc->URL);
|
|
if (URL) {
|
|
real_doc->URL = xmlStrdup((const xmlChar*) URL);
|
|
}
|
|
}
|
|
#endif
|
|
if ( real_doc ) {
|
|
if (URL==NULL) {
|
|
SV * newURI = sv_2mortal(newSVpvf("unknown-%p", (void*)real_doc));
|
|
real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
|
|
}
|
|
/* This HTML memory parser doesn't use a ctxt; there is no "well-formed"
|
|
* distinction, and if it manages to parse the HTML, it returns non-null. */
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
_parse_html_file(self, filename_sv, svURL, svEncoding, options = 0)
|
|
SV * self
|
|
SV * filename_sv
|
|
SV * svURL
|
|
SV * svEncoding
|
|
int options
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * filename;
|
|
char * URL = NULL;
|
|
char * encoding = NULL;
|
|
HV * real_obj;
|
|
htmlDocPtr real_doc;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
filename = SvPV(filename_sv, len);
|
|
if (len <= 0) {
|
|
croak("Empty filename\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if (SvOK(svURL))
|
|
URL = SvPV_nolen( svURL );
|
|
if (SvOK(svEncoding))
|
|
encoding = SvPV_nolen( svEncoding );
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
if (options & HTML_PARSE_RECOVER) {
|
|
recover = ((options & HTML_PARSE_NOERROR) ? 2 : 1);
|
|
}
|
|
#if LIBXML_VERSION >= 20627
|
|
real_doc = htmlReadFile((const char *)filename,
|
|
encoding,
|
|
options);
|
|
#else
|
|
real_doc = htmlParseFile((const char *)filename, encoding);
|
|
#endif
|
|
if ( real_doc != NULL ) {
|
|
|
|
/* This HTML file parser doesn't use a ctxt; there is no "well-formed"
|
|
* distinction, and if it manages to parse the HTML, it returns non-null. */
|
|
if (URL) {
|
|
if (real_doc->URL) xmlFree((xmlChar*) real_doc->URL);
|
|
real_doc->URL = xmlStrdup((const xmlChar*) URL);
|
|
}
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
LibXML_cleanup_parser();
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_parse_html_fh(self, fh, svURL, svEncoding, options = 0)
|
|
SV * self
|
|
SV * fh
|
|
SV * svURL
|
|
SV * svEncoding
|
|
int options
|
|
PREINIT:
|
|
HV * real_obj;
|
|
htmlDocPtr real_doc;
|
|
int recover = 0;
|
|
char * URL = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
#if LIBXML_VERSION >= 20627
|
|
char * encoding = NULL;
|
|
#else
|
|
xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
|
|
#endif
|
|
INIT:
|
|
if (SvOK(svURL))
|
|
URL = SvPV_nolen( svURL );
|
|
#if LIBXML_VERSION >= 20627
|
|
if (SvOK(svEncoding))
|
|
encoding = SvPV_nolen( svEncoding );
|
|
#else
|
|
if (SvOK(svEncoding))
|
|
enc = xmlParseCharEncoding(SvPV_nolen( svEncoding ));
|
|
#endif
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
if (options & HTML_PARSE_RECOVER) {
|
|
recover = ((options & HTML_PARSE_NOERROR) ? 2 : 1);
|
|
}
|
|
#if LIBXML_VERSION >= 20627
|
|
|
|
real_doc = htmlReadIO((xmlInputReadCallback) LibXML_read_perl,
|
|
NULL,
|
|
(void *) fh,
|
|
URL,
|
|
encoding,
|
|
options);
|
|
#else /* LIBXML_VERSION >= 20627 */
|
|
{
|
|
int read_length;
|
|
int well_formed;
|
|
char buffer[1024];
|
|
htmlParserCtxtPtr ctxt;
|
|
|
|
read_length = LibXML_read_perl(fh, buffer, 4);
|
|
if (read_length <= 0) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
croak( "Empty Stream\n" );
|
|
}
|
|
ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length,
|
|
URL, enc);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover ? recover : 1);
|
|
croak("Could not create html push parser context!\n");
|
|
}
|
|
ctxt->_private = (void*)self;
|
|
{
|
|
int ret;
|
|
while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
|
|
ret = htmlParseChunk(ctxt, buffer, read_length, 0);
|
|
if ( ret != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
ret = htmlParseChunk(ctxt, buffer, 0, 1);
|
|
}
|
|
well_formed = ctxt->wellFormed;
|
|
real_doc = ctxt->myDoc;
|
|
ctxt->myDoc = NULL;
|
|
htmlFreeParserCtxt(ctxt);
|
|
}
|
|
#endif /* LIBXML_VERSION >= 20627 */
|
|
if ( real_doc != NULL ) {
|
|
if (real_doc->URL) xmlFree((xmlChar*) real_doc->URL);
|
|
if (URL) {
|
|
real_doc->URL = xmlStrdup((const xmlChar*) URL);
|
|
} else {
|
|
SV * newURI = sv_2mortal(newSVpvf("unknown-%p", (void*)real_doc));
|
|
real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
|
|
}
|
|
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_parse_xml_chunk(self, svchunk, enc = &PL_sv_undef)
|
|
SV * self
|
|
SV * svchunk
|
|
SV * enc
|
|
PREINIT:
|
|
STRLEN len;
|
|
const char * encoding = "UTF-8";
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
xmlChar * chunk;
|
|
xmlNodePtr rv = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if (SvPOK(enc)) {
|
|
encoding = SvPV(enc, len);
|
|
if (len <= 0) {
|
|
encoding = "UTF-8";
|
|
}
|
|
}
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
|
|
chunk = Sv2C(svchunk, (const xmlChar*)encoding);
|
|
|
|
if ( chunk != NULL ) {
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
rv = domReadWellBalancedString( NULL, chunk, recover );
|
|
|
|
if ( rv != NULL ) {
|
|
xmlNodePtr fragment= NULL;
|
|
xmlNodePtr rv_end = NULL;
|
|
|
|
/* now we append the nodelist to a document
|
|
fragment which is unbound to a Document!!!! */
|
|
|
|
/* step 1: create the fragment */
|
|
fragment = xmlNewDocFragment( NULL );
|
|
RETVAL = LibXML_NodeToSv(real_obj, fragment);
|
|
|
|
/* step 2: set the node list to the fragment */
|
|
fragment->children = rv;
|
|
rv_end = rv;
|
|
while ( rv_end->next != NULL ) {
|
|
rv_end->parent = fragment;
|
|
rv_end = rv_end->next;
|
|
}
|
|
/* the following line is important, otherwise we'll have
|
|
occasional segmentation faults
|
|
*/
|
|
rv_end->parent = fragment;
|
|
fragment->last = rv_end;
|
|
}
|
|
|
|
/* free the chunk we created */
|
|
xmlFree( chunk );
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
|
|
if (rv == NULL) {
|
|
croak("_parse_xml_chunk: chunk parsing failed\n");
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_parse_sax_xml_chunk(self, svchunk, enc = &PL_sv_undef)
|
|
SV * self
|
|
SV * svchunk
|
|
SV * enc
|
|
PREINIT:
|
|
STRLEN len;
|
|
char * ptr;
|
|
const char * encoding = "UTF-8";
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
xmlChar * chunk;
|
|
int retCode = -1;
|
|
xmlNodePtr nodes = NULL;
|
|
xmlSAXHandlerPtr handler = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if (SvPOK(enc)) {
|
|
encoding = SvPV(enc, len);
|
|
if (len <= 0) {
|
|
encoding = "UTF-8";
|
|
}
|
|
}
|
|
ptr = SvPV(svchunk, len);
|
|
if (len <= 0) {
|
|
croak("Empty string\n");
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
chunk = Sv2C(svchunk, (const xmlChar*)encoding);
|
|
|
|
if ( chunk != NULL ) {
|
|
xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
|
|
if (ctxt == NULL) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover ? recover : 1);
|
|
croak("Could not create memory parser context!\n");
|
|
}
|
|
xs_warn( "context created\n");
|
|
real_obj = LibXML_init_parser(self,ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
PmmSAXInitContext( ctxt, self, saved_error );
|
|
handler = PSaxGetHandler();
|
|
|
|
retCode = xmlParseBalancedChunkMemory( NULL,
|
|
handler,
|
|
ctxt,
|
|
0,
|
|
chunk,
|
|
&nodes );
|
|
|
|
xmlFree( handler );
|
|
PmmSAXCloseContext(ctxt);
|
|
xmlFreeParserCtxt(ctxt);
|
|
|
|
/* free the chunk we created */
|
|
xmlFree( chunk );
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
|
|
if (retCode == -1) {
|
|
croak("_parse_sax_xml_chunk: chunk parsing failed\n");
|
|
}
|
|
|
|
int
|
|
_processXIncludes(self, doc, options=0)
|
|
SV * self
|
|
SV * doc
|
|
int options
|
|
PREINIT:
|
|
xmlDocPtr real_doc;
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
real_doc = (xmlDocPtr) PmmSvNode(doc);
|
|
if (real_doc == NULL) {
|
|
croak("No document to process!\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = 0;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
RETVAL = xmlXIncludeProcessFlags(real_doc,options);
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
|
|
if ( RETVAL < 0 ) {
|
|
croak( "unknown error during XInclude processing\n" );
|
|
XSRETURN_UNDEF;
|
|
} else if ( RETVAL == 0 ) {
|
|
RETVAL = 1;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_start_push(self, with_sax=0)
|
|
SV * self
|
|
int with_sax
|
|
PREINIT:
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
xmlParserCtxtPtr ctxt = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
|
|
/* create empty context */
|
|
ctxt = xmlCreatePushParserCtxt( NULL, NULL, NULL, 0, NULL );
|
|
real_obj = LibXML_init_parser(self,ctxt);
|
|
recover = LibXML_get_recover(real_obj);
|
|
if ( with_sax == 1 ) {
|
|
PmmSAXInitContext( ctxt, self, saved_error );
|
|
}
|
|
|
|
RETVAL = PmmContextSv( ctxt );
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_push(self, pctxt, data)
|
|
SV * self
|
|
SV * pctxt
|
|
SV * data
|
|
PREINIT:
|
|
HV * real_obj;
|
|
int recover = 0;
|
|
xmlParserCtxtPtr ctxt = NULL;
|
|
STRLEN len = 0;
|
|
char * chunk = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ctxt = PmmSvContext( pctxt );
|
|
if ( ctxt == NULL ) {
|
|
croak( "parser context already freed\n" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( data == &PL_sv_undef ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
chunk = SvPV( data, len );
|
|
if ( len <= 0 ) {
|
|
xs_warn( "empty string" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = 0;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
recover = LibXML_get_recover(real_obj);
|
|
|
|
xmlParseChunk(ctxt, (const char *)chunk, len, 0);
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(recover);
|
|
|
|
if ( ctxt->wellFormed == 0 ) {
|
|
croak( "XML not well-formed in xmlParseChunk\n" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = 1;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_end_push(self, pctxt, restore)
|
|
SV * self
|
|
SV * pctxt
|
|
int restore
|
|
PREINIT:
|
|
HV * real_obj;
|
|
int well_formed;
|
|
xmlParserCtxtPtr ctxt = NULL;
|
|
xmlDocPtr real_doc = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ctxt = PmmSvContext( pctxt );
|
|
if ( ctxt == NULL ) {
|
|
croak( "parser context already freed\n" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
|
|
xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
|
|
xs_warn( "Finished with push parser\n" );
|
|
|
|
well_formed = ctxt->wellFormed;
|
|
real_doc = ctxt->myDoc;
|
|
ctxt->myDoc = NULL;
|
|
xmlFreeParserCtxt(ctxt);
|
|
PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
|
|
|
|
if ( real_doc != NULL ) {
|
|
if ( restore || well_formed ) {
|
|
RETVAL = LibXML_NodeToSv( real_obj, INT2PTR(xmlNodePtr,real_doc) );
|
|
} else {
|
|
xmlFreeDoc(real_doc);
|
|
real_doc = NULL;
|
|
}
|
|
}
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(restore);
|
|
|
|
if ( real_doc == NULL ){
|
|
croak( "no document found!\n" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_end_sax_push(self, pctxt)
|
|
SV * self
|
|
SV * pctxt
|
|
PREINIT:
|
|
HV * real_obj;
|
|
xmlParserCtxtPtr ctxt = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ctxt = PmmSvContext( pctxt );
|
|
if ( ctxt == NULL ) {
|
|
croak( "parser context already freed\n" );
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
real_obj = LibXML_init_parser(self,NULL);
|
|
|
|
xmlParseChunk(ctxt, "", 0, 1); /* finish the parse */
|
|
xs_warn( "Finished with SAX push parser\n" );
|
|
|
|
xmlFree(ctxt->sax);
|
|
ctxt->sax = NULL;
|
|
PmmSAXCloseContext(ctxt);
|
|
xmlFreeParserCtxt(ctxt);
|
|
PmmNODE( SvPROXYNODE( pctxt ) ) = NULL;
|
|
|
|
LibXML_cleanup_parser();
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
|
|
SV*
|
|
import_GDOME( CLASS, sv_gdome, deep=1 )
|
|
SV * sv_gdome
|
|
int deep
|
|
PREINIT:
|
|
xmlNodePtr node = NULL;
|
|
INIT:
|
|
RETVAL = &PL_sv_undef;
|
|
#ifndef XML_LIBXML_GDOME_SUPPORT
|
|
croak( "GDOME Support not compiled" );
|
|
#endif
|
|
if ( sv_gdome == NULL || sv_gdome == &PL_sv_undef ) {
|
|
croak( "no XML::GDOME data found" );
|
|
}
|
|
#ifdef XML_LIBXML_GDOME_SUPPORT
|
|
else {
|
|
GdomeNode* gnode = NULL;
|
|
gnode = (GdomeNode*)SvIV((SV*)SvRV( sv_gdome ));
|
|
if ( gnode == NULL ) {
|
|
croak( "no XML::GDOME data found (datastructure empty)" );
|
|
}
|
|
|
|
node = gdome_xml_n_get_xmlNode( gnode );
|
|
if ( node == NULL ) {
|
|
croak( "no XML::LibXML node found in GDOME object" );
|
|
}
|
|
}
|
|
#endif
|
|
CODE:
|
|
if ( node->type == XML_NAMESPACE_DECL ) {
|
|
const char * CLASS = "XML::LibXML::Namespace";
|
|
RETVAL = NEWSV(0,0);
|
|
RETVAL = sv_setref_pv( RETVAL,
|
|
CLASS,
|
|
(void*)xmlCopyNamespace((xmlNsPtr)node) );
|
|
}
|
|
else {
|
|
RETVAL = PmmNodeToSv( PmmCloneNode( node, deep ), NULL );
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
export_GDOME( CLASS, sv_libxml, deep=1 )
|
|
SV * sv_libxml
|
|
int deep
|
|
PREINIT:
|
|
xmlNodePtr node = NULL, retnode = NULL;
|
|
INIT:
|
|
RETVAL = &PL_sv_undef;
|
|
#ifndef XML_LIBXML_GDOME_SUPPORT
|
|
croak( "GDOME Support not configured!" );
|
|
#endif
|
|
if ( sv_libxml == NULL || sv_libxml == &PL_sv_undef ) {
|
|
croak( "no XML::LibXML data found" );
|
|
}
|
|
node = PmmSvNode( sv_libxml );
|
|
if ( node == NULL ) {
|
|
croak( "no XML::LibXML data found (empty structure)" );
|
|
}
|
|
CODE:
|
|
retnode = PmmCloneNode( node, deep );
|
|
if ( retnode == NULL ) {
|
|
croak( "Copy node failed" );
|
|
}
|
|
|
|
RETVAL = PmmNodeToGdomeSv( retnode );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
load_catalog( self, filename )
|
|
SV * filename
|
|
PREINIT:
|
|
const char * fn = (const char *) Sv2C(filename, NULL);
|
|
INIT:
|
|
if ( fn == NULL || xmlStrlen( (xmlChar *)fn ) == 0 ) {
|
|
croak( "cannot load catalog" );
|
|
}
|
|
CODE:
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
RETVAL = xmlLoadCatalog( fn );
|
|
#else
|
|
XSRETURN_UNDEF;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
|
|
int
|
|
_default_catalog( self, catalog )
|
|
SV * catalog
|
|
PREINIT:
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
xmlCatalogPtr catal = INT2PTR(xmlCatalogPtr,SvIV(SvRV(catalog)));
|
|
#endif
|
|
INIT:
|
|
if ( catal == NULL ) {
|
|
croak( "empty catalog\n" );
|
|
}
|
|
CODE:
|
|
warn( "this feature is not implemented" );
|
|
RETVAL = 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_externalEntityLoader( loader )
|
|
SV* loader
|
|
CODE:
|
|
{
|
|
RETVAL = EXTERNAL_ENTITY_LOADER_FUNC;
|
|
if(EXTERNAL_ENTITY_LOADER_FUNC == NULL)
|
|
{
|
|
EXTERNAL_ENTITY_LOADER_FUNC = newSVsv(loader);
|
|
}
|
|
|
|
if (LibXML_old_ext_ent_loader == NULL )
|
|
{
|
|
LibXML_old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader((xmlExternalEntityLoader)LibXML_load_external_entity);
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::HashTable
|
|
|
|
xmlHashTablePtr
|
|
new(CLASS)
|
|
const char * CLASS
|
|
CODE:
|
|
RETVAL = xmlHashCreate(8);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY( table )
|
|
xmlHashTablePtr table
|
|
CODE:
|
|
xs_warn("DESTROY XMLHASHTABLE\n");
|
|
PmmFreeHashTable(table);
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::ParserContext
|
|
|
|
void
|
|
DESTROY( self )
|
|
SV * self
|
|
CODE:
|
|
xs_warn( "DROP PARSER CONTEXT!" );
|
|
PmmContextREFCNT_dec( SvPROXYNODE( self ) );
|
|
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Document
|
|
|
|
SV *
|
|
_toString(self, format=0)
|
|
xmlDocPtr self
|
|
int format
|
|
PREINIT:
|
|
xmlChar *result=NULL;
|
|
int len=0;
|
|
SV* internalFlag = NULL;
|
|
int oldTagFlag = xmlSaveNoEmptyTags;
|
|
xmlDtdPtr intSubset = NULL;
|
|
/* PREINIT_SAVED_ERROR */
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
|
|
if( internalFlag ) {
|
|
xmlSaveNoEmptyTags = SvTRUE(internalFlag);
|
|
}
|
|
|
|
internalFlag = get_sv("XML::LibXML::skipDTD", 0);
|
|
if ( internalFlag && SvTRUE(internalFlag) ) {
|
|
intSubset = xmlGetIntSubset( self );
|
|
if ( intSubset )
|
|
xmlUnlinkNode( INT2PTR(xmlNodePtr,intSubset) );
|
|
}
|
|
|
|
/* INIT_ERROR_HANDLER; */
|
|
|
|
if ( format <= 0 ) {
|
|
xs_warn( "use no formated toString!" );
|
|
xmlDocDumpMemory(self, &result, &len);
|
|
}
|
|
else {
|
|
int t_indent_var = xmlIndentTreeOutput;
|
|
xs_warn( "use formated toString!" );
|
|
xmlIndentTreeOutput = 1;
|
|
xmlDocDumpFormatMemory( self, &result, &len, format );
|
|
xmlIndentTreeOutput = t_indent_var;
|
|
}
|
|
|
|
if ( intSubset != NULL ) {
|
|
if (self->children == NULL) {
|
|
xmlAddChild(INT2PTR(xmlNodePtr,self), INT2PTR(xmlNodePtr,intSubset));
|
|
}
|
|
else {
|
|
xmlAddPrevSibling(self->children, INT2PTR(xmlNodePtr,intSubset));
|
|
}
|
|
}
|
|
|
|
xmlSaveNoEmptyTags = oldTagFlag;
|
|
|
|
/* REPORT_ERROR(0); */
|
|
|
|
if (result == NULL) {
|
|
xs_warn("Failed to convert doc to string");
|
|
XSRETURN_UNDEF;
|
|
} else {
|
|
/* warn("%s, %d\n",result, len); */
|
|
RETVAL = newSVpvn( (const char *)result, len );
|
|
/* C2Sv( result, self->encoding ); */
|
|
xmlFree(result);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
toFH( self, filehandler, format=0 )
|
|
xmlDocPtr self
|
|
SV * filehandler
|
|
int format
|
|
PREINIT:
|
|
xmlOutputBufferPtr buffer;
|
|
const xmlChar * encoding = NULL;
|
|
xmlCharEncodingHandlerPtr handler = NULL;
|
|
SV* internalFlag = NULL;
|
|
int oldTagFlag = xmlSaveNoEmptyTags;
|
|
xmlDtdPtr intSubset = NULL;
|
|
int t_indent_var = xmlIndentTreeOutput;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
|
|
if( internalFlag ) {
|
|
xmlSaveNoEmptyTags = SvTRUE(internalFlag);
|
|
}
|
|
|
|
internalFlag = get_sv("XML::LibXML::skipDTD", 0);
|
|
if ( internalFlag && SvTRUE(internalFlag) ) {
|
|
intSubset = xmlGetIntSubset( self );
|
|
if ( intSubset )
|
|
xmlUnlinkNode( INT2PTR(xmlNodePtr,intSubset) );
|
|
}
|
|
|
|
xmlRegisterDefaultOutputCallbacks();
|
|
encoding = (self)->encoding;
|
|
if ( encoding != NULL ) {
|
|
if ( xmlParseCharEncoding((const char*)encoding) != XML_CHAR_ENCODING_UTF8) {
|
|
handler = xmlFindCharEncodingHandler((const char*)encoding);
|
|
}
|
|
|
|
}
|
|
else {
|
|
xs_warn("no encoding?");
|
|
}
|
|
|
|
buffer = xmlOutputBufferCreateIO( (xmlOutputWriteCallback) &LibXML_output_write_handler,
|
|
(xmlOutputCloseCallback)&LibXML_output_close_handler,
|
|
filehandler,
|
|
handler );
|
|
|
|
if ( format <= 0 ) {
|
|
format = 0;
|
|
xmlIndentTreeOutput = 0;
|
|
}
|
|
else {
|
|
xmlIndentTreeOutput = 1;
|
|
}
|
|
|
|
INIT_ERROR_HANDLER;
|
|
|
|
RETVAL = xmlSaveFormatFileTo( buffer,
|
|
self,
|
|
(const char *) encoding,
|
|
format);
|
|
|
|
if ( intSubset != NULL ) {
|
|
if (self->children == NULL) {
|
|
xmlAddChild(INT2PTR(xmlNodePtr,self), INT2PTR(xmlNodePtr,intSubset));
|
|
}
|
|
else {
|
|
xmlAddPrevSibling(self->children, INT2PTR(xmlNodePtr,intSubset));
|
|
}
|
|
}
|
|
|
|
xmlIndentTreeOutput = t_indent_var;
|
|
xmlSaveNoEmptyTags = oldTagFlag;
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
toFile( self, filename, format=0 )
|
|
xmlDocPtr self
|
|
char * filename
|
|
int format
|
|
PREINIT:
|
|
SV* internalFlag = NULL;
|
|
int oldTagFlag = xmlSaveNoEmptyTags;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
|
|
if( internalFlag ) {
|
|
xmlSaveNoEmptyTags = SvTRUE(internalFlag);
|
|
}
|
|
|
|
INIT_ERROR_HANDLER;
|
|
|
|
if ( format <= 0 ) {
|
|
xs_warn( "use no formated toFile!" );
|
|
RETVAL = xmlSaveFile( filename, self );
|
|
}
|
|
else {
|
|
int t_indent_var = xmlIndentTreeOutput;
|
|
xmlIndentTreeOutput = 1;
|
|
RETVAL =xmlSaveFormatFile( filename,
|
|
self,
|
|
format);
|
|
xmlIndentTreeOutput = t_indent_var;
|
|
}
|
|
|
|
xmlSaveNoEmptyTags = oldTagFlag;
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
|
|
if ( RETVAL > 0 )
|
|
RETVAL = 1;
|
|
else
|
|
XSRETURN_UNDEF;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
toStringHTML(self)
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::serialize_html = 1
|
|
PREINIT:
|
|
xmlChar *result=NULL;
|
|
int len = 0;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
xs_warn( "use no formated toString!" );
|
|
INIT_ERROR_HANDLER;
|
|
htmlDocDumpMemory(self, &result, &len);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
|
|
if (result == NULL) {
|
|
XSRETURN_UNDEF;
|
|
} else {
|
|
/* warn("%s, %d\n",result, len); */
|
|
RETVAL = newSVpvn((char *)result, (STRLEN)len);
|
|
xmlFree(result);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
const char *
|
|
URI( self )
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::documentURI = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = (const char*)xmlStrdup(self->URL );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setURI( self, new_URI )
|
|
xmlDocPtr self
|
|
char * new_URI
|
|
CODE:
|
|
if (new_URI) {
|
|
xmlFree((xmlChar*)self->URL );
|
|
self->URL = xmlStrdup((const xmlChar*)new_URI);
|
|
}
|
|
|
|
SV*
|
|
createDocument( CLASS, version="1.0", encoding=NULL )
|
|
char * version
|
|
char * encoding
|
|
ALIAS:
|
|
XML::LibXML::Document::new = 1
|
|
PREINIT:
|
|
xmlDocPtr doc=NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
doc = xmlNewDoc((const xmlChar*)version);
|
|
if (encoding && *encoding != 0) {
|
|
doc->encoding = (const xmlChar*)xmlStrdup((const xmlChar*)encoding);
|
|
}
|
|
RETVAL = PmmNodeToSv(INT2PTR(xmlNodePtr,doc),NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createInternalSubset( self, Pname, extID, sysID )
|
|
xmlDocPtr self
|
|
SV * Pname
|
|
SV * extID
|
|
SV * sysID
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
xmlChar * name = NULL;
|
|
xmlChar * externalID = NULL;
|
|
xmlChar * systemID = NULL;
|
|
CODE:
|
|
name = Sv2C( Pname, NULL );
|
|
if ( name == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
externalID = Sv2C(extID, NULL);
|
|
systemID = Sv2C(sysID, NULL);
|
|
|
|
dtd = xmlCreateIntSubset( self, name, externalID, systemID );
|
|
xmlFree(externalID);
|
|
xmlFree(systemID);
|
|
xmlFree(name);
|
|
if ( dtd ) {
|
|
RETVAL = PmmNodeToSv( INT2PTR(xmlNodePtr,dtd), PmmPROXYNODE(self) );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createExternalSubset( self, Pname, extID, sysID )
|
|
xmlDocPtr self
|
|
SV * Pname
|
|
SV * extID
|
|
SV * sysID
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
xmlChar * name = NULL;
|
|
xmlChar * externalID = NULL;
|
|
xmlChar * systemID = NULL;
|
|
CODE:
|
|
name = Sv2C( Pname, NULL );
|
|
if ( name == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
externalID = Sv2C(extID, NULL);
|
|
systemID = Sv2C(sysID, NULL);
|
|
|
|
dtd = xmlNewDtd( self, name, externalID, systemID );
|
|
|
|
xmlFree(externalID);
|
|
xmlFree(systemID);
|
|
xmlFree(name);
|
|
if ( dtd ) {
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createDTD( self, Pname, extID, sysID )
|
|
xmlDocPtr self
|
|
SV * Pname
|
|
SV * extID
|
|
SV * sysID
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
xmlChar * name = NULL;
|
|
xmlChar * externalID = NULL;
|
|
xmlChar * systemID = NULL;
|
|
CODE:
|
|
name = Sv2C( Pname, NULL );
|
|
if ( name == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
externalID = Sv2C(extID, NULL);
|
|
systemID = Sv2C(sysID, NULL);
|
|
|
|
dtd = xmlNewDtd( NULL, name, externalID, systemID );
|
|
dtd->doc = self;
|
|
|
|
xmlFree(externalID);
|
|
xmlFree(systemID);
|
|
xmlFree(name);
|
|
if ( dtd ) {
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createDocumentFragment( self )
|
|
xmlDocPtr self
|
|
CODE:
|
|
RETVAL = PmmNodeToSv(xmlNewDocFragment(self), PmmPROXYNODE(self));
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createElement( self, name )
|
|
xmlDocPtr self
|
|
SV* name
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * elname = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
elname = nodeSv2C( name , (xmlNodePtr) self);
|
|
if ( !LibXML_test_node_name( elname ) ) {
|
|
xmlFree( elname );
|
|
croak( "bad name" );
|
|
}
|
|
|
|
newNode = xmlNewNode(NULL , elname);
|
|
xmlFree(elname);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
newNode->doc = self;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createRawElement( self, name )
|
|
xmlDocPtr self
|
|
SV* name
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * elname = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
elname = nodeSv2C( name , (xmlNodePtr) self);
|
|
if ( !elname || xmlStrlen(elname) <= 0 ) {
|
|
xmlFree( elname );
|
|
croak( "bad name" );
|
|
}
|
|
|
|
newNode = xmlNewDocNode(self,NULL , elname, NULL);
|
|
xmlFree(elname);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createElementNS( self, nsURI, name )
|
|
xmlDocPtr self
|
|
SV * nsURI
|
|
SV * name
|
|
PREINIT:
|
|
xmlChar * ename = NULL;
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * eURI = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
xmlNodePtr newNode = NULL;
|
|
CODE:
|
|
ename = nodeSv2C( name , (xmlNodePtr) self );
|
|
if ( !LibXML_test_node_name( ename ) ) {
|
|
xmlFree( ename );
|
|
croak( "bad name" );
|
|
}
|
|
|
|
eURI = Sv2C( nsURI , NULL );
|
|
|
|
if ( eURI != NULL && xmlStrlen(eURI)!=0 ){
|
|
localname = xmlSplitQName2(ename, &prefix);
|
|
if ( localname == NULL ) {
|
|
localname = xmlStrdup( ename );
|
|
}
|
|
|
|
ns = xmlNewNs( NULL, eURI, prefix );
|
|
newNode = xmlNewDocNode( self, ns, localname, NULL );
|
|
newNode->nsDef = ns;
|
|
|
|
xmlFree(localname);
|
|
}
|
|
else {
|
|
xs_warn( " ordinary element " );
|
|
/* ordinary element */
|
|
localname = ename;
|
|
|
|
newNode = xmlNewDocNode( self, NULL , localname, NULL );
|
|
}
|
|
|
|
docfrag = PmmNewFragment( self );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode, docfrag);
|
|
|
|
if ( prefix != NULL ) {
|
|
xmlFree(prefix);
|
|
}
|
|
if ( eURI != NULL ) {
|
|
xmlFree(eURI);
|
|
}
|
|
xmlFree(ename);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createRawElementNS( self, nsURI, name )
|
|
xmlDocPtr self
|
|
SV * nsURI
|
|
SV * name
|
|
PREINIT:
|
|
xmlChar * ename = NULL;
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * eURI = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
xmlNodePtr newNode = NULL;
|
|
CODE:
|
|
ename = nodeSv2C( name , (xmlNodePtr) self );
|
|
if ( !LibXML_test_node_name( ename ) ) {
|
|
xmlFree( ename );
|
|
croak( "bad name" );
|
|
}
|
|
|
|
eURI = Sv2C( nsURI , NULL );
|
|
|
|
if ( eURI != NULL && xmlStrlen(eURI)!=0 ){
|
|
localname = xmlSplitQName2(ename, &prefix);
|
|
if ( localname == NULL ) {
|
|
localname = xmlStrdup( ename );
|
|
}
|
|
|
|
newNode = xmlNewDocNode( self,NULL , localname, NULL );
|
|
|
|
ns = xmlSearchNsByHref( self, newNode, eURI );
|
|
if ( ns == NULL ) {
|
|
/* create a new NS if the NS does not already exists */
|
|
ns = xmlNewNs(newNode, eURI , prefix );
|
|
}
|
|
|
|
if ( ns == NULL ) {
|
|
xmlFreeNode( newNode );
|
|
xmlFree(eURI);
|
|
xmlFree(localname);
|
|
if ( prefix != NULL ) {
|
|
xmlFree(prefix);
|
|
}
|
|
xmlFree(ename);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
xmlFree(localname);
|
|
}
|
|
else {
|
|
xs_warn( " ordinary element " );
|
|
/* ordinary element */
|
|
localname = ename;
|
|
|
|
newNode = xmlNewDocNode( self, NULL , localname, NULL );
|
|
}
|
|
|
|
xmlSetNs(newNode, ns);
|
|
docfrag = PmmNewFragment( self );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode, docfrag);
|
|
|
|
if ( prefix != NULL ) {
|
|
xmlFree(prefix);
|
|
}
|
|
if ( eURI != NULL ) {
|
|
xmlFree(eURI);
|
|
}
|
|
xmlFree(ename);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
createTextNode( self, content )
|
|
xmlDocPtr self
|
|
SV * content
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * elname = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
elname = nodeSv2C( content , (xmlNodePtr) self );
|
|
if ( elname != NULL || xmlStrlen(elname) > 0 ) {
|
|
newNode = xmlNewDocText( self, elname );
|
|
xmlFree(elname);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
newNode->doc = self;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
createComment( self , content )
|
|
xmlDocPtr self
|
|
SV * content
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * elname = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
elname = nodeSv2C( content , (xmlNodePtr) self );
|
|
if ( elname != NULL || xmlStrlen(elname) > 0 ) {
|
|
newNode = xmlNewDocComment( self, elname );
|
|
xmlFree(elname);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
newNode->doc = self;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
xs_warn( newNode->name );
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
createCDATASection( self, content )
|
|
xmlDocPtr self
|
|
SV * content
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * elname = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
elname = nodeSv2C( content , (xmlNodePtr)self );
|
|
if ( elname != NULL || xmlStrlen(elname) > 0 ) {
|
|
newNode = xmlNewCDataBlock( self, elname, xmlStrlen(elname) );
|
|
xmlFree(elname);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
newNode->doc = self;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
xs_warn( "[CDATA section]" );
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createEntityReference( self , pname )
|
|
xmlDocPtr self
|
|
SV * pname
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
xmlChar * name = Sv2C( pname, NULL );
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
if ( name == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
newNode = xmlNewReference( self, name );
|
|
xmlFree(name);
|
|
if ( newNode == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
docfrag = PmmNewFragment( self );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv( newNode, docfrag );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createAttribute( self, pname, pvalue=&PL_sv_undef )
|
|
xmlDocPtr self
|
|
SV * pname
|
|
SV * pvalue
|
|
PREINIT:
|
|
xmlChar * name = NULL;
|
|
xmlChar * value = NULL;
|
|
xmlAttrPtr newAttr = NULL;
|
|
xmlChar * buffer = NULL;
|
|
CODE:
|
|
name = nodeSv2C( pname , (xmlNodePtr) self );
|
|
if ( !LibXML_test_node_name( name ) ) {
|
|
xmlFree(name);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
value = nodeSv2C( pvalue , (xmlNodePtr) self );
|
|
/* unlike xmlSetProp, xmlNewDocProp does not encode entities in value */
|
|
buffer = xmlEncodeEntitiesReentrant(self, value);
|
|
newAttr = xmlNewDocProp( self, name, buffer );
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)newAttr, PmmPROXYNODE(self));
|
|
|
|
xmlFree(name);
|
|
xmlFree(buffer);
|
|
if ( value ) {
|
|
xmlFree(value);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createAttributeNS( self, URI, pname, pvalue=&PL_sv_undef )
|
|
xmlDocPtr self
|
|
SV * URI
|
|
SV * pname
|
|
SV * pvalue
|
|
PREINIT:
|
|
xmlChar * name = NULL;
|
|
xmlChar * value = NULL;
|
|
xmlChar * prefix = NULL;
|
|
const xmlChar * pchar = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * nsURI = NULL;
|
|
xmlAttrPtr newAttr = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
CODE:
|
|
name = nodeSv2C( pname , (xmlNodePtr) self );
|
|
if ( !LibXML_test_node_name( name ) ) {
|
|
xmlFree(name);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
nsURI = Sv2C( URI , NULL );
|
|
value = nodeSv2C( pvalue, (xmlNodePtr) self );
|
|
|
|
if ( nsURI != NULL && xmlStrlen(nsURI) > 0 ) {
|
|
xmlNodePtr root = xmlDocGetRootElement(self );
|
|
if ( root ) {
|
|
pchar = xmlStrchr(name, ':');
|
|
if ( pchar != NULL ) {
|
|
localname = xmlSplitQName2(name, &prefix);
|
|
}
|
|
else {
|
|
localname = xmlStrdup( name );
|
|
}
|
|
ns = xmlSearchNsByHref( self, root, nsURI );
|
|
if ( ns == NULL ) {
|
|
/* create a new NS if the NS does not already exists */
|
|
ns = xmlNewNs(root, nsURI , prefix );
|
|
}
|
|
|
|
if ( ns == NULL ) {
|
|
xmlFree(nsURI);
|
|
xmlFree(localname);
|
|
if ( prefix ) {
|
|
xmlFree(prefix);
|
|
}
|
|
xmlFree(name);
|
|
if ( value ) {
|
|
xmlFree(value);
|
|
}
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
newAttr = xmlNewDocProp( self, localname, value );
|
|
xmlSetNs((xmlNodePtr)newAttr, ns);
|
|
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)newAttr, PmmPROXYNODE(self) );
|
|
|
|
xmlFree(nsURI);
|
|
xmlFree(name);
|
|
if ( prefix ) {
|
|
xmlFree(prefix);
|
|
}
|
|
xmlFree(localname);
|
|
if ( value ) {
|
|
xmlFree(value);
|
|
}
|
|
}
|
|
else {
|
|
croak( "can't create a new namespace on an attribute!" );
|
|
xmlFree(name);
|
|
if ( value ) {
|
|
xmlFree(value);
|
|
}
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
xmlChar *buffer;
|
|
/* unlike xmlSetProp, xmlNewDocProp does not encode entities in value */
|
|
buffer = xmlEncodeEntitiesReentrant(self, value);
|
|
newAttr = xmlNewDocProp( self, name, buffer );
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)newAttr,PmmPROXYNODE(self));
|
|
xmlFree(name);
|
|
xmlFree(buffer);
|
|
if ( value ) {
|
|
xmlFree(value);
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
createProcessingInstruction(self, name, value=&PL_sv_undef)
|
|
xmlDocPtr self
|
|
SV * name
|
|
SV * value
|
|
ALIAS:
|
|
createPI = 1
|
|
PREINIT:
|
|
xmlChar * n = NULL;
|
|
xmlChar * v = NULL;
|
|
xmlNodePtr newNode = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
n = nodeSv2C(name, (xmlNodePtr)self);
|
|
if ( !n ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
v = nodeSv2C(value, (xmlNodePtr)self);
|
|
newNode = xmlNewPI(n,v);
|
|
xmlFree(v);
|
|
xmlFree(n);
|
|
if ( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( self );
|
|
newNode->doc = self;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
} else {
|
|
xs_warn( "no node created!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_setDocumentElement( self , proxy )
|
|
xmlDocPtr self
|
|
SV * proxy
|
|
PREINIT:
|
|
xmlNodePtr elem, oelem;
|
|
INIT:
|
|
elem = PmmSvNode(proxy);
|
|
if ( elem == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
/* please correct me if i am wrong: the document element HAS to be
|
|
* an ELEMENT NODE
|
|
*/
|
|
if ( elem->type == XML_ELEMENT_NODE ) {
|
|
if ( self != elem->doc ) {
|
|
domImportNode( self, elem, 1, 1 );
|
|
}
|
|
|
|
oelem = xmlDocGetRootElement( self );
|
|
if ( oelem == NULL || oelem->_private == NULL ) {
|
|
xmlDocSetRootElement( self, elem );
|
|
}
|
|
else {
|
|
ProxyNodePtr docfrag = PmmNewFragment( self );
|
|
xmlReplaceNode( oelem, elem );
|
|
xmlAddChild( PmmNODE(docfrag), oelem );
|
|
PmmFixOwner( ((ProxyNodePtr)oelem->_private), docfrag);
|
|
}
|
|
|
|
if ( elem->_private != NULL ) {
|
|
PmmFixOwner( SvPROXYNODE(proxy), PmmPROXYNODE(self));
|
|
}
|
|
} else {
|
|
croak("setDocumentElement: ELEMENT node required");
|
|
}
|
|
|
|
SV *
|
|
documentElement( self )
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::getDocumentElement = 1
|
|
PREINIT:
|
|
xmlNodePtr elem;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
elem = xmlDocGetRootElement( self );
|
|
if ( elem ) {
|
|
RETVAL = PmmNodeToSv(elem, PmmPROXYNODE(self));
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
externalSubset( self )
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlDtdPtr dtd;
|
|
CODE:
|
|
if ( self->extSubset == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
dtd = self->extSubset;
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)dtd, PmmPROXYNODE(self));
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
internalSubset( self )
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlDtdPtr dtd;
|
|
CODE:
|
|
if ( self->intSubset == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
dtd = self->intSubset;
|
|
RETVAL = PmmNodeToSv(INT2PTR(xmlNodePtr,dtd), PmmPROXYNODE(self));
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setExternalSubset( self, extdtd )
|
|
xmlDocPtr self
|
|
SV * extdtd
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
xmlDtdPtr olddtd = NULL;
|
|
INIT:
|
|
dtd = (xmlDtdPtr)PmmSvNode(extdtd);
|
|
if ( dtd == NULL ) {
|
|
croak( "lost DTD node" );
|
|
}
|
|
CODE:
|
|
if ( dtd && dtd != self->extSubset ) {
|
|
if ( dtd->doc == NULL ) {
|
|
xmlSetTreeDoc( (xmlNodePtr) dtd, self );
|
|
} else if ( dtd->doc != self ) {
|
|
domImportNode( self, (xmlNodePtr) dtd,1,1);
|
|
}
|
|
|
|
if ( dtd == self->intSubset ) {
|
|
xmlUnlinkNode( (xmlNodePtr)dtd );
|
|
self->intSubset = NULL;
|
|
}
|
|
|
|
olddtd = self->extSubset;
|
|
if ( olddtd && olddtd->_private == NULL ) {
|
|
xmlFreeDtd( olddtd );
|
|
}
|
|
self->extSubset = dtd;
|
|
}
|
|
|
|
void
|
|
setInternalSubset( self, extdtd )
|
|
xmlDocPtr self
|
|
SV * extdtd
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
xmlDtdPtr olddtd = NULL;
|
|
INIT:
|
|
dtd = (xmlDtdPtr)PmmSvNode(extdtd);
|
|
if ( dtd == NULL ) {
|
|
croak( "lost DTD node" );
|
|
}
|
|
CODE:
|
|
if ( dtd && dtd != self->intSubset ) {
|
|
if ( dtd->doc != self ) {
|
|
croak( "can't import DTDs" );
|
|
domImportNode( self, (xmlNodePtr) dtd,1,1);
|
|
}
|
|
|
|
if ( dtd == self->extSubset ) {
|
|
self->extSubset = NULL;
|
|
}
|
|
|
|
olddtd = xmlGetIntSubset( self );
|
|
if( olddtd ) {
|
|
xmlReplaceNode( (xmlNodePtr)olddtd, (xmlNodePtr) dtd );
|
|
if ( olddtd->_private == NULL ) {
|
|
xmlFreeDtd( olddtd );
|
|
}
|
|
}
|
|
else {
|
|
if (self->children == NULL)
|
|
xmlAddChild((xmlNodePtr) self, (xmlNodePtr) dtd);
|
|
else
|
|
xmlAddPrevSibling(self->children, (xmlNodePtr) dtd);
|
|
}
|
|
self->intSubset = dtd;
|
|
}
|
|
|
|
SV *
|
|
removeInternalSubset( self )
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
CODE:
|
|
dtd = xmlGetIntSubset(self);
|
|
if ( !dtd ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
xmlUnlinkNode( (xmlNodePtr)dtd );
|
|
self->intSubset = NULL;
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
removeExternalSubset( self )
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
CODE:
|
|
dtd = self->extSubset;
|
|
if ( !dtd ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
self->extSubset = NULL;
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, PmmPROXYNODE(self) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
importNode( self, node, dummy=0 )
|
|
xmlDocPtr self
|
|
xmlNodePtr node
|
|
int dummy
|
|
PREINIT:
|
|
xmlNodePtr ret = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
if ( node->type == XML_DOCUMENT_NODE
|
|
|| node->type == XML_HTML_DOCUMENT_NODE ) {
|
|
croak( "Can't import Documents!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if (node->type == XML_DTD_NODE) {
|
|
croak("Can't import DTD nodes");
|
|
}
|
|
|
|
ret = domImportNode( self, node, 0, 1 );
|
|
if ( ret ) {
|
|
docfrag = PmmNewFragment( self );
|
|
xmlAddChild( PmmNODE(docfrag), ret );
|
|
RETVAL = PmmNodeToSv( ret, docfrag);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
adoptNode( self, node )
|
|
xmlDocPtr self
|
|
xmlNodePtr node
|
|
PREINIT:
|
|
xmlNodePtr ret = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
if ( node->type == XML_DOCUMENT_NODE
|
|
|| node->type == XML_HTML_DOCUMENT_NODE ) {
|
|
croak( "Can't adopt Documents!" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if (node->type == XML_DTD_NODE) {
|
|
croak("Can't adopt DTD nodes");
|
|
}
|
|
|
|
ret = domImportNode( self, node, 1, 1 );
|
|
|
|
if ( ret ) {
|
|
docfrag = PmmNewFragment( self );
|
|
RETVAL = PmmNodeToSv(node, docfrag);
|
|
xmlAddChild( PmmNODE(docfrag), ret );
|
|
PmmFixOwner(SvPROXYNODE(RETVAL), docfrag);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char*
|
|
encoding( self )
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::getEncoding = 1
|
|
XML::LibXML::Document::xmlEncoding = 2
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = (char *) self->encoding;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setEncoding( self, encoding = NULL )
|
|
xmlDocPtr self
|
|
char *encoding
|
|
PREINIT:
|
|
int charset = XML_CHAR_ENCODING_ERROR;
|
|
CODE:
|
|
if ( self->encoding != NULL ) {
|
|
xmlFree( (xmlChar*) self->encoding );
|
|
}
|
|
if (encoding!=NULL && strlen(encoding)) {
|
|
self->encoding = xmlStrdup( (const xmlChar *)encoding );
|
|
charset = (int)xmlParseCharEncoding( (const char*)self->encoding );
|
|
if ( charset <= 0 ) {
|
|
charset = XML_CHAR_ENCODING_ERROR;
|
|
}
|
|
} else {
|
|
self->encoding=NULL;
|
|
charset = XML_CHAR_ENCODING_UTF8;
|
|
}
|
|
SetPmmNodeEncoding(self, charset);
|
|
|
|
|
|
int
|
|
standalone( self )
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::xmlStandalone = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = self->standalone;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setStandalone( self, value = 0 )
|
|
xmlDocPtr self
|
|
int value
|
|
CODE:
|
|
if ( value > 0 ) {
|
|
self->standalone = 1;
|
|
}
|
|
else if ( value < 0 ) {
|
|
self->standalone = -1;
|
|
}
|
|
else {
|
|
self->standalone = 0;
|
|
}
|
|
|
|
char*
|
|
version( self )
|
|
xmlDocPtr self
|
|
ALIAS:
|
|
XML::LibXML::Document::getVersion = 1
|
|
XML::LibXML::Document::xmlVersion = 2
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = (char *) self->version;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setVersion( self, version )
|
|
xmlDocPtr self
|
|
char *version
|
|
CODE:
|
|
if ( self->version != NULL ) {
|
|
xmlFree( (xmlChar*) self->version );
|
|
}
|
|
self->version = xmlStrdup( (const xmlChar*)version );
|
|
|
|
int
|
|
compression( self )
|
|
xmlDocPtr self
|
|
CODE:
|
|
RETVAL = xmlGetDocCompressMode(self);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setCompression( self, zLevel )
|
|
xmlDocPtr self
|
|
int zLevel
|
|
CODE:
|
|
xmlSetDocCompressMode(self, zLevel);
|
|
|
|
|
|
int
|
|
is_valid(self, ...)
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlValidCtxt cvp;
|
|
xmlDtdPtr dtd = NULL;
|
|
SV * dtd_sv;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
cvp.userData = saved_error;
|
|
cvp.error = (xmlValidityErrorFunc)LibXML_validity_error_ctx;
|
|
cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning_ctx;
|
|
|
|
/* we need to initialize the node stack, because perl might
|
|
* already have messed it up.
|
|
*/
|
|
cvp.nodeNr = 0;
|
|
cvp.nodeTab = NULL;
|
|
cvp.vstateNr = 0;
|
|
cvp.vstateTab = NULL;
|
|
|
|
PmmClearPSVI(self);
|
|
PmmInvalidatePSVI(self);
|
|
if (items > 1) {
|
|
dtd_sv = ST(1);
|
|
if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
|
|
dtd = (xmlDtdPtr)PmmSvNode(dtd_sv);
|
|
}
|
|
RETVAL = xmlValidateDtd(&cvp, self, dtd);
|
|
}
|
|
else {
|
|
RETVAL = xmlValidateDocument(&cvp, self);
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
/* REPORT_ERROR(1); */
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
validate(self, ...)
|
|
xmlDocPtr self
|
|
PREINIT:
|
|
xmlValidCtxt cvp;
|
|
xmlDtdPtr dtd;
|
|
SV * dtd_sv;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
cvp.userData = saved_error;
|
|
cvp.error = (xmlValidityErrorFunc)LibXML_validity_error_ctx;
|
|
cvp.warning = (xmlValidityWarningFunc)LibXML_validity_warning_ctx;
|
|
/* we need to initialize the node stack, because perl might
|
|
* already have messed it up.
|
|
*/
|
|
cvp.nodeNr = 0;
|
|
cvp.nodeTab = NULL;
|
|
cvp.vstateNr = 0;
|
|
cvp.vstateTab = NULL;
|
|
|
|
PmmClearPSVI(self);
|
|
PmmInvalidatePSVI(self);
|
|
|
|
if (items > 1) {
|
|
dtd_sv = ST(1);
|
|
if ( sv_isobject(dtd_sv) && (SvTYPE(SvRV(dtd_sv)) == SVt_PVMG) ) {
|
|
dtd = (xmlDtdPtr)PmmSvNode(dtd_sv);
|
|
}
|
|
else {
|
|
CLEANUP_ERROR_HANDLER;
|
|
croak("is_valid: argument must be a DTD object");
|
|
}
|
|
RETVAL = xmlValidateDtd(&cvp, self , dtd);
|
|
}
|
|
else {
|
|
RETVAL = xmlValidateDocument(&cvp, self);
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(RETVAL ? 1 : 0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
cloneNode( self, deep=0 )
|
|
xmlDocPtr self
|
|
int deep
|
|
PREINIT:
|
|
xmlDocPtr ret = NULL;
|
|
CODE:
|
|
ret = xmlCopyDoc( self, deep );
|
|
if ( ret == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)ret, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
getElementById( self, id )
|
|
xmlDocPtr self
|
|
const char * id
|
|
ALIAS:
|
|
XML::LibXML::Document::getElementsById = 1
|
|
PREINIT:
|
|
xmlNodePtr elem;
|
|
xmlAttrPtr attr;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( id != NULL ) {
|
|
attr = xmlGetID(self, (xmlChar *) id);
|
|
if (attr == NULL)
|
|
elem = NULL;
|
|
else if (attr->type == XML_ATTRIBUTE_NODE)
|
|
elem = attr->parent;
|
|
else if (attr->type == XML_ELEMENT_NODE)
|
|
elem = (xmlNodePtr) attr;
|
|
else
|
|
elem = NULL;
|
|
if (elem != NULL) {
|
|
RETVAL = PmmNodeToSv(elem, PmmPROXYNODE(self));
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
indexElements ( self )
|
|
xmlDocPtr self
|
|
CODE:
|
|
#if LIBXML_VERSION >= 20508
|
|
RETVAL = xmlXPathOrderDocElems( self );
|
|
#else
|
|
RETVAL = -2;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Node
|
|
|
|
void
|
|
DESTROY( node )
|
|
SV * node
|
|
PREINIT:
|
|
int count;
|
|
SV *is_shared;
|
|
CODE:
|
|
#ifdef XML_LIBXML_THREADS
|
|
if ( (is_shared = get_sv("XML::LibXML::__threads_shared", 0)) == NULL ) {
|
|
is_shared = &PL_sv_undef;
|
|
}
|
|
if ( SvTRUE(is_shared) ) {
|
|
dSP;
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
XPUSHs(node);
|
|
PUTBACK;
|
|
count = call_pv("threads::shared::is_shared", G_SCALAR);
|
|
SPAGAIN;
|
|
if (count != 1)
|
|
croak("Couldn't checks if the variable is shared or not\n");
|
|
is_shared = POPs;
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
if (is_shared != &PL_sv_undef) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
if( PmmUSEREGISTRY ) {
|
|
SvLOCK(PROXY_NODE_REGISTRY_MUTEX);
|
|
PmmRegistryREFCNT_dec(SvPROXYNODE(node));
|
|
}
|
|
#endif
|
|
PmmREFCNT_dec(SvPROXYNODE(node));
|
|
#ifdef XML_LIBXML_THREADS
|
|
if( PmmUSEREGISTRY )
|
|
SvUNLOCK(PROXY_NODE_REGISTRY_MUTEX);
|
|
#endif
|
|
|
|
SV*
|
|
nodeName( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getName = 1
|
|
XML::LibXML::Element::tagName = 2
|
|
PREINIT:
|
|
xmlChar * name = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
name = (xmlChar*)domName( self );
|
|
if ( name != NULL ) {
|
|
RETVAL = C2Sv(name,NULL);
|
|
xmlFree( name );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
localname( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getLocalName = 1
|
|
XML::LibXML::Attr::name = 2
|
|
XML::LibXML::Node::localName = 3
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->type == XML_ELEMENT_NODE
|
|
|| self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_ELEMENT_DECL
|
|
|| self->type == XML_ATTRIBUTE_DECL ) {
|
|
RETVAL = C2Sv(self->name,NULL);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
prefix( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getPrefix = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if( ( self->type == XML_ELEMENT_NODE
|
|
|| self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_PI_NODE )
|
|
&& self->ns != NULL
|
|
&& self->ns->prefix != NULL ) {
|
|
RETVAL = C2Sv(self->ns->prefix, NULL);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
namespaceURI( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
getNamespaceURI = 1
|
|
PREINIT:
|
|
xmlChar * nsURI;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( ( self->type == XML_ELEMENT_NODE
|
|
|| self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_PI_NODE )
|
|
&& self->ns != NULL
|
|
&& self->ns->href != NULL ) {
|
|
nsURI = xmlStrdup(self->ns->href);
|
|
RETVAL = C2Sv( nsURI, NULL );
|
|
xmlFree( nsURI );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
lookupNamespaceURI( self, svprefix=&PL_sv_undef )
|
|
xmlNodePtr self
|
|
SV * svprefix
|
|
PREINIT:
|
|
xmlChar * nsURI;
|
|
xmlChar * prefix = NULL;
|
|
xmlNsPtr ns;
|
|
CODE:
|
|
prefix = nodeSv2C( svprefix , self );
|
|
if ( prefix != NULL && xmlStrlen(prefix) == 0) {
|
|
xmlFree( prefix );
|
|
prefix = NULL;
|
|
}
|
|
ns = xmlSearchNs( self->doc, self, prefix );
|
|
if ( prefix != NULL) {
|
|
xmlFree( prefix );
|
|
}
|
|
if ( ns != NULL ) {
|
|
nsURI = xmlStrdup(ns->href);
|
|
RETVAL = C2Sv( nsURI, NULL );
|
|
xmlFree( nsURI );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
lookupNamespacePrefix( self, svuri )
|
|
xmlNodePtr self
|
|
SV * svuri
|
|
PREINIT:
|
|
xmlChar * nsprefix;
|
|
xmlChar * href = NULL;
|
|
CODE:
|
|
href = nodeSv2C( svuri , self );
|
|
if ( href != NULL && xmlStrlen(href) > 0) {
|
|
xmlNsPtr ns = xmlSearchNsByHref( self->doc, self, href );
|
|
xmlFree( href );
|
|
if ( ns != NULL ) {
|
|
if ( ns->prefix != NULL ) {
|
|
nsprefix = xmlStrdup( ns->prefix );
|
|
RETVAL = C2Sv( nsprefix, NULL );
|
|
xmlFree(nsprefix);
|
|
} else {
|
|
RETVAL = newSVpv("",0);
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
void
|
|
setNodeName( self , value )
|
|
xmlNodePtr self
|
|
SV* value
|
|
ALIAS:
|
|
setName = 1
|
|
PREINIT:
|
|
xmlChar* string;
|
|
xmlChar* localname;
|
|
xmlChar* prefix;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
string = nodeSv2C( value , self );
|
|
if ( !LibXML_test_node_name( string ) ) {
|
|
xmlFree(string);
|
|
croak( "bad name" );
|
|
}
|
|
if( ( self->type == XML_ELEMENT_NODE
|
|
|| self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_PI_NODE)
|
|
&& self->ns ){
|
|
localname = xmlSplitQName2(string, &prefix);
|
|
if ( localname == NULL ) {
|
|
localname = xmlStrdup( string );
|
|
}
|
|
xmlNodeSetName(self, localname );
|
|
xmlFree(localname);
|
|
xmlFree(prefix);
|
|
}
|
|
else {
|
|
xs_warn("node name normal\n");
|
|
xmlNodeSetName(self, string );
|
|
}
|
|
xmlFree(string);
|
|
|
|
void
|
|
setRawName( self, value )
|
|
xmlNodePtr self
|
|
SV * value
|
|
PREINIT:
|
|
xmlChar* string;
|
|
xmlChar* localname;
|
|
xmlChar* prefix;
|
|
CODE:
|
|
string = nodeSv2C( value , self );
|
|
if ( !string || xmlStrlen( string) <= 0 ) {
|
|
xmlFree(string);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if( ( self->type == XML_ELEMENT_NODE
|
|
|| self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_PI_NODE)
|
|
&& self->ns ){
|
|
localname = xmlSplitQName2(string, &prefix);
|
|
xmlNodeSetName(self, localname );
|
|
xmlFree(localname);
|
|
xmlFree(prefix);
|
|
}
|
|
else {
|
|
xmlNodeSetName(self, string );
|
|
}
|
|
xmlFree(string);
|
|
|
|
|
|
SV*
|
|
nodeValue( self, useDomEncoding = &PL_sv_undef )
|
|
xmlNodePtr self
|
|
SV * useDomEncoding
|
|
ALIAS:
|
|
XML::LibXML::Attr::value = 1
|
|
XML::LibXML::Attr::getValue = 2
|
|
XML::LibXML::Text::data = 3
|
|
XML::LibXML::Node::getValue = 4
|
|
XML::LibXML::Node::getData = 5
|
|
PREINIT:
|
|
xmlChar * content = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
content = domGetNodeValue( self );
|
|
|
|
if ( content != NULL ) {
|
|
if ( SvTRUE(useDomEncoding) ) {
|
|
RETVAL = nodeC2Sv(content, self);
|
|
}
|
|
else {
|
|
RETVAL = C2Sv(content, NULL);
|
|
}
|
|
xmlFree(content);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
nodeType( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getType = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = self->type;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
parentNode( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Attr::ownerElement = 1
|
|
XML::LibXML::Node::getParentNode = 2
|
|
XML::LibXML::Attr::getOwnerElement = 3
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv( self->parent,
|
|
PmmOWNERPO( PmmPROXYNODE(self) ) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
nextSibling( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
getNextSibling = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv( self->next,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
nextNonBlankSibling( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlNodePtr next;
|
|
CODE:
|
|
next = self->next;
|
|
while (next != NULL && xmlIsBlankNode(next))
|
|
next = next->next;
|
|
RETVAL = PmmNodeToSv( next,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
previousSibling( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
getPreviousSibling = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv( self->prev,
|
|
PmmOWNERPO( PmmPROXYNODE(self) ) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
previousNonBlankSibling( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlNodePtr prev;
|
|
CODE:
|
|
prev = self->prev;
|
|
while (prev != NULL && xmlIsBlankNode(prev))
|
|
prev = prev->prev;
|
|
RETVAL = PmmNodeToSv( prev,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
void
|
|
_childNodes( self, only_nonblank = 0 )
|
|
xmlNodePtr self
|
|
int only_nonblank
|
|
ALIAS:
|
|
XML::LibXML::Node::getChildnodes = 1
|
|
PREINIT:
|
|
xmlNodePtr cld;
|
|
SV * element;
|
|
int len = 0;
|
|
int wantarray = GIMME_V;
|
|
PPCODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->type != XML_ATTRIBUTE_NODE ) {
|
|
cld = self->children;
|
|
xs_warn("childnodes start");
|
|
while ( cld ) {
|
|
if ( !(only_nonblank && xmlIsBlankNode(cld)) ) {
|
|
if( wantarray != G_SCALAR ) {
|
|
element = PmmNodeToSv(cld, PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
XPUSHs(sv_2mortal(element));
|
|
}
|
|
len++;
|
|
}
|
|
cld = cld->next;
|
|
}
|
|
}
|
|
if ( wantarray == G_SCALAR ) {
|
|
XPUSHs(sv_2mortal(newSViv(len)) );
|
|
}
|
|
|
|
void
|
|
_getChildrenByTagNameNS( self, namespaceURI, node_name )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * node_name
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlChar * nsURI;
|
|
xmlNodePtr cld;
|
|
SV * element;
|
|
int len = 0;
|
|
int name_wildcard = 0;
|
|
int ns_wildcard = 0;
|
|
int wantarray = GIMME_V;
|
|
PPCODE:
|
|
name = nodeSv2C(node_name, self );
|
|
nsURI = nodeSv2C(namespaceURI, self );
|
|
|
|
if ( nsURI != NULL ) {
|
|
if (xmlStrlen(nsURI) == 0 ) {
|
|
xmlFree(nsURI);
|
|
nsURI = NULL;
|
|
} else if (xmlStrcmp( nsURI, (xmlChar *)"*" )==0) {
|
|
ns_wildcard = 1;
|
|
}
|
|
}
|
|
if ( name !=NULL && xmlStrcmp( name, (xmlChar *)"*" ) == 0) {
|
|
name_wildcard = 1;
|
|
}
|
|
if ( self->type != XML_ATTRIBUTE_NODE ) {
|
|
cld = self->children;
|
|
xs_warn("childnodes start");
|
|
while ( cld ) {
|
|
if (((name_wildcard && (cld->type == XML_ELEMENT_NODE)) ||
|
|
xmlStrcmp( name, cld->name ) == 0)
|
|
&& (ns_wildcard ||
|
|
(cld->ns != NULL &&
|
|
xmlStrcmp(nsURI,cld->ns->href) == 0 ) ||
|
|
(cld->ns == NULL && nsURI == NULL))) {
|
|
if( wantarray != G_SCALAR ) {
|
|
element = PmmNodeToSv(cld, PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
XPUSHs(sv_2mortal(element));
|
|
}
|
|
len++;
|
|
}
|
|
cld = cld->next;
|
|
}
|
|
}
|
|
if ( wantarray == G_SCALAR ) {
|
|
XPUSHs(sv_2mortal(newSViv(len)) );
|
|
}
|
|
xmlFree(name);
|
|
if (nsURI) xmlFree(nsURI);
|
|
|
|
SV*
|
|
firstChild( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
getFirstChild = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv( self->children,
|
|
PmmOWNERPO( PmmPROXYNODE(self) ) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
firstNonBlankChild( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlNodePtr child;
|
|
CODE:
|
|
child = self->children;
|
|
while (child !=NULL && xmlIsBlankNode(child))
|
|
child = child->next;
|
|
RETVAL = PmmNodeToSv( child,
|
|
PmmOWNERPO( PmmPROXYNODE(self) ) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
lastChild( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
getLastChild = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv( self->last,
|
|
PmmOWNERPO( PmmPROXYNODE(self) ) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_attributes( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getAttributes = 1
|
|
PREINIT:
|
|
xmlAttrPtr attr = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
SV * element;
|
|
int len=0;
|
|
int wantarray = GIMME_V;
|
|
PPCODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->type != XML_ATTRIBUTE_NODE
|
|
&& self->type != XML_DTD_NODE ) {
|
|
attr = self->properties;
|
|
while ( attr != NULL ) {
|
|
if ( wantarray != G_SCALAR ) {
|
|
element = PmmNodeToSv((xmlNodePtr)attr,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
XPUSHs(sv_2mortal(element));
|
|
}
|
|
attr = attr->next;
|
|
len++;
|
|
}
|
|
if (self->type == XML_ELEMENT_NODE) {
|
|
ns = self->nsDef;
|
|
while ( ns != NULL ) {
|
|
const char * CLASS = "XML::LibXML::Namespace";
|
|
if ( wantarray != G_SCALAR ) {
|
|
/* namespace handling is kinda odd:
|
|
* as soon we have a namespace isolated from its
|
|
* owner, we loose the context. therefore it is
|
|
* forbidden to access the NS information directly.
|
|
* instead the use will receive a copy of the real
|
|
* namespace, that can be destroied and is not
|
|
* bound to a document.
|
|
*
|
|
* this avoids segfaults in the end.
|
|
*/
|
|
if ((ns->prefix != NULL || ns->href != NULL)) {
|
|
xmlNsPtr tns = xmlCopyNamespace(ns);
|
|
if ( tns != NULL ) {
|
|
element = sv_newmortal();
|
|
XPUSHs(sv_setref_pv( element,
|
|
(char *)CLASS,
|
|
(void*)tns));
|
|
}
|
|
}
|
|
}
|
|
ns = ns->next;
|
|
len++;
|
|
}
|
|
}
|
|
}
|
|
if( wantarray == G_SCALAR ) {
|
|
XPUSHs( sv_2mortal(newSViv(len)) );
|
|
}
|
|
|
|
int
|
|
hasChildNodes( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
if ( self->type == XML_ATTRIBUTE_NODE ) {
|
|
RETVAL = 0;
|
|
}
|
|
else {
|
|
RETVAL = self->children ? 1 : 0 ;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
hasAttributes( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
if ( self->type == XML_ATTRIBUTE_NODE
|
|
|| self->type == XML_DTD_NODE ) {
|
|
RETVAL = 0;
|
|
}
|
|
else {
|
|
RETVAL = self->properties ? 1 : 0 ;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
ownerDocument( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getOwnerDocument = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
xs_warn( "GET OWNERDOC\n" );
|
|
if( self != NULL
|
|
&& self->doc != NULL ){
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)(self->doc), NULL);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
ownerNode( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::getOwner = 1
|
|
XML::LibXML::Node::getOwnerElement = 2
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = PmmNodeToSv(PmmNODE(PmmOWNERPO(PmmPROXYNODE(self))), NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
void
|
|
normalize( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
domNodeNormalize( self );
|
|
|
|
|
|
SV*
|
|
insertBefore( self, nNode, refNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
SV * refNode
|
|
PREINIT:
|
|
xmlNodePtr oNode=NULL, rNode;
|
|
INIT:
|
|
oNode = PmmSvNode(refNode);
|
|
CODE:
|
|
rNode = domInsertBefore( self, nNode, oNode );
|
|
if ( rNode != NULL ) {
|
|
RETVAL = PmmNodeToSv( rNode,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
if (rNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(self->doc, rNode);
|
|
}
|
|
PmmFixOwner(PmmPROXYNODE(rNode), PmmOWNERPO(PmmPROXYNODE(self)));
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
insertAfter( self, nNode, refNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
SV* refNode
|
|
PREINIT:
|
|
xmlNodePtr oNode = NULL, rNode;
|
|
INIT:
|
|
oNode = PmmSvNode(refNode);
|
|
CODE:
|
|
rNode = domInsertAfter( self, nNode, oNode );
|
|
if ( rNode != NULL ) {
|
|
RETVAL = PmmNodeToSv( rNode,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
if (rNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(self->doc, rNode);
|
|
}
|
|
PmmFixOwner(PmmPROXYNODE(rNode), PmmOWNERPO(PmmPROXYNODE(self)));
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
replaceChild( self, nNode, oNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
xmlNodePtr oNode
|
|
PREINIT:
|
|
xmlNodePtr ret = NULL;
|
|
CODE:
|
|
// if newNode == oldNode or self == newNode then do nothing, just return nNode.
|
|
if (nNode == oNode || self == nNode ) {
|
|
ret = nNode;
|
|
RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
|
|
}
|
|
else{
|
|
if ( self->type == XML_DOCUMENT_NODE ) {
|
|
switch ( nNode->type ) {
|
|
case XML_ELEMENT_NODE:
|
|
warn("replaceChild with an element on a document node not supported yet!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
case XML_DOCUMENT_FRAG_NODE:
|
|
warn("replaceChild with a document fragment node on a document node not supported yet!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
case XML_TEXT_NODE:
|
|
case XML_CDATA_SECTION_NODE:
|
|
warn("replaceChild with a text node not supported on a document node!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
ret = domReplaceChild( self, nNode, oNode );
|
|
if (ret == NULL) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
else {
|
|
LibXML_reparent_removed_node(ret);
|
|
RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
|
|
if (nNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(nNode->doc, nNode);
|
|
}
|
|
if ( nNode->_private != NULL ) {
|
|
PmmFixOwner( PmmPROXYNODE(nNode),
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
}
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
replaceNode( self,nNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
PREINIT:
|
|
xmlNodePtr ret = NULL;
|
|
ProxyNodePtr owner = NULL;
|
|
CODE:
|
|
if ( domIsParent( self, nNode ) == 1 ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
owner = PmmOWNERPO(PmmPROXYNODE(self));
|
|
|
|
if ( self->type != XML_ATTRIBUTE_NODE ) {
|
|
ret = domReplaceChild( self->parent, nNode, self);
|
|
}
|
|
else {
|
|
ret = xmlReplaceNode( self, nNode );
|
|
}
|
|
if ( ret ) {
|
|
LibXML_reparent_removed_node(ret);
|
|
RETVAL = PmmNodeToSv(ret, PmmOWNERPO(PmmPROXYNODE(ret)));
|
|
if (nNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(nNode->doc, nNode);
|
|
}
|
|
if ( nNode->_private != NULL ) {
|
|
PmmFixOwner(PmmPROXYNODE(nNode), owner);
|
|
}
|
|
}
|
|
else {
|
|
croak( "replacement failed" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
removeChild( self, node )
|
|
xmlNodePtr self
|
|
xmlNodePtr node
|
|
PREINIT:
|
|
xmlNodePtr ret;
|
|
CODE:
|
|
ret = domRemoveChild( self, node );
|
|
if (ret == NULL) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
else {
|
|
LibXML_reparent_removed_node(ret);
|
|
RETVAL = PmmNodeToSv(ret, NULL);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
removeChildNodes( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlNodePtr elem, fragment;
|
|
ProxyNodePtr docfrag;
|
|
CODE:
|
|
docfrag = PmmNewFragment( self->doc );
|
|
fragment = PmmNODE( docfrag );
|
|
elem = self->children;
|
|
while ( elem ) {
|
|
xmlNodePtr next = elem->next;
|
|
xmlUnlinkNode( elem );
|
|
if (elem->type == XML_ATTRIBUTE_NODE
|
|
|| elem->type == XML_DTD_NODE) {
|
|
if (PmmPROXYNODE(elem) == NULL) {
|
|
xmlFreeNode(elem);
|
|
}
|
|
}
|
|
else {
|
|
/* this following piece is the function of domAppendChild()
|
|
* but in this special case we can avoid most of the logic of
|
|
* that function.
|
|
*/
|
|
if ( fragment->children != NULL ) {
|
|
xs_warn("unlink node!\n");
|
|
domAddNodeToList( elem, fragment->last, NULL );
|
|
}
|
|
else {
|
|
fragment->children = elem;
|
|
fragment->last = elem;
|
|
elem->parent= fragment;
|
|
}
|
|
PmmFixOwnerNode( elem, docfrag );
|
|
}
|
|
elem = next;
|
|
}
|
|
|
|
self->children = self->last = NULL;
|
|
if ( PmmREFCNT(docfrag) <= 0 ) {
|
|
xs_warn( "have not references left" );
|
|
PmmREFCNT_inc( docfrag );
|
|
PmmREFCNT_dec( docfrag );
|
|
}
|
|
|
|
void
|
|
unbindNode( self )
|
|
xmlNodePtr self
|
|
ALIAS:
|
|
XML::LibXML::Node::unlink = 1
|
|
XML::LibXML::Node::unlinkNode = 2
|
|
PREINIT:
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->type != XML_DOCUMENT_NODE
|
|
&& self->type != XML_DOCUMENT_FRAG_NODE ) {
|
|
xmlUnlinkNode( self );
|
|
LibXML_reparent_removed_node(self);
|
|
}
|
|
|
|
SV*
|
|
appendChild( self, nNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
PREINIT:
|
|
xmlNodePtr rNode;
|
|
CODE:
|
|
if (self->type == XML_DOCUMENT_NODE ) {
|
|
/* NOT_SUPPORTED_ERR
|
|
*/
|
|
switch ( nNode->type ) {
|
|
case XML_ELEMENT_NODE:
|
|
warn("Appending an element to a document node not supported yet!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
case XML_DOCUMENT_FRAG_NODE:
|
|
warn("Appending a document fragment node to a document node not supported yet!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
case XML_TEXT_NODE:
|
|
case XML_CDATA_SECTION_NODE:
|
|
warn("Appending text node not supported on a document node yet!");
|
|
XSRETURN_UNDEF;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
rNode = domAppendChild( self, nNode );
|
|
|
|
if ( rNode == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
RETVAL = PmmNodeToSv( nNode,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
if (nNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(self->doc, nNode);
|
|
}
|
|
PmmFixOwner( SvPROXYNODE(RETVAL), PmmPROXYNODE(self) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
addChild( self, nNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
PREINIT:
|
|
xmlNodePtr retval = NULL;
|
|
ProxyNodePtr proxy;
|
|
CODE:
|
|
switch ( nNode->type ) {
|
|
case XML_DOCUMENT_FRAG_NODE:
|
|
croak("Adding document fragments with addChild not supported!");
|
|
XSRETURN_UNDEF;
|
|
case XML_DOCUMENT_NODE :
|
|
case XML_HTML_DOCUMENT_NODE :
|
|
case XML_DOCB_DOCUMENT_NODE :
|
|
croak("addChild: HIERARCHY_REQUEST_ERR\n");
|
|
XSRETURN_UNDEF;
|
|
case XML_NOTATION_NODE :
|
|
case XML_NAMESPACE_DECL :
|
|
case XML_DTD_NODE :
|
|
case XML_DOCUMENT_TYPE_NODE :
|
|
case XML_ENTITY_DECL :
|
|
case XML_ELEMENT_DECL :
|
|
case XML_ATTRIBUTE_DECL :
|
|
croak("addChild: unsupported node type!");
|
|
XSRETURN_UNDEF;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
xmlUnlinkNode(nNode);
|
|
proxy = PmmPROXYNODE(nNode);
|
|
retval = xmlAddChild( self, nNode );
|
|
|
|
if ( retval == NULL ) {
|
|
croak( "Error: addChild failed (check node types)!\n" );
|
|
}
|
|
|
|
if ( retval != nNode ) {
|
|
xs_warn( "node was lost during operation\n" );
|
|
PmmNODE(proxy) = NULL;
|
|
}
|
|
|
|
RETVAL = PmmNodeToSv( retval,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
if ( retval != self ) {
|
|
PmmFixOwner( SvPROXYNODE(RETVAL), PmmPROXYNODE(self) );
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
addSibling( self, nNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr nNode
|
|
PREINIT:
|
|
xmlNodePtr ret = NULL;
|
|
ProxyNodePtr owner = NULL;
|
|
CODE:
|
|
if ( nNode->type == XML_DOCUMENT_FRAG_NODE ) {
|
|
croak("Adding document fragments with addSibling not yet supported!");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
owner = PmmOWNERPO(PmmPROXYNODE(self));
|
|
|
|
if (self->type == XML_TEXT_NODE && nNode->type == XML_TEXT_NODE
|
|
&& self->name == nNode->name) {
|
|
/* As a result of text merging, the added node may be freed. */
|
|
xmlNodePtr copy = xmlCopyNode(nNode, 0);
|
|
ret = xmlAddSibling(self, copy);
|
|
|
|
if (ret) {
|
|
RETVAL = PmmNodeToSv(ret, owner);
|
|
/* Unlink original node. */
|
|
xmlUnlinkNode(nNode);
|
|
LibXML_reparent_removed_node(nNode);
|
|
}
|
|
else {
|
|
xmlFreeNode(copy);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
ret = xmlAddSibling( self, nNode );
|
|
|
|
if ( ret ) {
|
|
RETVAL = PmmNodeToSv(ret, owner);
|
|
if (nNode->type == XML_DTD_NODE) {
|
|
LibXML_set_int_subset(self->doc, nNode);
|
|
}
|
|
PmmFixOwner(SvPROXYNODE(RETVAL), owner);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
cloneNode( self, deep=0 )
|
|
xmlNodePtr self
|
|
int deep
|
|
PREINIT:
|
|
xmlNodePtr ret;
|
|
xmlDocPtr doc = NULL;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
ret = PmmCloneNode( self, deep );
|
|
if ( ret == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
if ( ret->type == XML_DTD_NODE ) {
|
|
RETVAL = PmmNodeToSv(ret, NULL);
|
|
}
|
|
else {
|
|
doc = self->doc;
|
|
|
|
if ( doc != NULL ) {
|
|
xmlSetTreeDoc(ret, doc); /* setting to self, no need to clear psvi */
|
|
}
|
|
|
|
docfrag = PmmNewFragment( doc );
|
|
xmlAddChild( PmmNODE(docfrag), ret );
|
|
RETVAL = PmmNodeToSv(ret, docfrag);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isSameNode( self, oNode )
|
|
xmlNodePtr self
|
|
xmlNodePtr oNode
|
|
ALIAS:
|
|
XML::LibXML::Node::isEqual = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = ( self == oNode ) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
IV
|
|
unique_key( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
/* Cast pointer to IV */
|
|
RETVAL = PTR2IV(self);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
baseURI( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlChar * uri;
|
|
CODE:
|
|
uri = xmlNodeGetBase( self->doc, self );
|
|
RETVAL = C2Sv( uri, NULL );
|
|
xmlFree( uri );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setBaseURI( self, URI )
|
|
xmlNodePtr self
|
|
SV * URI
|
|
PREINIT:
|
|
xmlChar * uri;
|
|
CODE:
|
|
uri = nodeSv2C( URI, self );
|
|
if ( uri != NULL ) {
|
|
xmlNodeSetBase( self, uri );
|
|
}
|
|
|
|
SV*
|
|
toString( self, format=0, useDomEncoding = &PL_sv_undef )
|
|
xmlNodePtr self
|
|
SV * useDomEncoding
|
|
int format
|
|
ALIAS:
|
|
XML::LibXML::Node::serialize = 1
|
|
PREINIT:
|
|
xmlBufferPtr buffer;
|
|
const xmlChar *ret = NULL;
|
|
SV* internalFlag = NULL;
|
|
int oldTagFlag = xmlSaveNoEmptyTags;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
|
|
|
|
if ( internalFlag ) {
|
|
xmlSaveNoEmptyTags = SvTRUE(internalFlag);
|
|
}
|
|
buffer = xmlBufferCreate();
|
|
|
|
if ( format <= 0 ) {
|
|
xmlNodeDump( buffer,
|
|
self->doc,
|
|
self, 0, format);
|
|
}
|
|
else {
|
|
int t_indent_var = xmlIndentTreeOutput;
|
|
xmlIndentTreeOutput = 1;
|
|
xmlNodeDump( buffer,
|
|
self->doc,
|
|
self, 0, format);
|
|
xmlIndentTreeOutput = t_indent_var;
|
|
}
|
|
|
|
ret = xmlBufferContent( buffer );
|
|
|
|
xmlSaveNoEmptyTags = oldTagFlag;
|
|
|
|
if ( ret != NULL ) {
|
|
if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
|
|
RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(self))) ;
|
|
SvUTF8_off(RETVAL);
|
|
}
|
|
else {
|
|
RETVAL = C2Sv((xmlChar*)ret, NULL) ;
|
|
}
|
|
xmlBufferFree( buffer );
|
|
}
|
|
else {
|
|
xmlBufferFree( buffer );
|
|
xs_warn("Failed to convert node to string");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV *
|
|
_toStringC14N(self, comments=0, xpath=&PL_sv_undef, exclusive=0, inc_prefix_list=NULL, xpath_context)
|
|
xmlNodePtr self
|
|
int comments
|
|
SV * xpath
|
|
int exclusive
|
|
char** inc_prefix_list
|
|
SV * xpath_context
|
|
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
xmlChar *nodepath = NULL;
|
|
xmlXPathContextPtr child_ctxt = NULL;
|
|
xmlXPathObjectPtr xpath_res = NULL;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
xmlNodePtr refNode = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
/* due to how c14n is implemented, the nodeset it receives must
|
|
include child nodes; ie, child nodes aren't assumed to be rendered.
|
|
so we use an xpath expression to find all of the child nodes. */
|
|
|
|
if ( self->doc == NULL ) {
|
|
croak("Node passed to toStringC14N must be part of a document");
|
|
}
|
|
|
|
refNode = self;
|
|
CODE:
|
|
if ( xpath != NULL && xpath != &PL_sv_undef ) {
|
|
nodepath = Sv2C( xpath, NULL );
|
|
}
|
|
|
|
if ( nodepath != NULL && xmlStrlen( nodepath ) == 0 ) {
|
|
xmlFree( nodepath );
|
|
nodepath = NULL;
|
|
}
|
|
|
|
if ( nodepath == NULL
|
|
&& self->type != XML_DOCUMENT_NODE
|
|
&& self->type != XML_HTML_DOCUMENT_NODE
|
|
&& self->type != XML_DOCB_DOCUMENT_NODE
|
|
) {
|
|
if (comments)
|
|
nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)" );
|
|
else
|
|
nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)[not(self::comment())]" );
|
|
}
|
|
|
|
if ( nodepath != NULL ) {
|
|
if ( self->type == XML_DOCUMENT_NODE
|
|
|| self->type == XML_HTML_DOCUMENT_NODE
|
|
|| self->type == XML_DOCB_DOCUMENT_NODE ) {
|
|
refNode = xmlDocGetRootElement( self->doc );
|
|
}
|
|
if (SvOK(xpath_context)) {
|
|
child_ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(xpath_context)));
|
|
if ( child_ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
} else {
|
|
xpath_context = NULL;
|
|
child_ctxt = xmlXPathNewContext(self->doc);
|
|
}
|
|
if (!child_ctxt) {
|
|
if ( nodepath != NULL ) {
|
|
xmlFree( nodepath );
|
|
}
|
|
croak("Failed to create xpath context");
|
|
}
|
|
|
|
child_ctxt->node = self;
|
|
LibXML_configure_namespaces(child_ctxt);
|
|
|
|
xpath_res = xmlXPathEval(nodepath, child_ctxt);
|
|
if (child_ctxt->namespaces != NULL) {
|
|
xmlFree( child_ctxt->namespaces );
|
|
child_ctxt->namespaces = NULL;
|
|
}
|
|
if (!xpath_context) xmlXPathFreeContext(child_ctxt);
|
|
if ( nodepath != NULL ) {
|
|
xmlFree( nodepath );
|
|
}
|
|
|
|
if (xpath_res == NULL) {
|
|
croak("2 Failed to compile xpath expression");
|
|
}
|
|
|
|
nodelist = xpath_res->nodesetval;
|
|
if ( nodelist == NULL ) {
|
|
xmlXPathFreeObject(xpath_res);
|
|
croak( "cannot canonize empty nodeset!" );
|
|
}
|
|
}
|
|
|
|
INIT_ERROR_HANDLER;
|
|
|
|
xmlC14NDocDumpMemory( self->doc,
|
|
nodelist,
|
|
exclusive, (xmlChar **) inc_prefix_list,
|
|
comments,
|
|
&result );
|
|
|
|
if ( xpath_res ) xmlXPathFreeObject(xpath_res);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
|
|
if (result == NULL) {
|
|
croak("Failed to convert doc to string in doc->toStringC14N");
|
|
} else {
|
|
RETVAL = C2Sv( result, NULL );
|
|
xmlFree(result);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
string_value ( self, useDomEncoding = &PL_sv_undef )
|
|
xmlNodePtr self
|
|
SV * useDomEncoding
|
|
ALIAS:
|
|
to_literal = 1
|
|
textContent = 2
|
|
PREINIT:
|
|
xmlChar * string = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
/* we can't just return a string, because of UTF8! */
|
|
string = xmlXPathCastNodeToString(self);
|
|
if ( SvTRUE(useDomEncoding) ) {
|
|
RETVAL = nodeC2Sv(string,
|
|
self);
|
|
}
|
|
else {
|
|
RETVAL = C2Sv(string,
|
|
NULL);
|
|
}
|
|
xmlFree(string);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
double
|
|
to_number ( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
RETVAL = xmlXPathCastNodeToNumber(self);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
void
|
|
_find( pnode, pxpath, to_bool )
|
|
SV* pnode
|
|
SV * pxpath
|
|
int to_bool
|
|
PREINIT:
|
|
xmlNodePtr node = PmmSvNode(pnode);
|
|
ProxyNodePtr owner = NULL;
|
|
xmlXPathObjectPtr found = NULL;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
xmlChar * xpath = NULL;
|
|
xmlXPathCompExprPtr comp = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if ( node == NULL ) {
|
|
croak( "lost node" );
|
|
}
|
|
if (sv_isobject(pxpath) && sv_isa(pxpath,"XML::LibXML::XPathExpression")) {
|
|
comp = INT2PTR(xmlXPathCompExprPtr,SvIV((SV*)SvRV( pxpath )));
|
|
if (!comp) XSRETURN_UNDEF;
|
|
} else {
|
|
xpath = nodeSv2C(pxpath, node);
|
|
if ( !(xpath && xmlStrlen(xpath)) ) {
|
|
xs_warn( "bad xpath\n" );
|
|
if ( xpath )
|
|
xmlFree(xpath);
|
|
croak( "empty XPath found" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
PPCODE:
|
|
INIT_ERROR_HANDLER;
|
|
if (comp) {
|
|
found = domXPathCompFind( node, comp, to_bool );
|
|
} else {
|
|
found = domXPathFind( node, xpath, to_bool );
|
|
xmlFree( xpath );
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
if (found) {
|
|
REPORT_ERROR(1);
|
|
switch (found->type) {
|
|
case XPATH_NODESET:
|
|
/* return as a NodeList */
|
|
/* access ->nodesetval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
|
|
nodelist = found->nodesetval;
|
|
if ( nodelist ) {
|
|
if ( nodelist->nodeNr > 0 ) {
|
|
int i;
|
|
const char * cls = "XML::LibXML::Node";
|
|
xmlNodePtr tnode;
|
|
SV * element;
|
|
int l = nodelist->nodeNr;
|
|
|
|
owner = PmmOWNERPO(SvPROXYNODE(pnode));
|
|
for( i=0 ; i < l; i++){
|
|
/* we have to create a new instance of an
|
|
* objectptr. and then
|
|
* place the current node into the new
|
|
* object. afterwards we can
|
|
* push the object to the array!
|
|
*/
|
|
tnode = nodelist->nodeTab[i];
|
|
|
|
/* let's be paranoid */
|
|
if (tnode->type == XML_NAMESPACE_DECL) {
|
|
xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
|
|
if ( newns != NULL ) {
|
|
element = NEWSV(0,0);
|
|
cls = PmmNodeTypeName( tnode );
|
|
element = sv_setref_pv( element,
|
|
(const char *)cls,
|
|
(void*)newns
|
|
);
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
element = PmmNodeToSv(tnode, owner);
|
|
}
|
|
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
xmlXPathFreeNodeSet( found->nodesetval );
|
|
found->nodesetval = NULL;
|
|
}
|
|
break;
|
|
case XPATH_BOOLEAN:
|
|
/* return as a Boolean */
|
|
/* access ->boolval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
|
|
XPUSHs(sv_2mortal(newSViv(found->boolval)));
|
|
break;
|
|
case XPATH_NUMBER:
|
|
/* return as a Number */
|
|
/* access ->floatval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
|
|
XPUSHs(sv_2mortal(newSVnv(found->floatval)));
|
|
break;
|
|
case XPATH_STRING:
|
|
/* access ->stringval */
|
|
/* return as a Literal */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
|
|
XPUSHs(sv_2mortal(C2Sv(found->stringval, NULL)));
|
|
break;
|
|
default:
|
|
croak("Unknown XPath return type");
|
|
}
|
|
xmlXPathFreeObject(found);
|
|
} else {
|
|
REPORT_ERROR(0);
|
|
}
|
|
|
|
void
|
|
_findnodes( pnode, perl_xpath )
|
|
SV* pnode
|
|
SV * perl_xpath
|
|
PREINIT:
|
|
xmlNodePtr node = PmmSvNode(pnode);
|
|
ProxyNodePtr owner = NULL;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
SV * element = NULL ;
|
|
xmlChar * xpath = NULL ;
|
|
xmlXPathCompExprPtr comp = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
if ( node == NULL ) {
|
|
if ( xpath )
|
|
xmlFree(xpath);
|
|
croak( "lost node" );
|
|
}
|
|
if (sv_isobject(perl_xpath) && sv_isa(perl_xpath,"XML::LibXML::XPathExpression")) {
|
|
comp = INT2PTR(xmlXPathCompExprPtr,SvIV((SV*)SvRV( perl_xpath )));
|
|
if (!comp) XSRETURN_UNDEF;
|
|
} else {
|
|
xpath = nodeSv2C(perl_xpath, node);
|
|
if ( !(xpath && xmlStrlen(xpath)) ) {
|
|
xs_warn( "bad xpath\n" );
|
|
if ( xpath )
|
|
xmlFree(xpath);
|
|
croak( "empty XPath found" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
PPCODE:
|
|
INIT_ERROR_HANDLER;
|
|
if (comp) {
|
|
nodelist = domXPathCompSelect( node, comp );
|
|
} else {
|
|
nodelist = domXPathSelect( node, xpath );
|
|
xmlFree(xpath);
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
|
|
if ( nodelist ) {
|
|
REPORT_ERROR(1);
|
|
if ( nodelist->nodeNr > 0 ) {
|
|
int i;
|
|
int len = nodelist->nodeNr;
|
|
const char * cls = "XML::LibXML::Node";
|
|
xmlNodePtr tnode;
|
|
owner = PmmOWNERPO(SvPROXYNODE(pnode));
|
|
|
|
for(i=0 ; i < len; i++){
|
|
/* we have to create a new instance of an objectptr.
|
|
* and then place the current node into the new object.
|
|
* afterwards we can push the object to the array!
|
|
*/
|
|
element = NULL;
|
|
tnode = nodelist->nodeTab[i];
|
|
if (tnode->type == XML_NAMESPACE_DECL) {
|
|
xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
|
|
if ( newns != NULL ) {
|
|
element = NEWSV(0,0);
|
|
cls = PmmNodeTypeName( tnode );
|
|
element = sv_setref_pv( element,
|
|
(const char *)cls,
|
|
newns
|
|
);
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
element = PmmNodeToSv(tnode, owner);
|
|
}
|
|
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
xmlXPathFreeNodeSet( nodelist );
|
|
} else {
|
|
REPORT_ERROR(0);
|
|
}
|
|
|
|
void
|
|
getNamespaces( pnode )
|
|
SV * pnode
|
|
ALIAS:
|
|
namespaces = 1
|
|
PREINIT:
|
|
xmlNodePtr node;
|
|
xmlNsPtr ns = NULL;
|
|
xmlNsPtr newns = NULL;
|
|
SV* element = &PL_sv_undef;
|
|
const char * class = "XML::LibXML::Namespace";
|
|
INIT:
|
|
PERL_UNUSED_VAR(ix);
|
|
node = PmmSvNode(pnode);
|
|
if ( node == NULL ) {
|
|
croak( "lost node" );
|
|
}
|
|
PPCODE:
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
ns = node->nsDef;
|
|
while ( ns != NULL ) {
|
|
if (ns->prefix != NULL || ns->href != NULL) {
|
|
newns = xmlCopyNamespace(ns);
|
|
if ( newns != NULL ) {
|
|
element = NEWSV(0,0);
|
|
element = sv_setref_pv( element,
|
|
(const char *)class,
|
|
(void*)newns
|
|
);
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
ns = ns->next;
|
|
}
|
|
}
|
|
|
|
SV *
|
|
getNamespace( node )
|
|
xmlNodePtr node
|
|
ALIAS:
|
|
localNamespace = 1
|
|
localNS = 2
|
|
PREINIT:
|
|
xmlNsPtr ns = NULL;
|
|
xmlNsPtr newns = NULL;
|
|
const char * class = "XML::LibXML::Namespace";
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( node->type == XML_ELEMENT_NODE
|
|
|| node->type == XML_ATTRIBUTE_NODE
|
|
|| node->type == XML_PI_NODE ) {
|
|
ns = node->ns;
|
|
if ( ns != NULL ) {
|
|
newns = xmlCopyNamespace(ns);
|
|
if ( newns != NULL ) {
|
|
RETVAL = NEWSV(0,0);
|
|
RETVAL = sv_setref_pv( RETVAL,
|
|
(const char *)class,
|
|
(void*)newns
|
|
);
|
|
} else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
} else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV *
|
|
nodePath( self )
|
|
xmlNodePtr self
|
|
PREINIT:
|
|
xmlChar * path = NULL;
|
|
CODE:
|
|
path = xmlGetNodePath( self );
|
|
if ( path == NULL ) {
|
|
croak( "cannot calculate path for the given node" );
|
|
}
|
|
RETVAL = C2Sv( path, NULL );
|
|
xmlFree(path);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
line_number( self )
|
|
xmlNodePtr self
|
|
CODE:
|
|
RETVAL = xmlGetLineNo( self );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Element
|
|
|
|
SV*
|
|
new(CLASS, name )
|
|
char * name
|
|
PREINIT:
|
|
xmlNodePtr newNode;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
docfrag = PmmNewFragment(NULL);
|
|
newNode = xmlNewNode( NULL, (const xmlChar*)name );
|
|
newNode->doc = NULL;
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode, docfrag );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_setNamespace(self, namespaceURI, namespacePrefix = &PL_sv_undef, flag = 1 )
|
|
SV * self
|
|
SV * namespaceURI
|
|
SV * namespacePrefix
|
|
int flag
|
|
PREINIT:
|
|
xmlNodePtr node = PmmSvNode(self);
|
|
xmlChar * nsURI = nodeSv2C(namespaceURI,node);
|
|
xmlChar * nsPrefix = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
INIT:
|
|
if ( node == NULL ) {
|
|
croak( "lost node" );
|
|
}
|
|
CODE:
|
|
/* if ( !nsURI ){
|
|
XSRETURN_UNDEF;
|
|
} */
|
|
|
|
nsPrefix = nodeSv2C(namespacePrefix, node);
|
|
if ( xmlStrlen( nsPrefix ) == 0 ) {
|
|
xmlFree(nsPrefix);
|
|
nsPrefix = NULL;
|
|
}
|
|
if ( xmlStrlen( nsURI ) == 0 ) {
|
|
xmlFree(nsURI);
|
|
nsURI = NULL;
|
|
}
|
|
if ( nsPrefix == NULL && nsURI == NULL ) {
|
|
/* special case: empty namespace */
|
|
if ( (ns = xmlSearchNs(node->doc, node, NULL)) &&
|
|
( ns->href && xmlStrlen( ns->href ) != 0 ) ) {
|
|
/* won't take it */
|
|
RETVAL = 0;
|
|
} else if ( flag ) {
|
|
/* no namespace */
|
|
xmlSetNs(node, NULL);
|
|
RETVAL = 1;
|
|
} else {
|
|
RETVAL = 0;
|
|
}
|
|
}
|
|
else if ( flag && (ns = xmlSearchNs(node->doc, node, nsPrefix)) ) {
|
|
/* user just wants to set the namespace for the node */
|
|
/* try to reuse an existing declaration for the prefix */
|
|
if ( xmlStrEqual( ns->href, nsURI ) ) {
|
|
RETVAL = 1;
|
|
}
|
|
else if ( (ns = xmlNewNs( node, nsURI, nsPrefix )) ) {
|
|
RETVAL = 1;
|
|
}
|
|
else {
|
|
RETVAL = 0;
|
|
}
|
|
}
|
|
else if ( (ns = xmlNewNs( node, nsURI, nsPrefix )) )
|
|
RETVAL = 1;
|
|
else
|
|
RETVAL = 0;
|
|
|
|
if ( flag && ns ) {
|
|
xmlSetNs(node, ns);
|
|
}
|
|
if ( nsPrefix ) xmlFree(nsPrefix);
|
|
if ( nsURI ) xmlFree(nsURI);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
setNamespaceDeclURI( self, svprefix, newURI )
|
|
xmlNodePtr self
|
|
SV * svprefix
|
|
SV * newURI
|
|
PREINIT:
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * nsURI = NULL;
|
|
xmlNsPtr ns;
|
|
CODE:
|
|
RETVAL = 0;
|
|
prefix = nodeSv2C( svprefix , self );
|
|
nsURI = nodeSv2C( newURI , self );
|
|
/* null empty values */
|
|
if ( prefix && xmlStrlen(prefix) == 0) {
|
|
xmlFree( prefix );
|
|
prefix = NULL;
|
|
}
|
|
if ( nsURI && xmlStrlen(nsURI) == 0) {
|
|
xmlFree( nsURI );
|
|
nsURI = NULL;
|
|
}
|
|
ns = self->nsDef;
|
|
while ( ns ) {
|
|
if ((ns->prefix || ns->href ) &&
|
|
( xmlStrcmp( ns->prefix, prefix ) == 0 )) {
|
|
if (ns->href) xmlFree((char*)ns->href);
|
|
ns->href = nsURI;
|
|
if ( nsURI == NULL ) {
|
|
domRemoveNsRefs( self, ns );
|
|
} else
|
|
nsURI = NULL; /* do not free it */
|
|
RETVAL = 1;
|
|
break;
|
|
} else {
|
|
ns = ns->next;
|
|
}
|
|
}
|
|
if ( prefix ) xmlFree( prefix );
|
|
if ( nsURI ) xmlFree( nsURI );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
setNamespaceDeclPrefix( self, svprefix, newPrefix )
|
|
xmlNodePtr self
|
|
SV * svprefix
|
|
SV * newPrefix
|
|
PREINIT:
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * nsPrefix = NULL;
|
|
xmlNsPtr ns;
|
|
CODE:
|
|
RETVAL = 0;
|
|
prefix = nodeSv2C( svprefix , self );
|
|
nsPrefix = nodeSv2C( newPrefix , self );
|
|
/* null empty values */
|
|
if ( prefix != NULL && xmlStrlen(prefix) == 0) {
|
|
xmlFree( prefix );
|
|
prefix = NULL;
|
|
}
|
|
if ( nsPrefix != NULL && xmlStrlen(nsPrefix) == 0) {
|
|
xmlFree( nsPrefix );
|
|
nsPrefix = NULL;
|
|
}
|
|
if ( xmlStrcmp( prefix, nsPrefix ) == 0 ) {
|
|
RETVAL = 1;
|
|
} else {
|
|
/* check that new prefix is not in scope */
|
|
ns = xmlSearchNs( self->doc, self, nsPrefix );
|
|
if ( ns != NULL ) {
|
|
if (nsPrefix != NULL) xmlFree( nsPrefix );
|
|
if (prefix != NULL) xmlFree( prefix );
|
|
croak("setNamespaceDeclPrefix: prefix '%s' is in use", ns->prefix);
|
|
}
|
|
/* lookup the declaration */
|
|
ns = self->nsDef;
|
|
while ( ns != NULL ) {
|
|
if ((ns->prefix != NULL || ns->href != NULL) &&
|
|
xmlStrcmp( ns->prefix, prefix ) == 0 ) {
|
|
if ( ns->href == NULL && nsPrefix != NULL ) {
|
|
/* xmlns:foo="" - no go */
|
|
if ( prefix != NULL) xmlFree(prefix);
|
|
croak("setNamespaceDeclPrefix: cannot set non-empty prefix for empty namespace");
|
|
}
|
|
if ( ns->prefix != NULL )
|
|
xmlFree( (xmlChar*)ns->prefix );
|
|
ns->prefix = nsPrefix;
|
|
nsPrefix = NULL; /* do not free it */
|
|
RETVAL = 1;
|
|
break;
|
|
} else {
|
|
ns = ns->next;
|
|
}
|
|
}
|
|
}
|
|
if ( nsPrefix != NULL ) xmlFree(nsPrefix);
|
|
if ( prefix != NULL) xmlFree(prefix);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
_getNamespaceDeclURI( self, ns_prefix )
|
|
xmlNodePtr self
|
|
SV * ns_prefix
|
|
PREINIT:
|
|
xmlChar * prefix;
|
|
xmlNsPtr ns;
|
|
CODE:
|
|
prefix = nodeSv2C(ns_prefix, self );
|
|
if ( prefix != NULL && xmlStrlen(prefix) == 0) {
|
|
xmlFree( prefix );
|
|
prefix = NULL;
|
|
}
|
|
RETVAL = &PL_sv_undef;
|
|
ns = self->nsDef;
|
|
while ( ns != NULL ) {
|
|
if ( (ns->prefix != NULL || ns->href != NULL) &&
|
|
xmlStrcmp( ns->prefix, prefix ) == 0 ) {
|
|
RETVAL = C2Sv(ns->href, NULL);
|
|
break;
|
|
} else {
|
|
ns = ns->next;
|
|
}
|
|
}
|
|
if ( prefix != NULL ) {
|
|
xmlFree( prefix );
|
|
}
|
|
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
hasAttribute( self, attr_name )
|
|
xmlNodePtr self
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * name;
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
if ( ! name ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( domGetAttrNode( self, name ) ) {
|
|
RETVAL = 1;
|
|
}
|
|
else {
|
|
RETVAL = 0;
|
|
}
|
|
xmlFree(name);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
hasAttributeNS( self, namespaceURI, attr_name )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlChar * nsURI;
|
|
xmlNodePtr attr;
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
nsURI = nodeSv2C(namespaceURI, self );
|
|
|
|
if ( name == NULL ) {
|
|
if ( nsURI != NULL ) {
|
|
xmlFree(nsURI);
|
|
}
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( nsURI != NULL && xmlStrlen(nsURI) == 0 ){
|
|
xmlFree(nsURI);
|
|
nsURI = NULL;
|
|
}
|
|
attr = (xmlNodePtr) xmlHasNsProp( self, name, nsURI );
|
|
if ( attr && attr->type == XML_ATTRIBUTE_NODE ) {
|
|
RETVAL = 1;
|
|
}
|
|
else {
|
|
RETVAL = 0;
|
|
}
|
|
|
|
xmlFree(name);
|
|
if ( nsURI != NULL ){
|
|
xmlFree(nsURI);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
_getAttribute( self, attr_name, useDomEncoding = 0 )
|
|
xmlNodePtr self
|
|
SV * attr_name
|
|
int useDomEncoding
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * ret = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
if( !name ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
ret = xmlGetNoNsProp(self, name);
|
|
if ( ret == NULL ) {
|
|
localname = xmlSplitQName2(name, &prefix);
|
|
if ( localname != NULL ) {
|
|
ns = xmlSearchNs( self->doc, self, prefix );
|
|
if ( ns != NULL ) {
|
|
ret = xmlGetNsProp(self, localname, ns->href);
|
|
}
|
|
if ( prefix != NULL) {
|
|
xmlFree( prefix );
|
|
}
|
|
xmlFree( localname );
|
|
}
|
|
}
|
|
xmlFree(name);
|
|
if ( ret ) {
|
|
if ( useDomEncoding ) {
|
|
RETVAL = nodeC2Sv(ret, self);
|
|
}
|
|
else {
|
|
RETVAL = C2Sv(ret, NULL);
|
|
}
|
|
xmlFree( ret );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_setAttribute( self, attr_name, attr_value )
|
|
xmlNodePtr self
|
|
SV * attr_name
|
|
SV * attr_value
|
|
PREINIT:
|
|
xmlChar * name = NULL;
|
|
xmlChar * value = NULL;
|
|
#if LIBXML_VERSION < 20621
|
|
xmlChar * prefix = NULL;
|
|
xmlChar * localname = NULL;
|
|
#endif
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
|
|
if ( !LibXML_test_node_name(name) ) {
|
|
xmlFree(name);
|
|
croak( "bad name" );
|
|
}
|
|
value = nodeSv2C(attr_value, self );
|
|
#if LIBXML_VERSION >= 20621
|
|
/*
|
|
* For libxml2-2.6.21 and later we can use just xmlSetProp
|
|
*/
|
|
xmlSetProp(self,name,value);
|
|
#else
|
|
/*
|
|
* but xmlSetProp does not work correctly for older libxml2 versions
|
|
* The following is copied from libxml2 source
|
|
* with xmlSplitQName3 replaced by xmlSplitQName2 for compatibility
|
|
* with older libxml2 versions
|
|
*/
|
|
localname = xmlSplitQName2(name, &prefix);
|
|
if (localname != NULL) {
|
|
xmlNsPtr ns;
|
|
ns = xmlSearchNs(self->doc, self, prefix);
|
|
if (prefix != NULL)
|
|
xmlFree(prefix);
|
|
if (ns != NULL)
|
|
xmlSetNsProp(self, ns, localname, value);
|
|
else
|
|
xmlSetNsProp(self, NULL, name, value);
|
|
xmlFree(localname);
|
|
} else {
|
|
xmlSetNsProp(self, NULL, name, value);
|
|
}
|
|
#endif
|
|
xmlFree(name);
|
|
xmlFree(value);
|
|
|
|
|
|
void
|
|
removeAttribute( self, attr_name )
|
|
xmlNodePtr self
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlAttrPtr xattr = NULL;
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
if ( name ) {
|
|
xattr = domGetAttrNode( self, name );
|
|
|
|
if ( xattr ) {
|
|
xmlUnlinkNode((xmlNodePtr)xattr);
|
|
if ( xattr->_private ) {
|
|
PmmFixOwner((ProxyNodePtr)xattr->_private, NULL);
|
|
}
|
|
else {
|
|
xmlFreeProp(xattr);
|
|
}
|
|
}
|
|
xmlFree(name);
|
|
}
|
|
|
|
SV*
|
|
getAttributeNode( self, attr_name )
|
|
xmlNodePtr self
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlAttrPtr ret = NULL;
|
|
CODE:
|
|
name = nodeSv2C(attr_name, self );
|
|
if ( !name ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
ret = domGetAttrNode( self, name );
|
|
xmlFree(name);
|
|
if ( ret ) {
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)ret,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
setAttributeNode( self, attr_node )
|
|
xmlNodePtr self
|
|
SV * attr_node
|
|
PREINIT:
|
|
xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
|
|
xmlAttrPtr ret = NULL;
|
|
INIT:
|
|
if ( attr == NULL ) {
|
|
croak( "lost attribute" );
|
|
}
|
|
CODE:
|
|
if ( attr != NULL && attr->type != XML_ATTRIBUTE_NODE ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( attr->doc != self->doc ) {
|
|
domImportNode( self->doc, (xmlNodePtr)attr, 1, 1);
|
|
}
|
|
ret = domGetAttrNode( self, attr->name );
|
|
if ( ret != NULL ) {
|
|
if ( ret != attr ) {
|
|
xmlReplaceNode( (xmlNodePtr)ret, (xmlNodePtr)attr );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
xmlAddChild( self, (xmlNodePtr)attr );
|
|
}
|
|
|
|
if ( attr->_private != NULL ) {
|
|
PmmFixOwner( SvPROXYNODE(attr_node), PmmPROXYNODE(self) );
|
|
}
|
|
|
|
if ( ret == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
|
|
PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
_getAttributeNS( self, namespaceURI, attr_name, useDomEncoding = 0 )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * attr_name
|
|
int useDomEncoding
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlChar * nsURI;
|
|
xmlChar * ret = NULL;
|
|
CODE:
|
|
name = nodeSv2C( attr_name, self );
|
|
nsURI = nodeSv2C( namespaceURI, self );
|
|
if ( !name ) {
|
|
xmlFree(nsURI);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( nsURI && xmlStrlen(nsURI) ) {
|
|
ret = xmlGetNsProp( self, name, nsURI );
|
|
}
|
|
else {
|
|
ret = xmlGetProp( self, name );
|
|
}
|
|
|
|
xmlFree( name );
|
|
if ( nsURI ) {
|
|
xmlFree( nsURI );
|
|
}
|
|
if ( ret ) {
|
|
if (useDomEncoding) {
|
|
RETVAL = nodeC2Sv( ret, self );
|
|
} else {
|
|
RETVAL = C2Sv( ret, NULL );
|
|
}
|
|
xmlFree( ret );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_setAttributeNS( self, namespaceURI, attr_name, attr_value )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * attr_name
|
|
SV * attr_value
|
|
PREINIT:
|
|
xmlChar * nsURI;
|
|
xmlChar * name = NULL;
|
|
xmlChar * value = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * prefix = NULL;
|
|
xmlNsPtr * all_ns = NULL;
|
|
int i;
|
|
INIT:
|
|
name = nodeSv2C( attr_name, self );
|
|
|
|
if ( !LibXML_test_node_name(name) ) {
|
|
xmlFree(name);
|
|
croak( "bad name" );
|
|
}
|
|
|
|
nsURI = nodeSv2C( namespaceURI, self );
|
|
localname = xmlSplitQName2(name, &prefix);
|
|
if ( localname ) {
|
|
xmlFree( name );
|
|
name = localname;
|
|
}
|
|
CODE:
|
|
value = nodeSv2C( attr_value, self );
|
|
|
|
if ( nsURI && xmlStrlen(nsURI) ) {
|
|
xs_warn( "found uri" );
|
|
|
|
ns = xmlSearchNsByHref( self->doc, self, nsURI );
|
|
|
|
/*
|
|
* check for any prefixed namespaces occluded by a default namespace
|
|
* because xmlSearchNsByHref will return default namespaces unless
|
|
* you are searching on an attribute node, which may not exist yet
|
|
*/
|
|
if ( ns && !ns->prefix )
|
|
{
|
|
all_ns = xmlGetNsList(self->doc, self);
|
|
if ( all_ns )
|
|
{
|
|
i = 0;
|
|
ns = all_ns[i];
|
|
while ( ns )
|
|
{
|
|
if ( ns->prefix && xmlStrEqual(ns->href, nsURI) )
|
|
{
|
|
break;
|
|
}
|
|
ns = all_ns[i++];
|
|
}
|
|
xmlFree(all_ns);
|
|
}
|
|
}
|
|
|
|
if ( !ns ) {
|
|
/* create new ns */
|
|
if ( prefix && xmlStrlen( prefix ) ) {
|
|
ns = xmlNewNs(self, nsURI , prefix);
|
|
}
|
|
else {
|
|
ns = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( nsURI && xmlStrlen(nsURI) && !ns ) {
|
|
if ( prefix ) xmlFree( prefix );
|
|
if ( nsURI ) xmlFree( nsURI );
|
|
xmlFree( name );
|
|
xmlFree( value );
|
|
croak( "bad ns attribute!" );
|
|
}
|
|
else {
|
|
/* warn( "set attribute %s->%s", name, value ); */
|
|
xmlSetNsProp( self, ns, name, value );
|
|
}
|
|
|
|
if ( prefix ) {
|
|
xmlFree( prefix );
|
|
}
|
|
if ( nsURI ) {
|
|
xmlFree( nsURI );
|
|
}
|
|
xmlFree( name );
|
|
xmlFree( value );
|
|
|
|
void
|
|
removeAttributeNS( self, namespaceURI, attr_name )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * nsURI;
|
|
xmlChar * name = NULL;
|
|
xmlAttrPtr xattr = NULL;
|
|
CODE:
|
|
nsURI = nodeSv2C( namespaceURI, self );
|
|
name = nodeSv2C( attr_name, self );
|
|
if ( ! name ) {
|
|
xmlFree(nsURI);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
if ( nsURI && xmlStrlen(nsURI) ) {
|
|
xattr = xmlHasNsProp( self, name, nsURI );
|
|
}
|
|
else {
|
|
xattr = xmlHasNsProp( self, name, NULL );
|
|
}
|
|
if ( xattr && xattr->type == XML_ATTRIBUTE_NODE ) {
|
|
xmlUnlinkNode((xmlNodePtr)xattr);
|
|
if ( xattr->_private ) {
|
|
PmmFixOwner((ProxyNodePtr)xattr->_private, NULL);
|
|
}
|
|
else {
|
|
xmlFreeProp(xattr);
|
|
}
|
|
}
|
|
xmlFree(nsURI);
|
|
xmlFree( name );
|
|
|
|
|
|
SV*
|
|
getAttributeNodeNS( self,namespaceURI, attr_name )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * attr_name
|
|
PREINIT:
|
|
xmlChar * nsURI;
|
|
xmlChar * name;
|
|
xmlAttrPtr ret = NULL;
|
|
CODE:
|
|
nsURI = nodeSv2C(namespaceURI, self );
|
|
name = nodeSv2C(attr_name, self );
|
|
if ( !name ) {
|
|
xmlFree(nsURI);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( nsURI && xmlStrlen(nsURI) ) {
|
|
ret = xmlHasNsProp( self, name, nsURI );
|
|
}
|
|
else {
|
|
ret = xmlHasNsProp( self, name, NULL );
|
|
}
|
|
xmlFree(name);
|
|
if ( nsURI ) {
|
|
xmlFree(nsURI);
|
|
}
|
|
if ( ret &&
|
|
ret->type == XML_ATTRIBUTE_NODE /* we don't want fixed attribute decls */
|
|
) {
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)ret,
|
|
PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
}
|
|
else {
|
|
/* warn("no prop\n"); */
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
setAttributeNodeNS( self, attr_node )
|
|
xmlNodePtr self
|
|
SV * attr_node
|
|
PREINIT:
|
|
xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
|
|
xmlNsPtr ns = NULL;
|
|
xmlAttrPtr ret = NULL;
|
|
INIT:
|
|
if ( attr == NULL ) {
|
|
croak( "lost attribute node" );
|
|
}
|
|
CODE:
|
|
if ( attr->type != XML_ATTRIBUTE_NODE ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
if ( attr->doc != self->doc ) {
|
|
domImportNode( self->doc, (xmlNodePtr)attr, 1,1);
|
|
}
|
|
|
|
|
|
ns = attr->ns;
|
|
if ( ns != NULL ) {
|
|
ret = xmlHasNsProp( self, ns->href, attr->name );
|
|
}
|
|
else {
|
|
ret = xmlHasNsProp( self, NULL, attr->name );
|
|
}
|
|
|
|
if ( ret && ret->type == XML_ATTRIBUTE_NODE ) {
|
|
if ( ret != attr ) {
|
|
xmlReplaceNode( (xmlNodePtr)ret, (xmlNodePtr)attr );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
xmlAddChild( self, (xmlNodePtr)attr );
|
|
xmlReconciliateNs(self->doc, self);
|
|
}
|
|
if ( attr->_private != NULL ) {
|
|
PmmFixOwner( SvPROXYNODE(attr_node), PmmPROXYNODE(self) );
|
|
}
|
|
if ( ret != NULL && ret->type == XML_ATTRIBUTE_NODE ) {
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
|
|
PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
|
|
} else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
removeAttributeNode( self, attr_node )
|
|
xmlNodePtr self
|
|
SV * attr_node
|
|
PREINIT:
|
|
xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode( attr_node );
|
|
xmlAttrPtr ret;
|
|
INIT:
|
|
if ( attr == NULL ) {
|
|
croak( "lost attribute node" );
|
|
}
|
|
CODE:
|
|
if ( attr->type != XML_ATTRIBUTE_NODE ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( attr->parent != self ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
ret = attr;
|
|
xmlUnlinkNode( (xmlNodePtr)attr );
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr)ret, NULL );
|
|
PmmFixOwner( SvPROXYNODE(RETVAL), NULL );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
appendText( self, string )
|
|
xmlNodePtr self
|
|
SV * string
|
|
ALIAS:
|
|
appendTextNode = 1
|
|
XML::LibXML::DocumentFragment::appendText = 2
|
|
XML::LibXML::DocumentFragment::appendTextNode = 3
|
|
PREINIT:
|
|
xmlChar * content = NULL;
|
|
INIT:
|
|
PERL_UNUSED_VAR(ix);
|
|
content = nodeSv2C( string, self );
|
|
if ( content == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( xmlStrlen(content) == 0 ) {
|
|
xmlFree( content );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
xmlNodeAddContent( self, content );
|
|
xmlFree(content);
|
|
|
|
|
|
void
|
|
appendTextChild( self, strname, strcontent=&PL_sv_undef, nsURI=&PL_sv_undef )
|
|
xmlNodePtr self
|
|
SV * strname
|
|
SV * strcontent
|
|
SV * nsURI
|
|
PREINIT:
|
|
xmlChar * name;
|
|
xmlChar * content = NULL;
|
|
xmlChar * encstr = NULL;
|
|
INIT:
|
|
name = nodeSv2C( strname, self );
|
|
if ( xmlStrlen(name) == 0 ) {
|
|
xmlFree(name);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
CODE:
|
|
content = nodeSv2C(strcontent, self);
|
|
if ( content && xmlStrlen( content ) == 0 ) {
|
|
xmlFree(content);
|
|
content=NULL;
|
|
}
|
|
else if ( content ) {
|
|
encstr = xmlEncodeEntitiesReentrant( self->doc, content );
|
|
xmlFree(content);
|
|
}
|
|
|
|
xmlNewChild( self, NULL, name, encstr );
|
|
|
|
if ( encstr )
|
|
xmlFree(encstr);
|
|
xmlFree(name);
|
|
|
|
SV *
|
|
addNewChild( self, namespaceURI, nodename )
|
|
xmlNodePtr self
|
|
SV * namespaceURI
|
|
SV * nodename
|
|
ALIAS:
|
|
XML::LibXML::DocumentFragment::addNewChild = 1
|
|
PREINIT:
|
|
xmlChar * nsURI = NULL;
|
|
xmlChar * name = NULL;
|
|
xmlChar * localname = NULL;
|
|
xmlChar * prefix = NULL;
|
|
xmlNodePtr newNode = NULL;
|
|
xmlNodePtr prev = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
name = nodeSv2C(nodename, self);
|
|
if ( name && xmlStrlen( name ) == 0 ) {
|
|
xmlFree(name);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
|
|
nsURI = nodeSv2C(namespaceURI, self);
|
|
if ( nsURI && xmlStrlen( nsURI ) == 0 ) {
|
|
xmlFree(nsURI);
|
|
nsURI=NULL;
|
|
}
|
|
|
|
if ( nsURI != NULL ) {
|
|
localname = xmlSplitQName2(name, &prefix);
|
|
ns = xmlSearchNsByHref(self->doc, self, nsURI);
|
|
|
|
newNode = xmlNewDocNode(self->doc,
|
|
ns,
|
|
localname?localname:name,
|
|
NULL);
|
|
if ( ns == NULL ) {
|
|
xmlSetNs(newNode,xmlNewNs(newNode, nsURI, prefix));
|
|
}
|
|
|
|
xmlFree(localname);
|
|
xmlFree(prefix);
|
|
xmlFree(nsURI);
|
|
}
|
|
else {
|
|
newNode = xmlNewDocNode(self->doc,
|
|
NULL,
|
|
name,
|
|
NULL);
|
|
}
|
|
xmlFree(name);
|
|
/* add the node to the parent node */
|
|
newNode->type = XML_ELEMENT_NODE;
|
|
newNode->parent = self;
|
|
newNode->doc = self->doc;
|
|
|
|
if (self->children == NULL) {
|
|
self->children = newNode;
|
|
self->last = newNode;
|
|
} else {
|
|
prev = self->last;
|
|
prev->next = newNode;
|
|
newNode->prev = prev;
|
|
self->last = newNode;
|
|
}
|
|
RETVAL = PmmNodeToSv(newNode, PmmOWNERPO(PmmPROXYNODE(self)) );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Text
|
|
|
|
SV *
|
|
new( CLASS, content )
|
|
SV * content
|
|
PREINIT:
|
|
xmlChar * data;
|
|
xmlNodePtr newNode;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
data = Sv2C(content, NULL);
|
|
newNode = xmlNewText( data );
|
|
xmlFree(data);
|
|
if( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( NULL );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
substringData( self, offset, length )
|
|
xmlNodePtr self
|
|
int offset
|
|
int length
|
|
PREINIT:
|
|
xmlChar * data = NULL;
|
|
xmlChar * substr = NULL;
|
|
CODE:
|
|
if ( offset >= 0 && length >= 0 ) {
|
|
data = domGetNodeValue( self );
|
|
if ( data != NULL ) {
|
|
substr = xmlUTF8Strsub( data, offset, length );
|
|
RETVAL = C2Sv( (const xmlChar*)substr, NULL );
|
|
xmlFree( substr );
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setData( self, value )
|
|
xmlNodePtr self
|
|
SV * value
|
|
ALIAS:
|
|
XML::LibXML::Attr::setValue = 1
|
|
XML::LibXML::PI::_setData = 2
|
|
PREINIT:
|
|
xmlChar * encstr = NULL;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
encstr = nodeSv2C(value,self);
|
|
domSetNodeValue( self, encstr );
|
|
xmlFree(encstr);
|
|
|
|
void
|
|
appendData( self, value )
|
|
xmlNodePtr self
|
|
SV * value
|
|
PREINIT:
|
|
xmlChar * encstring = NULL;
|
|
int strlen = 0;
|
|
CODE:
|
|
encstring = Sv2C( value,
|
|
self->doc!=NULL ? self->doc->encoding : NULL );
|
|
|
|
if ( encstring != NULL ) {
|
|
strlen = xmlStrlen( encstring );
|
|
xmlTextConcat( self, encstring, strlen );
|
|
xmlFree( encstring );
|
|
}
|
|
|
|
void
|
|
insertData( self, offset, value )
|
|
xmlNodePtr self
|
|
int offset
|
|
SV * value
|
|
PREINIT:
|
|
xmlChar * after= NULL;
|
|
xmlChar * data = NULL;
|
|
xmlChar * new = NULL;
|
|
xmlChar * encstring = NULL;
|
|
int dl = 0;
|
|
CODE:
|
|
if ( offset >= 0 ) {
|
|
encstring = Sv2C( value,
|
|
self->doc!=NULL ? self->doc->encoding : NULL );
|
|
if ( encstring != NULL && xmlStrlen( encstring ) > 0 ) {
|
|
data = domGetNodeValue(self);
|
|
if ( data != NULL && xmlStrlen( data ) > 0 ) {
|
|
if ( xmlUTF8Strlen( data ) < offset ) {
|
|
data = xmlStrcat( data, encstring );
|
|
domSetNodeValue( self, data );
|
|
}
|
|
else {
|
|
dl = xmlUTF8Strlen( data ) - offset;
|
|
|
|
if ( offset > 0 )
|
|
new = xmlUTF8Strsub(data, 0, offset );
|
|
|
|
after = xmlUTF8Strsub(data, offset, dl );
|
|
|
|
if ( new != NULL ) {
|
|
new = xmlStrcat(new, encstring );
|
|
}
|
|
else {
|
|
new = xmlStrdup( encstring );
|
|
}
|
|
|
|
if ( after != NULL )
|
|
new = xmlStrcat(new, after );
|
|
|
|
domSetNodeValue( self, new );
|
|
|
|
xmlFree( new );
|
|
xmlFree( after );
|
|
}
|
|
xmlFree( data );
|
|
}
|
|
else {
|
|
domSetNodeValue( self, encstring );
|
|
}
|
|
xmlFree(encstring);
|
|
}
|
|
}
|
|
|
|
void
|
|
deleteData( self, offset, length )
|
|
xmlNodePtr self
|
|
int offset
|
|
int length
|
|
PREINIT:
|
|
xmlChar * data = NULL;
|
|
xmlChar * after = NULL;
|
|
xmlChar * new = NULL;
|
|
int len = 0;
|
|
int dl1 = 0;
|
|
int dl2 = 0;
|
|
CODE:
|
|
if ( length > 0 && offset >= 0 ) {
|
|
data = domGetNodeValue(self);
|
|
len = xmlUTF8Strlen( data );
|
|
if ( data != NULL
|
|
&& len > 0
|
|
&& len > offset ) {
|
|
dl1 = offset + length;
|
|
if ( offset > 0 )
|
|
new = xmlUTF8Strsub( data, 0, offset );
|
|
|
|
if ( len > dl1 ) {
|
|
dl2 = len - dl1;
|
|
after = xmlUTF8Strsub( data, dl1, dl2 );
|
|
if ( new != NULL ) {
|
|
new = xmlStrcat( new, after );
|
|
xmlFree(after);
|
|
}
|
|
else {
|
|
new = after;
|
|
}
|
|
}
|
|
|
|
domSetNodeValue( self, new );
|
|
xmlFree(new);
|
|
}
|
|
}
|
|
|
|
void
|
|
replaceData( self, offset,length, value )
|
|
xmlNodePtr self
|
|
int offset
|
|
int length
|
|
SV * value
|
|
PREINIT:
|
|
xmlChar * after= NULL;
|
|
xmlChar * data = NULL;
|
|
xmlChar * new = NULL;
|
|
xmlChar * encstring = NULL;
|
|
int len = 0;
|
|
int dl1 = 0;
|
|
int dl2 = 0;
|
|
CODE:
|
|
if ( offset >= 0 ) {
|
|
encstring = Sv2C( value,
|
|
self->doc!=NULL ? self->doc->encoding : NULL );
|
|
|
|
if ( encstring != NULL && xmlStrlen( encstring ) > 0 ) {
|
|
data = domGetNodeValue(self);
|
|
len = xmlUTF8Strlen( data );
|
|
|
|
if ( data != NULL
|
|
&& len > 0
|
|
&& len > offset ) {
|
|
|
|
dl1 = offset + length;
|
|
if ( dl1 < len ) {
|
|
dl2 = xmlUTF8Strlen( data ) - dl1;
|
|
if ( offset > 0 ) {
|
|
new = xmlUTF8Strsub(data, 0, offset );
|
|
new = xmlStrcat(new, encstring );
|
|
}
|
|
else {
|
|
new = xmlStrdup( encstring );
|
|
}
|
|
|
|
after = xmlUTF8Strsub(data, dl1, dl2 );
|
|
new = xmlStrcat(new, after );
|
|
|
|
domSetNodeValue( self, new );
|
|
|
|
xmlFree( new );
|
|
xmlFree( after );
|
|
}
|
|
else {
|
|
/* replace until end! */
|
|
if ( offset > 0 ) {
|
|
new = xmlUTF8Strsub(data, 0, offset );
|
|
new = xmlStrcat(new, encstring );
|
|
}
|
|
else {
|
|
new = xmlStrdup( encstring );
|
|
}
|
|
domSetNodeValue( self, new );
|
|
xmlFree( new );
|
|
}
|
|
xmlFree( data );
|
|
}
|
|
|
|
xmlFree(encstring);
|
|
}
|
|
}
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Comment
|
|
|
|
SV *
|
|
new( CLASS, content )
|
|
SV * content
|
|
PREINIT:
|
|
xmlChar * encstring;
|
|
xmlNodePtr newNode;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
encstring = Sv2C(content, NULL);
|
|
newNode = xmlNewComment( encstring );
|
|
xmlFree(encstring);
|
|
if( newNode != NULL ) {
|
|
docfrag = PmmNewFragment( NULL );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::CDATASection
|
|
|
|
SV *
|
|
new( CLASS , content )
|
|
SV * content
|
|
PREINIT:
|
|
xmlChar * encstring;
|
|
xmlNodePtr newNode;
|
|
ProxyNodePtr docfrag = NULL;
|
|
CODE:
|
|
encstring = Sv2C(content, NULL);
|
|
newNode = xmlNewCDataBlock( NULL , encstring, xmlStrlen( encstring ) );
|
|
xmlFree(encstring);
|
|
if ( newNode != NULL ){
|
|
docfrag = PmmNewFragment( NULL );
|
|
xmlAddChild(PmmNODE(docfrag), newNode);
|
|
RETVAL = PmmNodeToSv(newNode,docfrag);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::DocumentFragment
|
|
|
|
SV*
|
|
new( CLASS )
|
|
PREINIT:
|
|
xmlNodePtr real_doc=NULL;
|
|
CODE:
|
|
real_doc = xmlNewDocFragment( NULL );
|
|
RETVAL = PmmNodeToSv( real_doc, NULL );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Attr
|
|
|
|
SV*
|
|
new( CLASS, pname, pvalue )
|
|
SV * pname
|
|
SV * pvalue
|
|
PREINIT:
|
|
xmlNodePtr attr = NULL;
|
|
xmlChar * name;
|
|
xmlChar * value;
|
|
CODE:
|
|
name = Sv2C(pname,NULL);
|
|
value = Sv2C(pvalue,NULL);
|
|
if ( name == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
attr = (xmlNodePtr)xmlNewProp( NULL, name, value );
|
|
attr->doc = NULL;
|
|
RETVAL = PmmNodeToSv(attr,NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV*
|
|
parentElement( self )
|
|
ALIAS:
|
|
XML::LibXML::Attr::getParentNode = 1
|
|
XML::LibXML::Attr::getNextSibling = 2
|
|
XML::LibXML::Attr::getPreviousSibling = 3
|
|
XML::LibXML::Attr::nextSibling = 4
|
|
XML::LibXML::Attr::previousSibling = 5
|
|
CODE:
|
|
/* override the original parentElement(), since this an attribute is
|
|
* not part of the main tree
|
|
*/
|
|
|
|
PERL_UNUSED_VAR(ix);
|
|
XSRETURN_UNDEF;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
serializeContent( self, useDomEncoding = &PL_sv_undef )
|
|
SV * self
|
|
SV * useDomEncoding
|
|
PREINIT:
|
|
xmlBufferPtr buffer;
|
|
const xmlChar *ret = NULL;
|
|
xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
|
|
CODE:
|
|
buffer = xmlBufferCreate();
|
|
domAttrSerializeContent(buffer, node);
|
|
if ( xmlBufferLength(buffer) > 0 ) {
|
|
ret = xmlBufferContent( buffer );
|
|
}
|
|
if ( ret != NULL ) {
|
|
if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
|
|
RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(node))) ;
|
|
}
|
|
else {
|
|
RETVAL = C2Sv((xmlChar*)ret, NULL) ;
|
|
}
|
|
xmlBufferFree( buffer );
|
|
}
|
|
else {
|
|
xmlBufferFree( buffer );
|
|
xs_warn("Failed to convert attribute to string");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
toString(self , format=0, useDomEncoding = &PL_sv_undef )
|
|
SV * self
|
|
SV * useDomEncoding
|
|
int format
|
|
ALIAS:
|
|
XML::LibXML::Attr::serialize = 1
|
|
PREINIT:
|
|
xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
|
|
xmlBufferPtr buffer;
|
|
const xmlChar *ret = NULL;
|
|
CODE:
|
|
/* we add an extra method for serializing attributes since
|
|
XML::LibXML::Node::toString causes segmentation fault inside
|
|
libxml2
|
|
*/
|
|
PERL_UNUSED_VAR(ix);
|
|
buffer = xmlBufferCreate();
|
|
xmlBufferAdd(buffer, BAD_CAST " ", 1);
|
|
if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
|
|
xmlBufferAdd(buffer, node->ns->prefix, xmlStrlen(node->ns->prefix));
|
|
xmlBufferAdd(buffer, BAD_CAST ":", 1);
|
|
}
|
|
xmlBufferAdd(buffer, node->name, xmlStrlen(node->name));
|
|
xmlBufferAdd(buffer, BAD_CAST "=\"", 2);
|
|
domAttrSerializeContent(buffer, node);
|
|
xmlBufferAdd(buffer, BAD_CAST "\"", 1);
|
|
|
|
if ( xmlBufferLength(buffer) > 0 ) {
|
|
ret = xmlBufferContent( buffer );
|
|
}
|
|
if ( ret != NULL ) {
|
|
if ( useDomEncoding != &PL_sv_undef && SvTRUE(useDomEncoding) ) {
|
|
RETVAL = nodeC2Sv((xmlChar*)ret, PmmNODE(PmmPROXYNODE(node))) ;
|
|
}
|
|
else {
|
|
RETVAL = C2Sv((xmlChar*)ret, NULL) ;
|
|
}
|
|
xmlBufferFree( buffer );
|
|
}
|
|
else {
|
|
xmlBufferFree( buffer );
|
|
xs_warn("Failed to convert attribute to string");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
_setNamespace(self, namespaceURI, namespacePrefix = &PL_sv_undef )
|
|
SV * self
|
|
SV * namespaceURI
|
|
SV * namespacePrefix
|
|
PREINIT:
|
|
xmlAttrPtr node = (xmlAttrPtr)PmmSvNode(self);
|
|
xmlChar * nsURI = nodeSv2C(namespaceURI,(xmlNodePtr)node);
|
|
xmlChar * nsPrefix = NULL;
|
|
xmlNsPtr ns = NULL;
|
|
INIT:
|
|
if ( node == NULL ) {
|
|
croak( "lost node" );
|
|
}
|
|
CODE:
|
|
if ( !nsURI || xmlStrlen(nsURI)==0 ){
|
|
xmlSetNs((xmlNodePtr)node, NULL);
|
|
RETVAL = 1;
|
|
}
|
|
if ( !node->parent ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
nsPrefix = nodeSv2C(namespacePrefix, (xmlNodePtr)node);
|
|
if ( (ns = xmlSearchNs(node->doc, node->parent, nsPrefix)) &&
|
|
xmlStrEqual( ns->href, nsURI) ) {
|
|
/* same uri and prefix */
|
|
RETVAL = 1;
|
|
}
|
|
else if ( (ns = xmlSearchNsByHref(node->doc, node->parent, nsURI)) ) {
|
|
/* set uri, but with a different prefix */
|
|
RETVAL = 1;
|
|
}
|
|
else if (! RETVAL)
|
|
RETVAL = 0;
|
|
|
|
if ( ns ) {
|
|
if ( ns->prefix ) {
|
|
xmlSetNs((xmlNodePtr)node, ns);
|
|
} else {
|
|
RETVAL = 0;
|
|
}
|
|
}
|
|
xmlFree(nsPrefix);
|
|
xmlFree(nsURI);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isId( self )
|
|
SV * self
|
|
PREINIT:
|
|
xmlAttrPtr attr = (xmlAttrPtr)PmmSvNode(self);
|
|
xmlNodePtr elem;
|
|
CODE:
|
|
if ( attr == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
elem = attr->parent;
|
|
if ( elem == NULL || elem->doc == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = xmlIsID( elem->doc, elem, attr );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Namespace
|
|
|
|
SV*
|
|
new(CLASS, namespaceURI, namespacePrefix=&PL_sv_undef)
|
|
const char * CLASS
|
|
SV * namespaceURI
|
|
SV * namespacePrefix
|
|
PREINIT:
|
|
xmlNsPtr ns = NULL;
|
|
xmlChar* nsURI;
|
|
xmlChar* nsPrefix;
|
|
CODE:
|
|
RETVAL = &PL_sv_undef;
|
|
|
|
nsURI = Sv2C(namespaceURI,NULL);
|
|
if ( !nsURI ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
nsPrefix = Sv2C(namespacePrefix, NULL);
|
|
ns = xmlNewNs(NULL, nsURI, nsPrefix);
|
|
if ( ns ) {
|
|
RETVAL = NEWSV(0,0);
|
|
RETVAL = sv_setref_pv( RETVAL,
|
|
CLASS,
|
|
(void*)ns);
|
|
}
|
|
xmlFree(nsURI);
|
|
if ( nsPrefix )
|
|
xmlFree(nsPrefix);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY(self)
|
|
SV * self
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
CODE:
|
|
xs_warn( "DESTROY NS" );
|
|
if (ns) {
|
|
xmlFreeNs(ns);
|
|
}
|
|
|
|
int
|
|
nodeType(self)
|
|
SV * self
|
|
ALIAS:
|
|
getType = 1
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = ns->type;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
declaredURI(self)
|
|
SV * self
|
|
ALIAS:
|
|
value = 1
|
|
nodeValue = 2
|
|
getData = 3
|
|
getValue = 4
|
|
value2 = 5
|
|
href = 6
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
xmlChar * href;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
href = xmlStrdup(ns->href);
|
|
RETVAL = C2Sv(href, NULL);
|
|
xmlFree(href);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
declaredPrefix(self)
|
|
SV * self
|
|
ALIAS:
|
|
localname = 1
|
|
getLocalName = 2
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
xmlChar * prefix;
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
prefix = xmlStrdup(ns->prefix);
|
|
RETVAL = C2Sv(prefix, NULL);
|
|
xmlFree(prefix);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
unique_key( self )
|
|
SV * self
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
xmlChar* key;
|
|
CODE:
|
|
/* Concatenate prefix and URI with vertical bar dividing*/
|
|
key = xmlStrdup(ns->prefix);
|
|
key = xmlStrcat(key, (const xmlChar*)"|");
|
|
key = xmlStrcat(key, ns->href);
|
|
RETVAL = C2Sv(key, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_isEqual(self, ref_node)
|
|
SV * self
|
|
SV * ref_node
|
|
PREINIT:
|
|
xmlNsPtr ns = INT2PTR(xmlNsPtr,SvIV(SvRV(self)));
|
|
xmlNsPtr ons = INT2PTR(xmlNsPtr,SvIV(SvRV(ref_node)));
|
|
CODE:
|
|
RETVAL = 0;
|
|
if ( ns == ons ) {
|
|
RETVAL = 1;
|
|
}
|
|
else if ( xmlStrEqual(ns->href, ons->href)
|
|
&& xmlStrEqual(ns->prefix, ons->prefix) ) {
|
|
RETVAL = 1;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Dtd
|
|
|
|
SV *
|
|
new(CLASS, external, system)
|
|
char * external
|
|
char * system
|
|
ALIAS:
|
|
parse_uri = 1
|
|
PREINIT:
|
|
xmlDtdPtr dtd = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
INIT_ERROR_HANDLER;
|
|
dtd = xmlParseDTD((const xmlChar*)external, (const xmlChar*)system);
|
|
if ( dtd == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
XSRETURN_UNDEF;
|
|
} else {
|
|
xmlSetTreeDoc((xmlNodePtr)dtd, NULL);
|
|
RETVAL = PmmNodeToSv( (xmlNodePtr) dtd, NULL );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
systemId( self )
|
|
xmlDtdPtr self
|
|
ALIAS:
|
|
getSystemId = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->SystemID == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
} else {
|
|
RETVAL = C2Sv(self->SystemID,NULL);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
publicId( self )
|
|
xmlDtdPtr self
|
|
ALIAS:
|
|
getPublicId = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
if ( self->ExternalID == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
} else {
|
|
RETVAL = C2Sv(self->ExternalID,NULL);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
parse_string(CLASS, str, ...)
|
|
char * str
|
|
PREINIT:
|
|
xmlDtdPtr res;
|
|
SV * encoding_sv;
|
|
xmlParserInputBufferPtr buffer;
|
|
xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
|
|
xmlChar * new_string;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
if (items > 2) {
|
|
encoding_sv = ST(2);
|
|
if (items > 3) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
croak("parse_string: too many parameters");
|
|
}
|
|
/* warn("getting encoding...\n"); */
|
|
enc = xmlParseCharEncoding(SvPV_nolen(encoding_sv));
|
|
if (enc == XML_CHAR_ENCODING_ERROR) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(1);
|
|
croak("Parse of encoding %s failed", SvPV_nolen(encoding_sv));
|
|
}
|
|
}
|
|
buffer = xmlAllocParserInputBuffer(enc);
|
|
/* buffer = xmlParserInputBufferCreateMem(str, xmlStrlen(str), enc); */
|
|
if ( !buffer) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(1);
|
|
croak("cannot create buffer!\n" );
|
|
}
|
|
new_string = xmlStrdup((const xmlChar*)str);
|
|
xmlParserInputBufferPush(buffer, xmlStrlen(new_string), (const char*)new_string);
|
|
|
|
res = xmlIOParseDTD(NULL, buffer, enc);
|
|
|
|
/* NOTE: xmlIOParseDTD is documented to free its InputBuffer */
|
|
xmlFree(new_string);
|
|
if ( res && LibXML_will_die_ctx(saved_error, 0) )
|
|
xmlFreeDtd( res );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if (res == NULL) {
|
|
croak("no DTD parsed!");
|
|
}
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)res, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
#ifdef HAVE_SCHEMAS
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::RelaxNG
|
|
|
|
void
|
|
DESTROY( self )
|
|
xmlRelaxNGPtr self
|
|
CODE:
|
|
xmlRelaxNGFree( self );
|
|
|
|
|
|
xmlRelaxNGPtr
|
|
parse_location( self, url, parser_options = 0, recover = FALSE )
|
|
char * url
|
|
int parser_options
|
|
bool recover
|
|
PREINIT:
|
|
const char * CLASS = "XML::LibXML::RelaxNG";
|
|
xmlRelaxNGParserCtxtPtr rngctxt = NULL;
|
|
xmlExternalEntityLoader old_ext_ent_loader = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
rngctxt = xmlRelaxNGNewParserCtxt( url );
|
|
if ( rngctxt == NULL ) {
|
|
croak( "failed to initialize RelaxNG parser" );
|
|
}
|
|
#ifndef WITH_SERRORS
|
|
/* Register Error callbacks */
|
|
xmlRelaxNGSetParserErrors( rngctxt,
|
|
(xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
#endif
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) ) {
|
|
old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
|
|
RETVAL = xmlRelaxNGParse( rngctxt );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) )
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)old_ext_ent_loader );
|
|
|
|
xmlRelaxNGFreeParserCtxt( rngctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR((RETVAL == NULL) ? 0 : recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
xmlRelaxNGPtr
|
|
parse_buffer( self, perlstring, parser_options = 0, recover = FALSE )
|
|
SV * perlstring
|
|
int parser_options
|
|
bool recover
|
|
PREINIT:
|
|
const char * CLASS = "XML::LibXML::RelaxNG";
|
|
xmlRelaxNGParserCtxtPtr rngctxt = NULL;
|
|
xmlExternalEntityLoader old_ext_ent_loader = NULL;
|
|
char * string = NULL;
|
|
STRLEN len = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
string = SvPV( perlstring, len );
|
|
if ( string == NULL ) {
|
|
croak( "cannot parse empty string" );
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
rngctxt = xmlRelaxNGNewMemParserCtxt( string,len );
|
|
if ( rngctxt == NULL ) {
|
|
croak( "failed to initialize RelaxNG parser" );
|
|
}
|
|
#ifndef WITH_SERRORS
|
|
/* Register Error callbacks */
|
|
xmlRelaxNGSetParserErrors( rngctxt,
|
|
(xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
#endif
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) ) {
|
|
old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
|
|
RETVAL = xmlRelaxNGParse( rngctxt );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) )
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)old_ext_ent_loader );
|
|
|
|
xmlRelaxNGFreeParserCtxt( rngctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR((RETVAL == NULL) ? 0 : recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
xmlRelaxNGPtr
|
|
parse_document( self, doc, parser_options = 0, recover = FALSE )
|
|
xmlDocPtr doc
|
|
int parser_options
|
|
bool recover
|
|
PREINIT:
|
|
const char * CLASS = "XML::LibXML::RelaxNG";
|
|
xmlRelaxNGParserCtxtPtr rngctxt = NULL;
|
|
xmlExternalEntityLoader old_ext_ent_loader = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
rngctxt = xmlRelaxNGNewDocParserCtxt( doc );
|
|
if ( rngctxt == NULL ) {
|
|
croak( "failed to initialize RelaxNG parser" );
|
|
}
|
|
#ifndef WITH_SERRORS
|
|
/* Register Error callbacks */
|
|
xmlRelaxNGSetParserErrors( rngctxt,
|
|
(xmlRelaxNGValidityErrorFunc) LibXML_error_handler_ctx,
|
|
(xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
#endif
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) ) {
|
|
old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
|
|
RETVAL = xmlRelaxNGParse( rngctxt );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) )
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)old_ext_ent_loader );
|
|
|
|
xmlRelaxNGFreeParserCtxt( rngctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR((RETVAL == NULL) ? 0 : recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
validate( self, doc )
|
|
xmlRelaxNGPtr self
|
|
xmlDocPtr doc
|
|
PREINIT:
|
|
xmlRelaxNGValidCtxtPtr vctxt = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
if (doc) {
|
|
PmmClearPSVI(doc);
|
|
PmmInvalidatePSVI(doc);
|
|
}
|
|
vctxt = xmlRelaxNGNewValidCtxt( self );
|
|
if ( vctxt == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
croak( "cannot initialize the validation context" );
|
|
}
|
|
#ifndef WITH_SERRORS
|
|
/* Register Error callbacks */
|
|
xmlRelaxNGSetValidErrors( vctxt,
|
|
(xmlRelaxNGValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlRelaxNGValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
#endif /* WITH_SERRORS */
|
|
/* ** test only **
|
|
xmlRelaxNGSetValidErrors( vctxt,
|
|
(xmlRelaxNGValidityErrorFunc)fprintf,
|
|
(xmlRelaxNGValidityWarningFunc)fprintf,
|
|
stderr );
|
|
*/
|
|
RETVAL = xmlRelaxNGValidateDoc( vctxt, doc );
|
|
xmlRelaxNGFreeValidCtxt( vctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( RETVAL == 1 ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( RETVAL == -1 ) {
|
|
croak( "API Error" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Schema
|
|
|
|
void
|
|
DESTROY( self )
|
|
xmlSchemaPtr self
|
|
CODE:
|
|
xmlSchemaFree( self );
|
|
|
|
|
|
xmlSchemaPtr
|
|
parse_location( self, url, parser_options = 0, recover = FALSE )
|
|
char * url
|
|
int parser_options
|
|
bool recover
|
|
PREINIT:
|
|
const char * CLASS = "XML::LibXML::Schema";
|
|
xmlSchemaParserCtxtPtr rngctxt = NULL;
|
|
xmlExternalEntityLoader old_ext_ent_loader = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
rngctxt = xmlSchemaNewParserCtxt( url );
|
|
if ( rngctxt == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
croak( "failed to initialize Schema parser" );
|
|
}
|
|
|
|
/* Register Error callbacks */
|
|
xmlSchemaSetParserErrors( rngctxt,
|
|
(xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) ) {
|
|
old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
|
|
RETVAL = xmlSchemaParse( rngctxt );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) )
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)old_ext_ent_loader );
|
|
|
|
xmlSchemaFreeParserCtxt( rngctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR((RETVAL == NULL) ? 0 : recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
xmlSchemaPtr
|
|
parse_buffer( self, perlstring, parser_options = 0, recover = FALSE )
|
|
SV * perlstring
|
|
int parser_options
|
|
bool recover
|
|
PREINIT:
|
|
const char * CLASS = "XML::LibXML::Schema";
|
|
xmlSchemaParserCtxtPtr rngctxt = NULL;
|
|
xmlExternalEntityLoader old_ext_ent_loader = NULL;
|
|
char * string = NULL;
|
|
STRLEN len = 0;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
string = SvPV( perlstring, len );
|
|
if ( string == NULL ) {
|
|
croak( "cannot parse empty string" );
|
|
}
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
rngctxt = xmlSchemaNewMemParserCtxt( string,len );
|
|
if ( rngctxt == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
croak( "failed to initialize Schema parser" );
|
|
}
|
|
|
|
/* Register Error callbacks */
|
|
xmlSchemaSetParserErrors( rngctxt,
|
|
(xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) ) {
|
|
old_ext_ent_loader = xmlGetExternalEntityLoader();
|
|
xmlSetExternalEntityLoader( xmlNoNetExternalEntityLoader );
|
|
}
|
|
|
|
RETVAL = xmlSchemaParse( rngctxt );
|
|
|
|
if ( EXTERNAL_ENTITY_LOADER_FUNC == NULL && (parser_options & XML_PARSE_NONET) )
|
|
xmlSetExternalEntityLoader( (xmlExternalEntityLoader)old_ext_ent_loader );
|
|
|
|
xmlSchemaFreeParserCtxt( rngctxt );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR((RETVAL == NULL) ? 0 : recover);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
validate( self, node )
|
|
xmlSchemaPtr self
|
|
xmlNodePtr node
|
|
PREINIT:
|
|
xmlSchemaValidCtxtPtr vctxt = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
if (node->type == XML_DOCUMENT_NODE) {
|
|
PmmClearPSVI((xmlDocPtr)node);
|
|
PmmInvalidatePSVI((xmlDocPtr)node);
|
|
}
|
|
vctxt = xmlSchemaNewValidCtxt( self );
|
|
if ( vctxt == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
croak( "cannot initialize the validation context" );
|
|
}
|
|
|
|
/* Register Error callbacks */
|
|
xmlSchemaSetValidErrors( vctxt,
|
|
(xmlSchemaValidityErrorFunc)LibXML_error_handler_ctx,
|
|
(xmlSchemaValidityWarningFunc)LibXML_error_handler_ctx,
|
|
saved_error );
|
|
|
|
if (node->type == XML_DOCUMENT_NODE) {
|
|
RETVAL = xmlSchemaValidateDoc(vctxt, (xmlDocPtr)node);
|
|
}
|
|
else {
|
|
RETVAL = xmlSchemaValidateOneElement(vctxt, node);
|
|
}
|
|
|
|
xmlSchemaFreeValidCtxt( vctxt );
|
|
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( RETVAL > 0 ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( RETVAL == -1 ) {
|
|
croak( "API Error" );
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#endif /* HAVE_SCHEMAS */
|
|
|
|
MODULE = XML::LibXML::XPathContext PACKAGE = XML::LibXML::XPathContext
|
|
|
|
# PROTOTYPES: DISABLE
|
|
|
|
SV*
|
|
new( CLASS, ... )
|
|
const char * CLASS
|
|
PREINIT:
|
|
SV * pnode = &PL_sv_undef;
|
|
INIT:
|
|
xmlXPathContextPtr ctxt;
|
|
CODE:
|
|
if( items > 1 )
|
|
pnode = ST(1);
|
|
|
|
ctxt = xmlXPathNewContext( NULL );
|
|
ctxt->namespaces = NULL;
|
|
|
|
New(0, ctxt->user, sizeof(XPathContextData), XPathContextData);
|
|
if (ctxt->user == NULL) {
|
|
croak("XPathContext: failed to allocate proxy object\n");
|
|
}
|
|
|
|
if (SvOK(pnode)) {
|
|
XPathContextDATA(ctxt)->node = newSVsv(pnode);
|
|
} else {
|
|
XPathContextDATA(ctxt)->node = &PL_sv_undef;
|
|
}
|
|
|
|
XPathContextDATA(ctxt)->pool = NULL;
|
|
XPathContextDATA(ctxt)->varLookup = NULL;
|
|
XPathContextDATA(ctxt)->varData = NULL;
|
|
|
|
xmlXPathRegisterFunc(ctxt,
|
|
(const xmlChar *) "document",
|
|
perlDocumentFunction);
|
|
|
|
RETVAL = NEWSV(0,0),
|
|
RETVAL = sv_setref_pv( RETVAL,
|
|
CLASS,
|
|
(void*)ctxt );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
CODE:
|
|
xs_warn( "DESTROY XPATH CONTEXT" );
|
|
if (ctxt) {
|
|
if (XPathContextDATA(ctxt) != NULL) {
|
|
if (XPathContextDATA(ctxt)->node != NULL &&
|
|
SvOK(XPathContextDATA(ctxt)->node)) {
|
|
SvREFCNT_dec(XPathContextDATA(ctxt)->node);
|
|
}
|
|
if (XPathContextDATA(ctxt)->varLookup != NULL &&
|
|
SvOK(XPathContextDATA(ctxt)->varLookup)) {
|
|
SvREFCNT_dec(XPathContextDATA(ctxt)->varLookup);
|
|
}
|
|
if (XPathContextDATA(ctxt)->varData != NULL &&
|
|
SvOK(XPathContextDATA(ctxt)->varData)) {
|
|
SvREFCNT_dec(XPathContextDATA(ctxt)->varData);
|
|
}
|
|
if (XPathContextDATA(ctxt)->pool != NULL &&
|
|
SvOK(XPathContextDATA(ctxt)->pool)) {
|
|
SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
|
|
}
|
|
Safefree(XPathContextDATA(ctxt));
|
|
}
|
|
|
|
if (ctxt->namespaces != NULL) {
|
|
xmlFree( ctxt->namespaces );
|
|
}
|
|
if (ctxt->funcLookupData != NULL && SvROK((SV*)ctxt->funcLookupData)
|
|
&& SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
|
|
SvREFCNT_dec((SV *)ctxt->funcLookupData);
|
|
}
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
}
|
|
|
|
SV*
|
|
getContextNode( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
CODE:
|
|
if(XPathContextDATA(ctxt)->node != NULL) {
|
|
RETVAL = newSVsv(XPathContextDATA(ctxt)->node);
|
|
} else {
|
|
RETVAL = &PL_sv_undef;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
getContextPosition( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
CODE:
|
|
RETVAL = ctxt->proximityPosition;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
getContextSize( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
CODE:
|
|
RETVAL = ctxt->contextSize;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
setContextNode( self , pnode )
|
|
SV * self
|
|
SV * pnode
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
PPCODE:
|
|
if (XPathContextDATA(ctxt)->node != NULL) {
|
|
SvREFCNT_dec(XPathContextDATA(ctxt)->node);
|
|
}
|
|
if (SvOK(pnode)) {
|
|
XPathContextDATA(ctxt)->node = newSVsv(pnode);
|
|
} else {
|
|
XPathContextDATA(ctxt)->node = NULL;
|
|
}
|
|
|
|
void
|
|
setContextPosition( self , position )
|
|
SV * self
|
|
int position
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL )
|
|
croak("XPathContext: missing xpath context\n");
|
|
if ( position < -1 || position > ctxt->contextSize )
|
|
croak("XPathContext: invalid position\n");
|
|
PPCODE:
|
|
ctxt->proximityPosition = position;
|
|
|
|
void
|
|
setContextSize( self , size )
|
|
SV * self
|
|
int size
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL )
|
|
croak("XPathContext: missing xpath context\n");
|
|
if ( size < -1 )
|
|
croak("XPathContext: invalid size\n");
|
|
PPCODE:
|
|
ctxt->contextSize = size;
|
|
if ( size == 0 )
|
|
ctxt->proximityPosition = 0;
|
|
else if ( size > 0 )
|
|
ctxt->proximityPosition = 1;
|
|
else
|
|
ctxt->proximityPosition = -1;
|
|
|
|
void
|
|
registerNs( pxpath_context, prefix, ns_uri )
|
|
SV * pxpath_context
|
|
SV * prefix
|
|
SV * ns_uri
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
PPCODE:
|
|
if(SvOK(ns_uri)) {
|
|
if(xmlXPathRegisterNs(ctxt, (xmlChar *) SvPV_nolen(prefix),
|
|
(xmlChar *) SvPV_nolen(ns_uri)) == -1) {
|
|
croak("XPathContext: cannot register namespace\n");
|
|
}
|
|
} else {
|
|
if(xmlXPathRegisterNs(ctxt, (xmlChar *) SvPV_nolen(prefix), NULL) == -1) {
|
|
croak("XPathContext: cannot unregister namespace\n");
|
|
}
|
|
}
|
|
|
|
SV*
|
|
lookupNs( pxpath_context, prefix )
|
|
SV * pxpath_context
|
|
SV * prefix
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
CODE:
|
|
RETVAL = C2Sv(xmlXPathNsLookup(ctxt, (xmlChar *) SvPV_nolen(prefix)), NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
getVarLookupData( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
CODE:
|
|
if(XPathContextDATA(ctxt)->varData != NULL) {
|
|
RETVAL = newSVsv(XPathContextDATA(ctxt)->varData);
|
|
} else {
|
|
RETVAL = &PL_sv_undef;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
getVarLookupFunc( self )
|
|
SV * self
|
|
INIT:
|
|
xmlXPathContextPtr ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(self)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
CODE:
|
|
if(XPathContextDATA(ctxt)->varData != NULL) {
|
|
RETVAL = newSVsv(XPathContextDATA(ctxt)->varLookup);
|
|
} else {
|
|
RETVAL = &PL_sv_undef;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
registerVarLookupFunc( pxpath_context, lookup_func, lookup_data )
|
|
SV * pxpath_context
|
|
SV * lookup_func
|
|
SV * lookup_data
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
XPathContextDataPtr data = NULL;
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL )
|
|
croak("XPathContext: missing xpath context\n");
|
|
data = XPathContextDATA(ctxt);
|
|
if ( data == NULL )
|
|
croak("XPathContext: missing xpath context private data\n");
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
/* free previous lookup function and data */
|
|
if (data->varLookup && SvOK(data->varLookup))
|
|
SvREFCNT_dec(data->varLookup);
|
|
if (data->varData && SvOK(data->varData))
|
|
SvREFCNT_dec(data->varData);
|
|
data->varLookup=NULL;
|
|
data->varData=NULL;
|
|
PPCODE:
|
|
if (SvOK(lookup_func)) {
|
|
if ( SvROK(lookup_func) && SvTYPE(SvRV(lookup_func)) == SVt_PVCV ) {
|
|
data->varLookup = newSVsv(lookup_func);
|
|
if (SvOK(lookup_data))
|
|
data->varData = newSVsv(lookup_data);
|
|
xmlXPathRegisterVariableLookup(ctxt,
|
|
LibXML_generic_variable_lookup, ctxt);
|
|
if (ctxt->varLookupData==NULL || ctxt->varLookupData != ctxt) {
|
|
croak( "XPathContext: registration failure\n" );
|
|
}
|
|
} else {
|
|
croak("XPathContext: 1st argument is not a CODE reference\n");
|
|
}
|
|
} else {
|
|
/* unregister */
|
|
xmlXPathRegisterVariableLookup(ctxt, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
registerFunctionNS( pxpath_context, name, uri, func)
|
|
SV * pxpath_context
|
|
char * name
|
|
SV * uri
|
|
SV * func
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
SV * pfdr;
|
|
SV * key;
|
|
STRLEN len;
|
|
char *strkey;
|
|
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
if ( !SvOK(func) ||
|
|
(SvOK(func) && ((SvROK(func) && SvTYPE(SvRV(func)) == SVt_PVCV )
|
|
|| SvPOK(func)))) {
|
|
if (ctxt->funcLookupData == NULL) {
|
|
if (SvOK(func)) {
|
|
pfdr = newRV_noinc((SV*) newHV());
|
|
ctxt->funcLookupData = pfdr;
|
|
} else {
|
|
/* looks like no perl function was never registered, */
|
|
/* nothing to unregister */
|
|
warn("XPathContext: nothing to unregister\n");
|
|
return;
|
|
}
|
|
} else {
|
|
if (SvTYPE(SvRV((SV *)ctxt->funcLookupData)) == SVt_PVHV) {
|
|
/* good, it's a HV */
|
|
pfdr = (SV *)ctxt->funcLookupData;
|
|
} else {
|
|
croak ("XPathContext: cannot register: funcLookupData structure occupied\n");
|
|
}
|
|
}
|
|
key = newSVpvn("",0);
|
|
if (SvOK(uri)) {
|
|
sv_catpv(key, "{");
|
|
sv_catsv(key, uri);
|
|
sv_catpv(key, "}");
|
|
}
|
|
sv_catpv(key, (const char*)name);
|
|
strkey = SvPV(key, len);
|
|
/* warn("Trying to store function '%s' in %d\n", strkey, pfdr); */
|
|
if (SvOK(func)) {
|
|
(void) hv_store((HV *)SvRV(pfdr),strkey, len, newSVsv(func), 0);
|
|
} else {
|
|
/* unregister */
|
|
(void) hv_delete((HV *)SvRV(pfdr),strkey, len, G_DISCARD);
|
|
}
|
|
SvREFCNT_dec(key);
|
|
} else {
|
|
croak("XPathContext: 3rd argument is not a CODE reference or function name\n");
|
|
}
|
|
PPCODE:
|
|
if (SvOK(uri)) {
|
|
xmlXPathRegisterFuncNS(ctxt, (xmlChar *) name,
|
|
(xmlChar *) SvPV(uri, len),
|
|
(SvOK(func) ?
|
|
LibXML_generic_extension_function : NULL));
|
|
} else {
|
|
xmlXPathRegisterFunc(ctxt, (xmlChar *) name,
|
|
(SvOK(func) ?
|
|
LibXML_generic_extension_function : NULL));
|
|
}
|
|
|
|
void
|
|
_free_node_pool( pxpath_context )
|
|
SV * pxpath_context
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
PPCODE:
|
|
if (XPathContextDATA(ctxt)->pool != NULL) {
|
|
SvREFCNT_dec((SV *)XPathContextDATA(ctxt)->pool);
|
|
XPathContextDATA(ctxt)->pool = NULL;
|
|
}
|
|
|
|
void
|
|
_findnodes( pxpath_context, perl_xpath )
|
|
SV * pxpath_context
|
|
SV * perl_xpath
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
ProxyNodePtr owner = NULL;
|
|
xmlXPathObjectPtr found = NULL;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
SV * element = NULL ;
|
|
xmlChar * xpath = NULL;
|
|
xmlXPathCompExprPtr comp = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
if ( ctxt->node == NULL ) {
|
|
croak("XPathContext: lost current node\n");
|
|
}
|
|
if (sv_isobject(perl_xpath) && sv_isa(perl_xpath,"XML::LibXML::XPathExpression")) {
|
|
comp = INT2PTR(xmlXPathCompExprPtr,SvIV((SV*)SvRV( perl_xpath )));
|
|
if (!comp) XSRETURN_UNDEF;
|
|
} else {
|
|
xpath = nodeSv2C(perl_xpath, ctxt->node);
|
|
if ( !(xpath && xmlStrlen(xpath)) ) {
|
|
if ( xpath )
|
|
xmlFree(xpath);
|
|
croak("XPathContext: empty XPath found\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
PPCODE:
|
|
INIT_ERROR_HANDLER;
|
|
|
|
PUTBACK ;
|
|
if (comp) {
|
|
found = domXPathCompFindCtxt( ctxt, comp, 0 );
|
|
} else {
|
|
found = domXPathFindCtxt( ctxt, xpath, 0 );
|
|
xmlFree(xpath);
|
|
}
|
|
SPAGAIN ;
|
|
|
|
if (found != NULL) {
|
|
nodelist = found->nodesetval;
|
|
} else {
|
|
nodelist = NULL;
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
if ( nodelist ) {
|
|
REPORT_ERROR(1);
|
|
if ( nodelist->nodeNr > 0 ) {
|
|
int i;
|
|
const char * cls = "XML::LibXML::Node";
|
|
xmlNodePtr tnode;
|
|
int l = nodelist->nodeNr;
|
|
for( i = 0 ; i < l; i++){
|
|
/* we have to create a new instance of an objectptr.
|
|
* and then place the current node into the new object.
|
|
* afterwards we can push the object to the array!
|
|
*/
|
|
element = NULL;
|
|
tnode = nodelist->nodeTab[i];
|
|
if (tnode->type == XML_NAMESPACE_DECL) {
|
|
xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
|
|
if ( newns != NULL ) {
|
|
element = NEWSV(0,0);
|
|
cls = PmmNodeTypeName( tnode );
|
|
element = sv_setref_pv( element,
|
|
(const char *)cls,
|
|
newns
|
|
);
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
if (tnode->doc) {
|
|
owner = PmmOWNERPO(PmmNewNode((xmlNodePtr) tnode->doc));
|
|
} else {
|
|
/* we try to find a known node on the ancestor axis */
|
|
xmlNodePtr n = tnode;
|
|
while (n && n->_private == NULL) n = n->parent;
|
|
if (n) owner = PmmOWNERPO(((ProxyNodePtr)n->_private));
|
|
else owner = NULL; /* self contained node */
|
|
}
|
|
element = PmmNodeToSv(tnode, owner);
|
|
}
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
/* prevent libxml2 from freeing the actual nodes */
|
|
if (found->boolval) found->boolval=0;
|
|
xmlXPathFreeObject(found);
|
|
}
|
|
else {
|
|
xmlXPathFreeObject(found);
|
|
REPORT_ERROR(0);
|
|
}
|
|
|
|
void
|
|
_find( pxpath_context, pxpath, to_bool )
|
|
SV * pxpath_context
|
|
SV * pxpath
|
|
int to_bool
|
|
PREINIT:
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
ProxyNodePtr owner = NULL;
|
|
xmlXPathObjectPtr found = NULL;
|
|
xmlNodeSetPtr nodelist = NULL;
|
|
xmlChar * xpath = NULL;
|
|
xmlXPathCompExprPtr comp = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
INIT:
|
|
ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(pxpath_context)));
|
|
if ( ctxt == NULL ) {
|
|
croak("XPathContext: missing xpath context\n");
|
|
}
|
|
LibXML_configure_xpathcontext(ctxt);
|
|
if ( ctxt->node == NULL ) {
|
|
croak("XPathContext: lost current node\n");
|
|
}
|
|
if (sv_isobject(pxpath) && sv_isa(pxpath,"XML::LibXML::XPathExpression")) {
|
|
comp = INT2PTR(xmlXPathCompExprPtr,SvIV((SV*)SvRV( pxpath )));
|
|
if (!comp) XSRETURN_UNDEF;
|
|
} else {
|
|
xpath = nodeSv2C(pxpath, ctxt->node);
|
|
if ( !(xpath && xmlStrlen(xpath)) ) {
|
|
if ( xpath )
|
|
xmlFree(xpath);
|
|
croak("XPathContext: empty XPath found\n");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
PPCODE:
|
|
INIT_ERROR_HANDLER;
|
|
PUTBACK ;
|
|
if (comp) {
|
|
found = domXPathCompFindCtxt( ctxt, comp, to_bool );
|
|
} else {
|
|
found = domXPathFindCtxt( ctxt, xpath, to_bool );
|
|
xmlFree(xpath);
|
|
}
|
|
SPAGAIN ;
|
|
CLEANUP_ERROR_HANDLER;
|
|
if (found) {
|
|
REPORT_ERROR(1);
|
|
switch (found->type) {
|
|
case XPATH_NODESET:
|
|
/* return as a NodeList */
|
|
/* access ->nodesetval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
|
|
nodelist = found->nodesetval;
|
|
if ( nodelist ) {
|
|
if ( nodelist->nodeNr > 0 ) {
|
|
int i;
|
|
const char * cls = "XML::LibXML::Node";
|
|
xmlNodePtr tnode;
|
|
SV * element;
|
|
int l = nodelist->nodeNr;
|
|
|
|
for( i = 0 ; i < l; i++){
|
|
/* we have to create a new instance of an
|
|
* objectptr. and then
|
|
* place the current node into the new
|
|
* object. afterwards we can
|
|
* push the object to the array!
|
|
*/
|
|
tnode = nodelist->nodeTab[i];
|
|
|
|
/* let's be paranoid */
|
|
if (tnode->type == XML_NAMESPACE_DECL) {
|
|
xmlNsPtr newns = xmlCopyNamespace((xmlNsPtr)tnode);
|
|
if ( newns != NULL ) {
|
|
element = NEWSV(0,0);
|
|
cls = PmmNodeTypeName( tnode );
|
|
element = sv_setref_pv( element,
|
|
(const char *)cls,
|
|
(void*)newns
|
|
);
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
if (tnode->doc) {
|
|
owner = PmmOWNERPO(PmmNewNode((xmlNodePtr) tnode->doc));
|
|
} else {
|
|
/* we try to find a known node on the ancestor axis */
|
|
xmlNodePtr n = tnode;
|
|
while (n && n->_private == NULL) n = n->parent;
|
|
if (n) owner = PmmOWNERPO(((ProxyNodePtr)n->_private));
|
|
else owner = NULL; /* self contained node */
|
|
}
|
|
element = PmmNodeToSv(tnode, owner);
|
|
}
|
|
XPUSHs( sv_2mortal(element) );
|
|
}
|
|
}
|
|
}
|
|
/* prevent libxml2 from freeing the actual nodes */
|
|
if (found->boolval) found->boolval=0;
|
|
break;
|
|
case XPATH_BOOLEAN:
|
|
/* return as a Boolean */
|
|
/* access ->boolval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
|
|
XPUSHs(sv_2mortal(newSViv(found->boolval)));
|
|
break;
|
|
case XPATH_NUMBER:
|
|
/* return as a Number */
|
|
/* access ->floatval */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
|
|
XPUSHs(sv_2mortal(newSVnv(found->floatval)));
|
|
break;
|
|
case XPATH_STRING:
|
|
/* access ->stringval */
|
|
/* return as a Literal */
|
|
XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
|
|
XPUSHs(sv_2mortal(C2Sv(found->stringval, NULL)));
|
|
break;
|
|
default:
|
|
croak("Unknown XPath return type");
|
|
}
|
|
xmlXPathFreeObject(found);
|
|
}
|
|
else {
|
|
REPORT_ERROR(0);
|
|
}
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::InputCallback
|
|
|
|
void
|
|
lib_cleanup_callbacks( self )
|
|
CODE:
|
|
xmlCleanupInputCallbacks();
|
|
xmlRegisterDefaultInputCallbacks();
|
|
|
|
void
|
|
lib_init_callbacks( self )
|
|
CODE:
|
|
xmlRegisterDefaultInputCallbacks(); /* important */
|
|
xmlRegisterInputCallbacks((xmlInputMatchCallback) LibXML_input_match,
|
|
(xmlInputOpenCallback) LibXML_input_open,
|
|
(xmlInputReadCallback) LibXML_input_read,
|
|
(xmlInputCloseCallback) LibXML_input_close);
|
|
|
|
#ifdef HAVE_READER_SUPPORT
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Reader
|
|
|
|
xmlTextReaderPtr
|
|
_newForFile(CLASS, filename, encoding, options)
|
|
const char* CLASS
|
|
const char* filename
|
|
const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
int options = SvOK($arg) ? SvIV($arg) : 0;
|
|
CODE:
|
|
RETVAL = xmlReaderForFile(filename, encoding, options);
|
|
INIT_READER_ERROR_HANDLER(RETVAL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
xmlTextReaderPtr
|
|
_newForIO(CLASS, fh, url, encoding, options)
|
|
const char* CLASS
|
|
SV * fh
|
|
const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
int options = SvOK($arg) ? SvIV($arg) : 0;
|
|
CODE:
|
|
(void)SvREFCNT_inc(fh); /* _dec'd by LibXML_close_perl */
|
|
RETVAL = xmlReaderForIO((xmlInputReadCallback) LibXML_read_perl,
|
|
(xmlInputCloseCallback) LibXML_close_perl,
|
|
(void *) fh, url, encoding, options);
|
|
INIT_READER_ERROR_HANDLER(RETVAL)
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
xmlTextReaderPtr
|
|
_newForString(CLASS, string, url, encoding, options)
|
|
const char* CLASS
|
|
SV * string
|
|
const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
int options = SvOK($arg) ? SvIV($arg) : 0;
|
|
CODE:
|
|
if (encoding == NULL && SvUTF8( string )) {
|
|
encoding = "UTF-8";
|
|
}
|
|
RETVAL = xmlReaderForDoc((xmlChar* )SvPV_nolen(string), url, encoding, options);
|
|
INIT_READER_ERROR_HANDLER(RETVAL)
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
xmlTextReaderPtr
|
|
_newForFd(CLASS, fd, url, encoding, options)
|
|
const char* CLASS
|
|
int fd
|
|
const char * url = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
const char * encoding = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
int options = SvOK($arg) ? SvIV($arg) : 0;
|
|
CODE:
|
|
RETVAL = xmlReaderForFd(fd, url, encoding, options);
|
|
INIT_READER_ERROR_HANDLER(RETVAL)
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
xmlTextReaderPtr
|
|
_newForDOM(CLASS, perl_doc)
|
|
const char* CLASS
|
|
SV * perl_doc
|
|
CODE:
|
|
PmmREFCNT_inc(SvPROXYNODE(perl_doc)); /* _dec in DESTROY */
|
|
RETVAL = xmlReaderWalker((xmlDocPtr) PmmSvNode(perl_doc));
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
attributeCount(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderAttributeCount(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
baseURI(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstBaseUri(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
long
|
|
byteConsumed(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderByteConsumed(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_close(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderClose(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
encoding(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstEncoding(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
localName(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstLocalName(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
name(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstName(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
namespaceURI(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstNamespaceUri(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
prefix(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstPrefix(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
value(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstValue(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
xmlLang(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstXmlLang(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV *
|
|
xmlVersion(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
const xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderConstXmlVersion(reader);
|
|
RETVAL = C2Sv(result, NULL);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
depth(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderDepth(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV *
|
|
getAttribute(reader, name)
|
|
xmlTextReaderPtr reader
|
|
char * name
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderGetAttribute(reader, (xmlChar*) name);
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
getAttributeNo(reader, no)
|
|
xmlTextReaderPtr reader
|
|
int no
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderGetAttributeNo(reader, no);
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
getAttributeNs(reader, localName, namespaceURI)
|
|
xmlTextReaderPtr reader
|
|
char * localName
|
|
char * namespaceURI = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderGetAttributeNs(reader, (xmlChar*) localName,
|
|
(xmlChar*) namespaceURI);
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
columnNumber(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderGetParserColumnNumber(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
lineNumber(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderGetParserLineNumber(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_getParserProp(reader, prop)
|
|
xmlTextReaderPtr reader
|
|
int prop
|
|
CODE:
|
|
RETVAL = xmlTextReaderGetParserProp(reader, prop);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
hasAttributes(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderHasAttributes(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
hasValue(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderHasValue(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
getAttributeHash(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
HV* hv;
|
|
SV* sv;
|
|
const xmlChar* name;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
hv=newHV();
|
|
if (xmlTextReaderHasAttributes(reader) && xmlTextReaderMoveToFirstAttribute(reader)==1) {
|
|
do {
|
|
name = xmlTextReaderConstName(reader);
|
|
sv=C2Sv((xmlTextReaderConstValue(reader)),NULL);
|
|
if (sv && hv_store(hv, (const char*) name, xmlStrlen(name), sv, 0)==NULL) {
|
|
SvREFCNT_dec(sv); /* free if not needed by hv_stores */
|
|
}
|
|
} while (xmlTextReaderMoveToNextAttribute(reader)==1);
|
|
xmlTextReaderMoveToElement(reader);
|
|
}
|
|
RETVAL=newRV_noinc((SV*)hv);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isDefault(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderIsDefault(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isEmptyElement(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderIsEmptyElement(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isNamespaceDecl(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderIsNamespaceDecl(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isValid(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderIsValid(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
lookupNamespace(reader, prefix)
|
|
xmlTextReaderPtr reader
|
|
char * prefix = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
CODE:
|
|
result = xmlTextReaderLookupNamespace(reader, (xmlChar*) prefix);
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
int
|
|
moveToAttribute(reader, name)
|
|
xmlTextReaderPtr reader
|
|
char * name
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToAttribute(reader, (xmlChar*) name);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
moveToAttributeNo(reader, no)
|
|
xmlTextReaderPtr reader
|
|
int no
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToAttributeNo(reader, no);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
moveToAttributeNs(reader, localName, namespaceURI)
|
|
xmlTextReaderPtr reader
|
|
char * localName
|
|
char * namespaceURI = SvOK($arg) ? SvPV_nolen($arg) : NULL;
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToAttributeNs(reader,
|
|
(xmlChar*) localName, (xmlChar*) namespaceURI);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
moveToElement(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToElement(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
moveToFirstAttribute(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToFirstAttribute(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
moveToNextAttribute(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderMoveToNextAttribute(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
next(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlTextReaderNext(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#define LIBXML_READER_NEXT_SIBLING(ret,reader) \
|
|
ret = xmlTextReaderNextSibling(reader); \
|
|
if (ret == -1) \
|
|
{ \
|
|
int depth; \
|
|
depth = xmlTextReaderDepth(reader); \
|
|
ret = xmlTextReaderRead(reader); \
|
|
while (ret == 1 && xmlTextReaderDepth(reader) > depth) { \
|
|
ret = xmlTextReaderNext(reader); \
|
|
} \
|
|
if (ret == 1) { \
|
|
if (xmlTextReaderDepth(reader) != depth) { \
|
|
ret = 0; \
|
|
} else if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) { \
|
|
ret = xmlTextReaderRead(reader); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
int
|
|
nextSibling(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
LIBXML_READER_NEXT_SIBLING(RETVAL,reader)
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
nextSiblingElement(reader, name = NULL, nsURI = NULL)
|
|
xmlTextReaderPtr reader
|
|
const char * name
|
|
const char * nsURI
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
do {
|
|
LIBXML_READER_NEXT_SIBLING(RETVAL,reader)
|
|
if (LIBXML_READER_TEST_ELEMENT(reader,name,nsURI)) {
|
|
break;
|
|
}
|
|
} while (RETVAL == 1);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
nextElement(reader, name = NULL, nsURI = NULL)
|
|
xmlTextReaderPtr reader
|
|
const char * name
|
|
const char * nsURI
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
do {
|
|
RETVAL = xmlTextReaderRead(reader);
|
|
if (LIBXML_READER_TEST_ELEMENT(reader,name,nsURI)) {
|
|
break;
|
|
}
|
|
} while (RETVAL == 1);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
nextPatternMatch(reader, compiled)
|
|
xmlTextReaderPtr reader
|
|
xmlPatternPtr compiled
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
xmlNodePtr node = NULL;
|
|
CODE:
|
|
if ( compiled == NULL )
|
|
croak("Usage: $reader->nextPatternMatch( a-XML::LibXML::Pattern-object )");
|
|
do {
|
|
RETVAL = xmlTextReaderRead(reader);
|
|
node = xmlTextReaderCurrentNode(reader);
|
|
if (node && xmlPatternMatch(compiled, node)) {
|
|
break;
|
|
}
|
|
} while (RETVAL == 1);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
skipSiblings(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
int depth;
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
depth = xmlTextReaderDepth(reader);
|
|
RETVAL = -1;
|
|
if (depth > 0) {
|
|
do {
|
|
RETVAL = xmlTextReaderNext(reader);
|
|
} while (RETVAL == 1 && xmlTextReaderDepth(reader) >= depth);
|
|
if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) {
|
|
RETVAL = -1;
|
|
}
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
nodeType(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderNodeType(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
quoteChar(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
int ret;
|
|
CODE:
|
|
ret = xmlTextReaderQuoteChar(reader);
|
|
if (ret == -1) XSRETURN_UNDEF;
|
|
RETVAL = newSVpvf("%c",ret);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
read(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlTextReaderRead(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
readAttributeValue(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlTextReaderReadAttributeValue(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
SV *
|
|
readInnerXml(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
result = xmlTextReaderReadInnerXml(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if (!result) XSRETURN_UNDEF;
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
readOuterXml(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlChar *result = NULL;
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
result = xmlTextReaderReadOuterXml(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if (result) {
|
|
RETVAL = C2Sv(result, NULL);
|
|
xmlFree(result);
|
|
} else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
readState(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderReadState(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_setParserProp(reader, prop, value)
|
|
xmlTextReaderPtr reader
|
|
int prop
|
|
int value
|
|
CODE:
|
|
RETVAL = xmlTextReaderSetParserProp(reader, prop, value);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
standalone(reader)
|
|
xmlTextReaderPtr reader
|
|
CODE:
|
|
RETVAL = xmlTextReaderStandalone(reader);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
_nodePath(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlNodePtr node = NULL;
|
|
xmlChar * path = NULL;
|
|
CODE:
|
|
node = xmlTextReaderCurrentNode(reader);
|
|
if ( node ==NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
path = xmlGetNodePath( node );
|
|
if ( path == NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = C2Sv(path,NULL);
|
|
xmlFree(path);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#ifdef LIBXML_PATTERN_ENABLED
|
|
|
|
int
|
|
matchesPattern(reader, compiled)
|
|
xmlTextReaderPtr reader
|
|
xmlPatternPtr compiled
|
|
PREINIT:
|
|
xmlNodePtr node = NULL;
|
|
CODE:
|
|
if ( compiled == NULL )
|
|
XSRETURN_UNDEF;
|
|
node = xmlTextReaderCurrentNode(reader);
|
|
if ( node ==NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = xmlPatternMatch(compiled, node);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#endif /* LIBXML_PATTERN_ENABLED */
|
|
|
|
SV *
|
|
copyCurrentNode(reader,expand = 0)
|
|
xmlTextReaderPtr reader
|
|
int expand
|
|
PREINIT:
|
|
xmlNodePtr node = NULL;
|
|
xmlNodePtr copy;
|
|
xmlDocPtr doc = NULL;
|
|
ProxyNodePtr proxy;
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
if (expand) {
|
|
node = xmlTextReaderExpand(reader);
|
|
}
|
|
else {
|
|
node = xmlTextReaderCurrentNode(reader);
|
|
}
|
|
if (node) {
|
|
doc = xmlTextReaderCurrentDoc(reader);
|
|
}
|
|
if (!doc) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if (xmlTextReaderGetParserProp(reader,XML_PARSER_VALIDATE))
|
|
PmmInvalidatePSVI(doc); /* the document may have psvi info */
|
|
|
|
copy = PmmCloneNode( node, expand );
|
|
if ( copy == NULL ) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
if ( copy->type == XML_DTD_NODE ) {
|
|
RETVAL = PmmNodeToSv(copy, NULL);
|
|
}
|
|
else {
|
|
ProxyNodePtr docfrag = NULL;
|
|
|
|
if ( doc != NULL ) {
|
|
xmlSetTreeDoc(copy, doc);
|
|
}
|
|
proxy = PmmNewNode((xmlNodePtr)doc);
|
|
if (PmmREFCNT(proxy) == 0) {
|
|
PmmREFCNT_inc(proxy);
|
|
}
|
|
LibXML_set_reader_preserve_flag(reader);
|
|
|
|
docfrag = PmmNewFragment( doc );
|
|
xmlAddChild( PmmNODE(docfrag), copy );
|
|
RETVAL = PmmNodeToSv(copy, docfrag);
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
document(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlDocPtr doc = NULL;
|
|
CODE:
|
|
doc = xmlTextReaderCurrentDoc(reader);
|
|
if (!doc) XSRETURN_UNDEF;
|
|
RETVAL = PmmNodeToSv((xmlNodePtr)doc, NULL);
|
|
/* FIXME: taint the document with PmmInvalidatePSVI if the reader did validation */
|
|
if ( PmmREFCNT(SvPROXYNODE(RETVAL))==1 ) {
|
|
/* will be decremented in Reader destructor */
|
|
PmmREFCNT_inc(SvPROXYNODE(RETVAL));
|
|
}
|
|
if (xmlTextReaderGetParserProp(reader,XML_PARSER_VALIDATE))
|
|
PmmInvalidatePSVI(doc); /* the document may have psvi info */
|
|
|
|
LibXML_set_reader_preserve_flag(reader);
|
|
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_preservePattern(reader,pattern,ns_map=NULL)
|
|
xmlTextReaderPtr reader
|
|
char * pattern
|
|
AV * ns_map
|
|
PREINIT:
|
|
xmlChar** namespaces = NULL;
|
|
SV** aux;
|
|
int last,i;
|
|
CODE:
|
|
if (ns_map) {
|
|
last = av_len(ns_map);
|
|
New(0,namespaces, last+2, xmlChar*);
|
|
for( i = 0; i <= last ; i++ ) {
|
|
aux = av_fetch(ns_map,i,0);
|
|
namespaces[i]=(xmlChar*) SvPV_nolen(*aux);
|
|
}
|
|
namespaces[i]=0;
|
|
}
|
|
RETVAL = xmlTextReaderPreservePattern(reader,(const xmlChar*) pattern,
|
|
(const xmlChar**)namespaces);
|
|
Safefree(namespaces);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
preserveNode(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlNodePtr node;
|
|
xmlDocPtr doc;
|
|
ProxyNodePtr proxy;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
doc = xmlTextReaderCurrentDoc(reader);
|
|
if (!doc) {
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
proxy = PmmNewNode((xmlNodePtr)doc);
|
|
if ( PmmREFCNT(proxy) == 0 ) {
|
|
/* new proxy node */
|
|
PmmREFCNT_inc(proxy);
|
|
}
|
|
LibXML_set_reader_preserve_flag(reader);
|
|
|
|
node = xmlTextReaderPreserve(reader);
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if (node) {
|
|
RETVAL = PmmNodeToSv(node, proxy);
|
|
} else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
finish(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
INIT_ERROR_HANDLER;
|
|
while (1) {
|
|
RETVAL = xmlTextReaderRead(reader);
|
|
if (RETVAL!=1) break;
|
|
}
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
RETVAL++; /* we want 0 - fail, 1- success */
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#ifdef HAVE_SCHEMAS
|
|
|
|
int
|
|
_setRelaxNGFile(reader,rng)
|
|
xmlTextReaderPtr reader
|
|
char* rng
|
|
CODE:
|
|
RETVAL = xmlTextReaderRelaxNGValidate(reader,rng);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_setRelaxNG(reader,rng_doc)
|
|
xmlTextReaderPtr reader
|
|
xmlRelaxNGPtr rng_doc
|
|
CODE:
|
|
RETVAL = xmlTextReaderRelaxNGSetSchema(reader,rng_doc);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_setXSDFile(reader,xsd)
|
|
xmlTextReaderPtr reader
|
|
char* xsd
|
|
CODE:
|
|
RETVAL = xmlTextReaderSchemaValidate(reader,xsd);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_setXSD(reader,xsd_doc)
|
|
xmlTextReaderPtr reader
|
|
xmlSchemaPtr xsd_doc
|
|
CODE:
|
|
RETVAL = xmlTextReaderSetSchema(reader,xsd_doc);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#endif /* HAVE_SCHEMAS */
|
|
|
|
void
|
|
_DESTROY(reader)
|
|
xmlTextReaderPtr reader
|
|
PREINIT:
|
|
xmlDocPtr doc;
|
|
ProxyNodePtr proxy;
|
|
/* SV * error_sv = NULL;
|
|
xmlTextReaderErrorFunc f = NULL; */
|
|
CODE:
|
|
|
|
if ( LibXML_get_reader_preserve_flag(reader) ) {
|
|
doc = xmlTextReaderCurrentDoc(reader);
|
|
if (doc) {
|
|
proxy = PmmNewNode((xmlNodePtr)doc);
|
|
if ( PmmREFCNT(proxy) == 0 ) {
|
|
PmmREFCNT_inc(proxy);
|
|
}
|
|
PmmREFCNT_dec(proxy);
|
|
}
|
|
}
|
|
if (xmlTextReaderReadState(reader) != XML_TEXTREADER_MODE_CLOSED) {
|
|
xmlTextReaderClose(reader);
|
|
}
|
|
/* xmlTextReaderGetErrorHandler(reader, &f, (void **) &error_sv);
|
|
if (error_sv) {
|
|
sv_2mortal(error_sv);
|
|
} */
|
|
xmlFreeTextReader(reader);
|
|
|
|
#endif /* HAVE_READER_SUPPORT */
|
|
|
|
#ifdef WITH_SERRORS
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::LibError
|
|
|
|
int
|
|
domain( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = self->domain;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
code( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = self->code;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
line( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = self->line;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
num1( self )
|
|
xmlErrorPtr self
|
|
ALIAS:
|
|
int1 = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = self->int1;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
num2( self )
|
|
xmlErrorPtr self
|
|
ALIAS:
|
|
int2 = 1
|
|
CODE:
|
|
PERL_UNUSED_VAR(ix);
|
|
RETVAL = self->int2;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
level( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = (int)self->level;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char *
|
|
message( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = self->message;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char *
|
|
file( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = (char*)self->file;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char *
|
|
str1( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = (char*)self->str1;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char *
|
|
str2( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = (char*)self->str2;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
char *
|
|
str3( self )
|
|
xmlErrorPtr self
|
|
CODE:
|
|
RETVAL = (char*)self->str3;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
context_and_column( self )
|
|
xmlErrorPtr self
|
|
PREINIT:
|
|
xmlParserInputPtr input;
|
|
const xmlChar *cur, *base, *col_cur;
|
|
unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
|
|
xmlChar content[81]; /* space for 80 chars + line terminator */
|
|
xmlChar *ctnt;
|
|
int domain;
|
|
xmlParserCtxtPtr ctxt = NULL;
|
|
PPCODE:
|
|
domain = self->domain;
|
|
if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
|
|
(domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
|
|
(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
|
|
ctxt = (xmlParserCtxtPtr) self->ctxt;
|
|
}
|
|
if (ctxt == NULL) XSRETURN_EMPTY;
|
|
input = ctxt->input;
|
|
if ((input != NULL) && (input->filename == NULL) &&
|
|
(ctxt->inputNr > 1)) {
|
|
input = ctxt->inputTab[ctxt->inputNr - 2];
|
|
}
|
|
if (input == NULL) XSRETURN_EMPTY;
|
|
cur = input->cur;
|
|
base = input->base;
|
|
/* skip backwards over any end-of-lines */
|
|
while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
|
|
cur--;
|
|
}
|
|
n = 0;
|
|
/* search backwards for beginning-of-line (to max buff size) */
|
|
while ((n++ < (sizeof(content)-1)) && (cur > base) &&
|
|
(*(cur) != '\n') && (*(cur) != '\r'))
|
|
cur--;
|
|
/* search backwards for beginning-of-line for calculating the
|
|
* column. */
|
|
col_cur = cur;
|
|
while ((col_cur > base) && (*(col_cur) != '\n') && (*(col_cur) != '\r'))
|
|
col_cur--;
|
|
if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
|
|
if ((*(col_cur) == '\n') || (*(col_cur) == '\r')) col_cur++;
|
|
/* calculate the error position in terms of the current position */
|
|
col = input->cur - col_cur;
|
|
/* search forward for end-of-line (to max buff size) */
|
|
n = 0;
|
|
ctnt = content;
|
|
/* copy selected text to our buffer */
|
|
while ((*cur != 0) && (*(cur) != '\n') &&
|
|
(*(cur) != '\r') && (n < sizeof(content)-1)) {
|
|
*ctnt++ = *cur++;
|
|
n++;
|
|
}
|
|
*ctnt = 0;
|
|
EXTEND(SP,2);
|
|
PUSHs(sv_2mortal(C2Sv(content, NULL)));
|
|
PUSHs(sv_2mortal(newSViv(col)));
|
|
|
|
#endif /* WITH_SERRORS */
|
|
|
|
|
|
#ifdef LIBXML_PATTERN_ENABLED
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Pattern
|
|
|
|
xmlPatternPtr
|
|
_compilePattern(CLASS, ppattern, pattern_type, ns_map=NULL)
|
|
SV * ppattern
|
|
AV * ns_map
|
|
int pattern_type
|
|
PREINIT:
|
|
xmlChar * pattern = Sv2C(ppattern, NULL);
|
|
xmlChar** namespaces = NULL;
|
|
SV** aux;
|
|
int last,i;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
if ( pattern == NULL )
|
|
XSRETURN_UNDEF;
|
|
if (ns_map) {
|
|
last = av_len(ns_map);
|
|
New(0,namespaces, last+2, xmlChar*);
|
|
for( i = 0; i <= last ; i++ ) {
|
|
aux = av_fetch(ns_map,i,0);
|
|
namespaces[i]=(xmlChar*) SvPV_nolen(*aux);
|
|
}
|
|
namespaces[i]=0;
|
|
}
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlPatterncompile(pattern, NULL, pattern_type, (const xmlChar **) namespaces);
|
|
Safefree(namespaces);
|
|
xmlFree( pattern );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( RETVAL == NULL ) {
|
|
croak("Compilation of pattern failed");
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
matchesNode(self, node)
|
|
xmlPatternPtr self
|
|
xmlNodePtr node
|
|
CODE:
|
|
if ( node ==NULL ) {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = xmlPatternMatch(self, node);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY( self )
|
|
xmlPatternPtr self
|
|
CODE:
|
|
xs_warn( "DESTROY PATTERN OBJECT" );
|
|
xmlFreePattern(self);
|
|
|
|
#endif /* LIBXML_PATTERN_ENABLED */
|
|
|
|
#ifdef LIBXML_REGEXP_ENABLED
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::RegExp
|
|
|
|
xmlRegexpPtr
|
|
_compile(CLASS, pregexp)
|
|
SV * pregexp
|
|
PREINIT:
|
|
xmlChar * regexp = Sv2C(pregexp, NULL);
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
if ( regexp == NULL )
|
|
XSRETURN_UNDEF;
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlRegexpCompile(regexp);
|
|
xmlFree( regexp );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( RETVAL == NULL ) {
|
|
croak("Compilation of regexp failed");
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
matches(self, pvalue)
|
|
xmlRegexpPtr self
|
|
SV* pvalue
|
|
PREINIT:
|
|
xmlChar * value = Sv2C(pvalue, NULL);
|
|
CODE:
|
|
if ( value == NULL )
|
|
XSRETURN_UNDEF;
|
|
RETVAL = xmlRegexpExec(self,value);
|
|
xmlFree( value );
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
isDeterministic(self)
|
|
xmlRegexpPtr self
|
|
CODE:
|
|
RETVAL = xmlRegexpIsDeterminist(self);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY( self )
|
|
xmlRegexpPtr self
|
|
CODE:
|
|
xs_warn( "DESTROY REGEXP OBJECT" );
|
|
xmlRegFreeRegexp(self);
|
|
|
|
#endif /* LIBXML_REGEXP_ENABLED */
|
|
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::XPathExpression
|
|
|
|
xmlXPathCompExprPtr
|
|
new(CLASS, pxpath)
|
|
SV * pxpath
|
|
PREINIT:
|
|
xmlChar * xpath = Sv2C(pxpath, NULL);
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
if ( pxpath == NULL )
|
|
XSRETURN_UNDEF;
|
|
INIT_ERROR_HANDLER;
|
|
RETVAL = xmlXPathCompile( xpath );
|
|
xmlFree( xpath );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( RETVAL == NULL ) {
|
|
croak("Compilation of XPath expression failed!");
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY( self )
|
|
xmlXPathCompExprPtr self
|
|
CODE:
|
|
xs_warn( "DESTROY COMPILED XPATH OBJECT" );
|
|
xmlXPathFreeCompExpr(self);
|
|
|
|
MODULE = XML::LibXML PACKAGE = XML::LibXML::Common
|
|
|
|
PROTOTYPES: DISABLE
|
|
|
|
SV*
|
|
encodeToUTF8( encoding, string )
|
|
const char * encoding
|
|
SV * string
|
|
PREINIT:
|
|
xmlChar * realstring = NULL;
|
|
xmlChar * tstr = NULL;
|
|
xmlCharEncoding enc = 0;
|
|
STRLEN len = 0;
|
|
xmlBufferPtr in = NULL, out = NULL;
|
|
xmlCharEncodingHandlerPtr coder = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
if (!SvOK(string)) {
|
|
XSRETURN_UNDEF;
|
|
} else if (!SvCUR(string)) {
|
|
XSRETURN_PV("");
|
|
}
|
|
realstring = (xmlChar*) SvPV(string, len);
|
|
if ( realstring != NULL ) {
|
|
/* warn("encode %s", realstring ); */
|
|
#ifdef HAVE_UTF8
|
|
if ( !DO_UTF8(string) && encoding != NULL ) {
|
|
#else
|
|
if ( encoding != NULL ) {
|
|
#endif
|
|
enc = xmlParseCharEncoding( encoding );
|
|
|
|
if ( enc == 0 ) {
|
|
/* this happens if the encoding is "" or NULL */
|
|
enc = XML_CHAR_ENCODING_UTF8;
|
|
}
|
|
|
|
if ( enc == XML_CHAR_ENCODING_UTF8 ) {
|
|
/* copy the string */
|
|
/* warn( "simply copy the string" ); */
|
|
tstr = xmlStrndup( realstring, len );
|
|
}
|
|
else {
|
|
INIT_ERROR_HANDLER;
|
|
if ( enc > 1 ) {
|
|
coder= xmlGetCharEncodingHandler( enc );
|
|
}
|
|
else if ( enc == XML_CHAR_ENCODING_ERROR ){
|
|
coder =xmlFindCharEncodingHandler( encoding );
|
|
}
|
|
else {
|
|
croak("no encoder found\n");
|
|
}
|
|
if ( coder == NULL ) {
|
|
croak( "cannot encode string" );
|
|
}
|
|
in = xmlBufferCreateStatic((void*)realstring, len );
|
|
out = xmlBufferCreate();
|
|
if ( xmlCharEncInFunc( coder, out, in ) >= 0 ) {
|
|
tstr = xmlStrdup( out->content );
|
|
}
|
|
|
|
xmlBufferFree( in );
|
|
xmlBufferFree( out );
|
|
xmlCharEncCloseFunc( coder );
|
|
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
}
|
|
}
|
|
else {
|
|
tstr = xmlStrndup( realstring, len );
|
|
}
|
|
|
|
if ( !tstr ) {
|
|
croak( "return value missing!" );
|
|
}
|
|
|
|
len = xmlStrlen( tstr );
|
|
RETVAL = newSVpvn( (const char *)tstr, len );
|
|
#ifdef HAVE_UTF8
|
|
SvUTF8_on(RETVAL);
|
|
#endif
|
|
xmlFree(tstr);
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
decodeFromUTF8( encoding, string )
|
|
const char * encoding
|
|
SV* string
|
|
PREINIT:
|
|
xmlChar * tstr = NULL;
|
|
xmlChar * realstring = NULL;
|
|
xmlCharEncoding enc = 0;
|
|
STRLEN len = 0;
|
|
xmlBufferPtr in = NULL, out = NULL;
|
|
xmlCharEncodingHandlerPtr coder = NULL;
|
|
PREINIT_SAVED_ERROR
|
|
CODE:
|
|
#ifdef HAVE_UTF8
|
|
if ( !SvOK(string) ) {
|
|
XSRETURN_UNDEF;
|
|
} else if (!SvCUR(string)) {
|
|
XSRETURN_PV("");
|
|
} else if ( !SvUTF8(string) ) {
|
|
croak("string is not utf8!!");
|
|
} else {
|
|
#endif
|
|
realstring = (xmlChar*) SvPV(string, len);
|
|
if ( realstring != NULL ) {
|
|
/* warn("decode %s", realstring ); */
|
|
enc = xmlParseCharEncoding( encoding );
|
|
if ( enc == 0 ) {
|
|
/* this happens if the encoding is "" or NULL */
|
|
enc = XML_CHAR_ENCODING_UTF8;
|
|
}
|
|
|
|
if ( enc == XML_CHAR_ENCODING_UTF8 ) {
|
|
/* copy the string */
|
|
/* warn( "simply copy the string" ); */
|
|
tstr = xmlStrdup( realstring );
|
|
len = xmlStrlen( tstr );
|
|
}
|
|
else {
|
|
INIT_ERROR_HANDLER;
|
|
if ( enc > 1 ) {
|
|
coder= xmlGetCharEncodingHandler( enc );
|
|
}
|
|
else if ( enc == XML_CHAR_ENCODING_ERROR ){
|
|
coder = xmlFindCharEncodingHandler( encoding );
|
|
}
|
|
else {
|
|
croak("no encoder found\n");
|
|
}
|
|
|
|
if ( coder == NULL ) {
|
|
croak( "cannot encode string" );
|
|
}
|
|
|
|
in = xmlBufferCreate();
|
|
out = xmlBufferCreate();
|
|
xmlBufferCCat( in, (char*) realstring );
|
|
if ( xmlCharEncOutFunc( coder, out, in ) >= 0 ) {
|
|
len = xmlBufferLength( out );
|
|
tstr = xmlCharStrndup( (char*) xmlBufferContent( out ), len );
|
|
}
|
|
|
|
xmlBufferFree( in );
|
|
xmlBufferFree( out );
|
|
xmlCharEncCloseFunc( coder );
|
|
CLEANUP_ERROR_HANDLER;
|
|
REPORT_ERROR(0);
|
|
if ( !tstr ) {
|
|
croak( "return value missing!" );
|
|
}
|
|
}
|
|
|
|
RETVAL = newSVpvn( (const char *)tstr, len );
|
|
xmlFree( tstr );
|
|
#ifdef HAVE_UTF8
|
|
if ( enc == XML_CHAR_ENCODING_UTF8 ) {
|
|
SvUTF8_on(RETVAL);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
XSRETURN_UNDEF;
|
|
}
|
|
#ifdef HAVE_UTF8
|
|
}
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|