diff --git a/configure.in b/configure.in
index 5a27d3a..352d7b2 100644
--- a/configure.in
+++ b/configure.in
@@ -732,15 +732,6 @@ fi
 AC_SUBST(with_libxml)
 
 #
-# XSLT
-#
-PGAC_ARG_BOOL(with, libxslt, no, [use XSLT support when building contrib/xml2],
-              [AC_DEFINE([USE_LIBXSLT], 1, [Define to 1 to use XSLT support when building contrib/xml2. (--with-libxslt)])])
-
-
-AC_SUBST(with_libxslt)
-
-#
 # tzdata
 #
 PGAC_ARG_REQ(with, system-tzdata,
@@ -943,10 +934,6 @@ if test "$with_libxml" = yes ; then
   AC_CHECK_LIB(xml2, xmlSaveToBuffer, [], [AC_MSG_ERROR([library 'xml2' (version >= 2.6.23) is required for XML support])])
 fi
 
-if test "$with_libxslt" = yes ; then
-  AC_CHECK_LIB(xslt, xsltCleanupGlobals, [], [AC_MSG_ERROR([library 'xslt' is required for XSLT support])])
-fi
-
 # for contrib/uuid-ossp
 if test "$with_ossp_uuid" = yes ; then
   AC_CHECK_LIB(ossp-uuid, uuid_export,
@@ -1051,10 +1038,6 @@ if test "$with_libxml" = yes ; then
   AC_CHECK_HEADER(libxml/parser.h, [], [AC_MSG_ERROR([header file <libxml/parser.h> is required for XML support])])
 fi
 
-if test "$with_libxslt" = yes ; then
-  AC_CHECK_HEADER(libxslt/xslt.h, [], [AC_MSG_ERROR([header file <libxslt/xslt.h> is required for XSLT support])])
-fi
-
 if test "$with_ldap" = yes ; then
   if test "$PORTNAME" != "win32"; then
      AC_CHECK_HEADERS(ldap.h, [],
diff --git a/contrib/Makefile b/contrib/Makefile
index 19d5c1b..168396c 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -51,10 +51,6 @@ ifeq ($(with_ossp_uuid),yes)
 SUBDIRS += uuid-ossp
 endif
 
-ifeq ($(with_libxml),yes)
-SUBDIRS += xml2
-endif
-
 # Missing:
 #		start-scripts	\ (does not have a makefile)
 
diff --git a/contrib/xml2/Makefile b/contrib/xml2/Makefile
deleted file mode 100644
index ea8636a..0000000
--- a/contrib/xml2/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# $PostgreSQL$
-
-MODULE_big = pgxml
-
-OBJS = $(if $(filter -lxslt, $(LIBS)), xpath.o xslt_proc.o, xpath.o)
-
-SHLIB_LINK += $(filter -lxslt, $(LIBS)) $(filter -lxml2, $(LIBS))
-
-DATA_built = pgxml.sql
-DATA = uninstall_pgxml.sql
-
-ifdef USE_PGXS
-PG_CONFIG = pg_config
-PGXS := $(shell $(PG_CONFIG) --pgxs)
-include $(PGXS)
-else
-subdir = contrib/xml2
-top_builddir = ../..
-include $(top_builddir)/src/Makefile.global
-include $(top_srcdir)/contrib/contrib-global.mk
-endif
diff --git a/contrib/xml2/pgxml.sql.in b/contrib/xml2/pgxml.sql.in
deleted file mode 100644
index 139ca14..0000000
--- a/contrib/xml2/pgxml.sql.in
+++ /dev/null
@@ -1,86 +0,0 @@
-/* $PostgreSQL$ */
-
--- Adjust this setting to control where the objects get created.
-SET search_path = public;
-
---SQL for XML parser
-
-CREATE OR REPLACE FUNCTION xml_is_well_formed(text) RETURNS bool
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
--- deprecated old name for xml_is_well_formed
-CREATE OR REPLACE FUNCTION xml_valid(text) RETURNS bool
-AS 'MODULE_PATHNAME', 'xml_is_well_formed'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xml_encode_special_chars(text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_string(text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text,text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_number(text,text) RETURNS float4
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE OR REPLACE FUNCTION xpath_bool(text,text) RETURNS boolean
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
--- List function
-
-CREATE OR REPLACE FUNCTION xpath_list(text,text,text) RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-
-CREATE OR REPLACE FUNCTION xpath_list(text,text) RETURNS text
-AS 'SELECT xpath_list($1,$2,'','')'
-LANGUAGE SQL STRICT IMMUTABLE;
-
-
-
--- Wrapper functions for nodeset where no tags needed
-
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text)
-RETURNS text
-AS 'SELECT xpath_nodeset($1,$2,'''','''')'
-LANGUAGE SQL STRICT IMMUTABLE;
-
-
-CREATE OR REPLACE FUNCTION xpath_nodeset(text,text,text)
-RETURNS text
-AS 'SELECT xpath_nodeset($1,$2,'''',$3)'
-LANGUAGE SQL STRICT IMMUTABLE;
-
--- Table function
-
-CREATE OR REPLACE FUNCTION xpath_table(text,text,text,text,text)
-RETURNS setof record
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT STABLE;
-
--- XSLT functions
--- Delete from here to the end of the file if you are not compiling with
--- XSLT support.
-
-
-CREATE OR REPLACE FUNCTION xslt_process(text,text,text)
-RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT VOLATILE;
-
--- the function checks for the correct argument count
-
-CREATE OR REPLACE FUNCTION xslt_process(text,text)
-RETURNS text
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
diff --git a/contrib/xml2/uninstall_pgxml.sql b/contrib/xml2/uninstall_pgxml.sql
deleted file mode 100644
index ec676dc..0000000
--- a/contrib/xml2/uninstall_pgxml.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-/* $PostgreSQL$ */
-
--- Adjust this setting to control where the objects get dropped.
-SET search_path = public;
-
-DROP FUNCTION xslt_process(text,text);
-
-DROP FUNCTION xslt_process(text,text,text);
-
-DROP FUNCTION xpath_table(text,text,text,text,text);
-
-DROP FUNCTION xpath_nodeset(text,text,text);
-
-DROP FUNCTION xpath_nodeset(text,text);
-
-DROP FUNCTION xpath_list(text,text);
-
-DROP FUNCTION xpath_list(text,text,text);
-
-DROP FUNCTION xpath_bool(text,text);
-
-DROP FUNCTION xpath_number(text,text);
-
-DROP FUNCTION xpath_nodeset(text,text,text,text);
-
-DROP FUNCTION xpath_string(text,text);
-
-DROP FUNCTION xml_encode_special_chars(text);
-
--- deprecated old name for xml_is_well_formed
-DROP FUNCTION xml_valid(text);
-
-DROP FUNCTION xml_is_well_formed(text);
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
deleted file mode 100644
index dd895b0..0000000
--- a/contrib/xml2/xpath.c
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * $PostgreSQL$
- *
- * Parser interface for DOM-based parser (libxml) rather than
- * stream-based SAX-type parser
- */
-#include "postgres.h"
-
-#include "executor/spi.h"
-#include "fmgr.h"
-#include "funcapi.h"
-#include "lib/stringinfo.h"
-#include "miscadmin.h"
-#include "utils/builtins.h"
-
-/* libxml includes */
-
-#include <libxml/xpath.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parserInternals.h>
-
-
-PG_MODULE_MAGIC;
-
-/* declarations */
-
-static void *pgxml_palloc(size_t size);
-static void *pgxml_repalloc(void *ptr, size_t size);
-static void pgxml_pfree(void *ptr);
-static char *pgxml_pstrdup(const char *string);
-static void pgxml_errorHandler(void *ctxt, const char *msg,...);
-
-void		elog_error(int level, char *explain, int force);
-void		pgxml_parser_init(void);
-
-static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
-				   xmlChar *toptagname, xmlChar *septagname,
-				   xmlChar *plainsep);
-
-text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *toptag,
-					 xmlChar *septag, xmlChar *plainsep);
-
-xmlChar    *pgxml_texttoxmlchar(text *textstring);
-
-static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
-
-
-Datum		xml_is_well_formed(PG_FUNCTION_ARGS);
-Datum		xml_encode_special_chars(PG_FUNCTION_ARGS);
-Datum		xpath_nodeset(PG_FUNCTION_ARGS);
-Datum		xpath_string(PG_FUNCTION_ARGS);
-Datum		xpath_number(PG_FUNCTION_ARGS);
-Datum		xpath_bool(PG_FUNCTION_ARGS);
-Datum		xpath_list(PG_FUNCTION_ARGS);
-Datum		xpath_table(PG_FUNCTION_ARGS);
-
-/* Global variables */
-char	   *errbuf;				/* per line error buffer */
-char	   *pgxml_errorMsg = NULL;		/* overall error message */
-
-#define ERRBUF_SIZE 200
-
-/* memory handling passthrough functions (e.g. palloc, pstrdup are
-   currently macros, and the others might become so...) */
-
-static void *
-pgxml_palloc(size_t size)
-{
-/*	elog(DEBUG1,"Alloc %d in CMC %p",size,CurrentMemoryContext); */
-	return palloc(size);
-}
-
-static void *
-pgxml_repalloc(void *ptr, size_t size)
-{
-/*	elog(DEBUG1,"ReAlloc in CMC %p",CurrentMemoryContext);*/
-	return repalloc(ptr, size);
-}
-
-static void
-pgxml_pfree(void *ptr)
-{
-/*	elog(DEBUG1,"Free in CMC %p",CurrentMemoryContext); */
-	pfree(ptr);
-}
-
-static char *
-pgxml_pstrdup(const char *string)
-{
-	return pstrdup(string);
-}
-
-/* The error handling function. This formats an error message and sets
- * a flag - an ereport will be issued prior to return
- */
-
-static void
-pgxml_errorHandler(void *ctxt, const char *msg,...)
-{
-	va_list		args;
-
-	va_start(args, msg);
-	vsnprintf(errbuf, ERRBUF_SIZE, msg, args);
-	va_end(args);
-	/* Now copy the argument across */
-	if (pgxml_errorMsg == NULL)
-		pgxml_errorMsg = pstrdup(errbuf);
-	else
-	{
-		int32		xsize = strlen(pgxml_errorMsg);
-
-		pgxml_errorMsg = repalloc(pgxml_errorMsg,
-								  (size_t) (xsize + strlen(errbuf) + 1));
-		strncpy(&pgxml_errorMsg[xsize - 1], errbuf, strlen(errbuf));
-		pgxml_errorMsg[xsize + strlen(errbuf) - 1] = '\0';
-
-	}
-	memset(errbuf, 0, ERRBUF_SIZE);
-}
-
-/* This function reports the current message at the level specified */
-void
-elog_error(int level, char *explain, int force)
-{
-	if (force || (pgxml_errorMsg != NULL))
-	{
-		if (pgxml_errorMsg == NULL)
-		{
-			ereport(level, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-							errmsg("%s", explain)));
-		}
-		else
-		{
-			ereport(level, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-							errmsg("%s:%s", explain, pgxml_errorMsg)));
-			pfree(pgxml_errorMsg);
-		}
-	}
-}
-
-void
-pgxml_parser_init()
-{
-	/*
-	 * This code could also set parser settings from  user-supplied info.
-	 * Quite how these settings are made is another matter :)
-	 */
-
-	xmlMemSetup(pgxml_pfree, pgxml_palloc, pgxml_repalloc, pgxml_pstrdup);
-	xmlInitParser();
-
-	xmlSetGenericErrorFunc(NULL, pgxml_errorHandler);
-
-	xmlSubstituteEntitiesDefault(1);
-	xmlLoadExtDtdDefaultValue = 1;
-
-	pgxml_errorMsg = NULL;
-
-	errbuf = palloc(200);
-	memset(errbuf, 0, 200);
-
-}
-
-
-/* Returns true if document is well-formed */
-
-PG_FUNCTION_INFO_V1(xml_is_well_formed);
-
-Datum
-xml_is_well_formed(PG_FUNCTION_ARGS)
-{
-	/* called as xml_is_well_formed(document) */
-	xmlDocPtr	doctree;
-	text	   *t = PG_GETARG_TEXT_P(0);		/* document buffer */
-	int32		docsize = VARSIZE(t) - VARHDRSZ;
-
-	pgxml_parser_init();
-
-	doctree = xmlParseMemory((char *) VARDATA(t), docsize);
-	if (doctree == NULL)
-	{
-		xmlCleanupParser();
-		PG_RETURN_BOOL(false);	/* i.e. not well-formed */
-	}
-	xmlCleanupParser();
-	xmlFreeDoc(doctree);
-	PG_RETURN_BOOL(true);
-}
-
-
-/* Encodes special characters (<, >, &, " and \r) as XML entities */
-
-PG_FUNCTION_INFO_V1(xml_encode_special_chars);
-
-Datum
-xml_encode_special_chars(PG_FUNCTION_ARGS)
-{
-	text	   *tin = PG_GETARG_TEXT_P(0);
-	text	   *tout;
-	xmlChar    *ts,
-			   *tt;
-
-	ts = pgxml_texttoxmlchar(tin);
-
-	tt = xmlEncodeSpecialChars(NULL, ts);
-
-	pfree(ts);
-
-	tout = cstring_to_text((char *) tt);
-
-	xmlFree(tt);
-
-	PG_RETURN_TEXT_P(tout);
-}
-
-static xmlChar
-		   *
-pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
-				   xmlChar *toptagname,
-				   xmlChar *septagname,
-				   xmlChar *plainsep)
-{
-	/* Function translates a nodeset into a text representation */
-
-	/*
-	 * iterates over each node in the set and calls xmlNodeDump to write it to
-	 * an xmlBuffer -from which an xmlChar * string is returned.
-	 */
-
-	/* each representation is surrounded by <tagname> ... </tagname> */
-
-	/*
-	 * plainsep is an ordinary (not tag) seperator - if used, then nodes are
-	 * cast to string as output method
-	 */
-
-
-	xmlBufferPtr buf;
-	xmlChar    *result;
-	int			i;
-
-	buf = xmlBufferCreate();
-
-	if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
-	{
-		xmlBufferWriteChar(buf, "<");
-		xmlBufferWriteCHAR(buf, toptagname);
-		xmlBufferWriteChar(buf, ">");
-	}
-	if (nodeset != NULL)
-	{
-		for (i = 0; i < nodeset->nodeNr; i++)
-		{
-
-			if (plainsep != NULL)
-			{
-				xmlBufferWriteCHAR(buf,
-							  xmlXPathCastNodeToString(nodeset->nodeTab[i]));
-
-				/* If this isn't the last entry, write the plain sep. */
-				if (i < (nodeset->nodeNr) - 1)
-					xmlBufferWriteChar(buf, (char *) plainsep);
-			}
-			else
-			{
-
-
-				if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
-				{
-					xmlBufferWriteChar(buf, "<");
-					xmlBufferWriteCHAR(buf, septagname);
-					xmlBufferWriteChar(buf, ">");
-				}
-				xmlNodeDump(buf,
-							nodeset->nodeTab[i]->doc,
-							nodeset->nodeTab[i],
-							1, 0);
-
-				if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
-				{
-					xmlBufferWriteChar(buf, "</");
-					xmlBufferWriteCHAR(buf, septagname);
-					xmlBufferWriteChar(buf, ">");
-				}
-			}
-		}
-	}
-
-	if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
-	{
-		xmlBufferWriteChar(buf, "</");
-		xmlBufferWriteCHAR(buf, toptagname);
-		xmlBufferWriteChar(buf, ">");
-	}
-	result = xmlStrdup(buf->content);
-	xmlBufferFree(buf);
-	return result;
-}
-
-
-/* Translate a PostgreSQL "varlena" -i.e. a variable length parameter
- * into the libxml2 representation
- */
-
-xmlChar *
-pgxml_texttoxmlchar(text *textstring)
-{
-	return (xmlChar *) text_to_cstring(textstring);
-}
-
-/* Public visible XPath functions */
-
-/* This is a "raw" xpath function. Check that it returns child elements
- * properly
- */
-
-PG_FUNCTION_INFO_V1(xpath_nodeset);
-
-Datum
-xpath_nodeset(PG_FUNCTION_ARGS)
-{
-	xmlChar    *xpath,
-			   *toptag,
-			   *septag;
-	int32		pathsize;
-	text
-			   *xpathsupp,
-			   *xpres;
-
-	/* PG_GETARG_TEXT_P(0) is document buffer */
-	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
-
-	toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
-	septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
-
-	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
-
-	xpath = pgxml_texttoxmlchar(xpathsupp);
-
-	xpres = pgxml_result_to_text(
-								 pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
-								 toptag, septag, NULL);
-
-	/* xmlCleanupParser(); done by result_to_text routine */
-	pfree(xpath);
-
-	if (xpres == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_TEXT_P(xpres);
-}
-
-/*	The following function is almost identical, but returns the elements in */
-/*	a list. */
-
-PG_FUNCTION_INFO_V1(xpath_list);
-
-Datum
-xpath_list(PG_FUNCTION_ARGS)
-{
-	xmlChar    *xpath,
-			   *plainsep;
-	int32		pathsize;
-	text
-			   *xpathsupp,
-			   *xpres;
-
-	/* PG_GETARG_TEXT_P(0) is document buffer */
-	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
-
-	plainsep = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
-
-	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
-
-	xpath = pgxml_texttoxmlchar(xpathsupp);
-
-	xpres = pgxml_result_to_text(
-								 pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
-								 NULL, NULL, plainsep);
-
-	/* xmlCleanupParser(); done by result_to_text routine */
-	pfree(xpath);
-
-	if (xpres == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_TEXT_P(xpres);
-}
-
-
-PG_FUNCTION_INFO_V1(xpath_string);
-
-Datum
-xpath_string(PG_FUNCTION_ARGS)
-{
-	xmlChar    *xpath;
-	int32		pathsize;
-	text
-			   *xpathsupp,
-			   *xpres;
-
-	/* PG_GETARG_TEXT_P(0) is document buffer */
-	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
-
-	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
-
-	/*
-	 * We encapsulate the supplied path with "string()" = 8 chars + 1 for NUL
-	 * at end
-	 */
-	/* We could try casting to string using the libxml function? */
-
-	xpath = (xmlChar *) palloc(pathsize + 9);
-	memcpy((char *) (xpath + 7), VARDATA(xpathsupp), pathsize);
-	strncpy((char *) xpath, "string(", 7);
-	xpath[pathsize + 7] = ')';
-	xpath[pathsize + 8] = '\0';
-
-	xpres = pgxml_result_to_text(
-								 pgxml_xpath(PG_GETARG_TEXT_P(0), xpath),
-								 NULL, NULL, NULL);
-
-	xmlCleanupParser();
-	pfree(xpath);
-
-	if (xpres == NULL)
-		PG_RETURN_NULL();
-	PG_RETURN_TEXT_P(xpres);
-}
-
-
-PG_FUNCTION_INFO_V1(xpath_number);
-
-Datum
-xpath_number(PG_FUNCTION_ARGS)
-{
-	xmlChar    *xpath;
-	int32		pathsize;
-	text
-			   *xpathsupp;
-
-	float4		fRes;
-
-	xmlXPathObjectPtr res;
-
-	/* PG_GETARG_TEXT_P(0) is document buffer */
-	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
-
-	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
-
-	xpath = pgxml_texttoxmlchar(xpathsupp);
-
-	res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
-	pfree(xpath);
-
-	if (res == NULL)
-	{
-		xmlCleanupParser();
-		PG_RETURN_NULL();
-	}
-
-	fRes = xmlXPathCastToNumber(res);
-	xmlCleanupParser();
-	if (xmlXPathIsNaN(fRes))
-		PG_RETURN_NULL();
-
-	PG_RETURN_FLOAT4(fRes);
-
-}
-
-
-PG_FUNCTION_INFO_V1(xpath_bool);
-
-Datum
-xpath_bool(PG_FUNCTION_ARGS)
-{
-	xmlChar    *xpath;
-	int32		pathsize;
-	text
-			   *xpathsupp;
-
-	int			bRes;
-
-	xmlXPathObjectPtr res;
-
-	/* PG_GETARG_TEXT_P(0) is document buffer */
-	xpathsupp = PG_GETARG_TEXT_P(1);	/* XPath expression */
-
-	pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
-
-	xpath = pgxml_texttoxmlchar(xpathsupp);
-
-	res = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath);
-	pfree(xpath);
-
-	if (res == NULL)
-	{
-		xmlCleanupParser();
-		PG_RETURN_BOOL(false);
-	}
-
-	bRes = xmlXPathCastToBoolean(res);
-	xmlCleanupParser();
-	PG_RETURN_BOOL(bRes);
-
-}
-
-
-
-/* Core function to evaluate XPath query */
-
-xmlXPathObjectPtr
-pgxml_xpath(text *document, xmlChar *xpath)
-{
-
-	xmlDocPtr	doctree;
-	xmlXPathContextPtr ctxt;
-	xmlXPathObjectPtr res;
-
-	xmlXPathCompExprPtr comppath;
-
-	int32		docsize;
-
-
-	docsize = VARSIZE(document) - VARHDRSZ;
-
-	pgxml_parser_init();
-
-	doctree = xmlParseMemory((char *) VARDATA(document), docsize);
-	if (doctree == NULL)
-	{							/* not well-formed */
-		return NULL;
-	}
-
-	ctxt = xmlXPathNewContext(doctree);
-	ctxt->node = xmlDocGetRootElement(doctree);
-
-
-	/* compile the path */
-	comppath = xmlXPathCompile(xpath);
-	if (comppath == NULL)
-	{
-		xmlCleanupParser();
-		xmlFreeDoc(doctree);
-		elog_error(ERROR, "XPath Syntax Error", 1);
-
-		return NULL;
-	}
-
-	/* Now evaluate the path expression. */
-	res = xmlXPathCompiledEval(comppath, ctxt);
-	xmlXPathFreeCompExpr(comppath);
-
-	if (res == NULL)
-	{
-		xmlXPathFreeContext(ctxt);
-		/* xmlCleanupParser(); */
-		xmlFreeDoc(doctree);
-
-		return NULL;
-	}
-	/* xmlFreeDoc(doctree); */
-	return res;
-}
-
-text
-		   *
-pgxml_result_to_text(xmlXPathObjectPtr res,
-					 xmlChar *toptag,
-					 xmlChar *septag,
-					 xmlChar *plainsep)
-{
-	xmlChar    *xpresstr;
-	text	   *xpres;
-
-	if (res == NULL)
-	{
-		xmlCleanupParser();
-		return NULL;
-	}
-	switch (res->type)
-	{
-		case XPATH_NODESET:
-			xpresstr = pgxmlNodeSetToText(res->nodesetval,
-										  toptag,
-										  septag, plainsep);
-			break;
-
-		case XPATH_STRING:
-			xpresstr = xmlStrdup(res->stringval);
-			break;
-
-		default:
-			elog(NOTICE, "unsupported XQuery result: %d", res->type);
-			xpresstr = xmlStrdup((const xmlChar *) "<unsupported/>");
-	}
-
-
-	/* Now convert this result back to text */
-	xpres = cstring_to_text((char *) xpresstr);
-
-	/* Free various storage */
-	xmlCleanupParser();
-	/* xmlFreeDoc(doctree);  -- will die at end of tuple anyway */
-
-	xmlFree(xpresstr);
-
-	elog_error(ERROR, "XPath error", 0);
-
-
-	return xpres;
-}
-
-/* xpath_table is a table function. It needs some tidying (as do the
- * other functions here!
- */
-
-PG_FUNCTION_INFO_V1(xpath_table);
-
-Datum
-xpath_table(PG_FUNCTION_ARGS)
-{
-/* SPI (input tuple) support */
-	SPITupleTable *tuptable;
-	HeapTuple	spi_tuple;
-	TupleDesc	spi_tupdesc;
-
-/* Output tuple (tuplestore) support */
-	Tuplestorestate *tupstore = NULL;
-	TupleDesc	ret_tupdesc;
-	HeapTuple	ret_tuple;
-
-	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
-	AttInMetadata *attinmeta;
-	MemoryContext per_query_ctx;
-	MemoryContext oldcontext;
-
-/* Function parameters */
-	char	   *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0));
-	char	   *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1));
-	char	   *relname = text_to_cstring(PG_GETARG_TEXT_PP(2));
-	char	   *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3));
-	char	   *condition = text_to_cstring(PG_GETARG_TEXT_PP(4));
-
-	char	  **values;
-	xmlChar   **xpaths;
-	char	   *pos;
-	const char *pathsep = "|";
-
-	int			numpaths;
-	int			ret;
-	int			proc;
-	int			i;
-	int			j;
-	int			rownr;			/* For issuing multiple rows from one original
-								 * document */
-	int			had_values;		/* To determine end of nodeset results */
-
-	StringInfoData query_buf;
-
-	/* We only have a valid tuple description in table function mode */
-	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("set-valued function called in context that cannot accept a set")));
-	if (rsinfo->expectedDesc == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_SYNTAX_ERROR),
-				 errmsg("xpath_table must be called as a table function")));
-
-	/*
-	 * We want to materialise because it means that we don't have to carry
-	 * libxml2 parser state between invocations of this function
-	 */
-	if (!(rsinfo->allowedModes & SFRM_Materialize))
-		ereport(ERROR,
-				(errcode(ERRCODE_SYNTAX_ERROR),
-			   errmsg("xpath_table requires Materialize mode, but it is not "
-					  "allowed in this context")));
-
-	/*
-	 * The tuplestore must exist in a higher context than this function call
-	 * (per_query_ctx is used)
-	 */
-
-	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
-	oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
-	/*
-	 * Create the tuplestore - work_mem is the max in-memory size before a
-	 * file is created on disk to hold it.
-	 */
-	tupstore =
-		tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
-							  false, work_mem);
-
-	MemoryContextSwitchTo(oldcontext);
-
-	/* get the requested return tuple description */
-	ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
-
-	/*
-	 * At the moment we assume that the returned attributes make sense for the
-	 * XPath specififed (i.e. we trust the caller). It's not fatal if they get
-	 * it wrong - the input function for the column type will raise an error
-	 * if the path result can't be converted into the correct binary
-	 * representation.
-	 */
-
-	attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
-
-	/* Set return mode and allocate value space. */
-	rsinfo->returnMode = SFRM_Materialize;
-	rsinfo->setDesc = ret_tupdesc;
-
-	values = (char **) palloc(ret_tupdesc->natts * sizeof(char *));
-
-	xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *));
-
-	/* Split XPaths. xpathset is a writable CString. */
-
-	/* Note that we stop splitting once we've done all needed for tupdesc */
-
-	numpaths = 0;
-	pos = xpathset;
-	do
-	{
-		xpaths[numpaths] = (xmlChar *) pos;
-		pos = strstr(pos, pathsep);
-		if (pos != NULL)
-		{
-			*pos = '\0';
-			pos++;
-		}
-		numpaths++;
-	} while ((pos != NULL) && (numpaths < (ret_tupdesc->natts - 1)));
-
-	/* Now build query */
-	initStringInfo(&query_buf);
-
-	/* Build initial sql statement */
-	appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s",
-					 pkeyfield,
-					 xmlfield,
-					 relname,
-					 condition
-		);
-
-
-	if ((ret = SPI_connect()) < 0)
-		elog(ERROR, "xpath_table: SPI_connect returned %d", ret);
-
-	if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT)
-		elog(ERROR, "xpath_table: SPI execution failed for query %s", query_buf.data);
-
-	proc = SPI_processed;
-	/* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */
-	tuptable = SPI_tuptable;
-	spi_tupdesc = tuptable->tupdesc;
-
-/* Switch out of SPI context */
-	MemoryContextSwitchTo(oldcontext);
-
-
-/* Check that SPI returned correct result. If you put a comma into one of
- * the function parameters, this will catch it when the SPI query returns
- * e.g. 3 columns.
- */
-
-	if (spi_tupdesc->natts != 2)
-	{
-		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						errmsg("expression returning multiple columns is not valid in parameter list"),
-						errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts)));
-	}
-
-/* Setup the parser. Beware that this must happen in the same context as the
- * cleanup - which means that any error from here on must do cleanup to
- * ensure that the entity table doesn't get freed by being out of context.
- */
-	pgxml_parser_init();
-
-	/* For each row i.e. document returned from SPI */
-	for (i = 0; i < proc; i++)
-	{
-		char	   *pkey;
-		char	   *xmldoc;
-
-		xmlDocPtr	doctree;
-		xmlXPathContextPtr ctxt;
-		xmlXPathObjectPtr res;
-		xmlChar    *resstr;
-
-
-		xmlXPathCompExprPtr comppath;
-
-		/* Extract the row data as C Strings */
-		spi_tuple = tuptable->vals[i];
-		pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
-		xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2);
-
-		/*
-		 * Clear the values array, so that not-well-formed documents return
-		 * NULL in all columns.
-		 */
-
-		/* Note that this also means that spare columns will be NULL. */
-		for (j = 0; j < ret_tupdesc->natts; j++)
-			values[j] = NULL;
-
-		/* Insert primary key */
-		values[0] = pkey;
-
-		/* Parse the document */
-		if (xmldoc)
-			doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
-		else	/* treat NULL as not well-formed */
-			doctree = NULL;
-
-		if (doctree == NULL)
-		{
-			/* not well-formed, so output all-NULL tuple */
-			ret_tuple = BuildTupleFromCStrings(attinmeta, values);
-			tuplestore_puttuple(tupstore, ret_tuple);
-			heap_freetuple(ret_tuple);
-		}
-		else
-		{
-			/* New loop here - we have to deal with nodeset results */
-			rownr = 0;
-
-			do
-			{
-				/* Now evaluate the set of xpaths. */
-				had_values = 0;
-				for (j = 0; j < numpaths; j++)
-				{
-
-					ctxt = xmlXPathNewContext(doctree);
-					ctxt->node = xmlDocGetRootElement(doctree);
-					xmlSetGenericErrorFunc(ctxt, pgxml_errorHandler);
-
-					/* compile the path */
-					comppath = xmlXPathCompile(xpaths[j]);
-					if (comppath == NULL)
-					{
-						xmlCleanupParser();
-						xmlFreeDoc(doctree);
-
-						elog_error(ERROR, "XPath Syntax Error", 1);
-
-						PG_RETURN_NULL();		/* Keep compiler happy */
-					}
-
-					/* Now evaluate the path expression. */
-					res = xmlXPathCompiledEval(comppath, ctxt);
-					xmlXPathFreeCompExpr(comppath);
-
-					if (res != NULL)
-					{
-						switch (res->type)
-						{
-							case XPATH_NODESET:
-								/* We see if this nodeset has enough nodes */
-								if ((res->nodesetval != NULL) && (rownr < res->nodesetval->nodeNr))
-								{
-									resstr =
-										xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]);
-									had_values = 1;
-								}
-								else
-									resstr = NULL;
-
-								break;
-
-							case XPATH_STRING:
-								resstr = xmlStrdup(res->stringval);
-								break;
-
-							default:
-								elog(NOTICE, "unsupported XQuery result: %d", res->type);
-								resstr = xmlStrdup((const xmlChar *) "<unsupported/>");
-						}
-
-
-						/*
-						 * Insert this into the appropriate column in the
-						 * result tuple.
-						 */
-						values[j + 1] = (char *) resstr;
-					}
-					xmlXPathFreeContext(ctxt);
-				}
-				/* Now add the tuple to the output, if there is one. */
-				if (had_values)
-				{
-					ret_tuple = BuildTupleFromCStrings(attinmeta, values);
-					tuplestore_puttuple(tupstore, ret_tuple);
-					heap_freetuple(ret_tuple);
-				}
-
-				rownr++;
-
-			} while (had_values);
-
-		}
-
-		xmlFreeDoc(doctree);
-
-		if (pkey)
-			pfree(pkey);
-		if (xmldoc)
-			pfree(xmldoc);
-	}
-
-	xmlCleanupParser();
-/* Needed to flag completeness in 7.3.1. 7.4 defines it as a no-op. */
-	tuplestore_donestoring(tupstore);
-
-	SPI_finish();
-
-	rsinfo->setResult = tupstore;
-
-	/*
-	 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
-	 * tuples are in our tuplestore and passed back through rsinfo->setResult.
-	 * rsinfo->setDesc is set to the tuple description that we actually used
-	 * to build our tuples with, so the caller can verify we did what it was
-	 * expecting.
-	 */
-	return (Datum) 0;
-
-}
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
deleted file mode 100644
index 798e688..0000000
--- a/contrib/xml2/xslt_proc.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * $PostgreSQL$
- *
- * XSLT processing functions (requiring libxslt)
- *
- * John Gray, for Torchbox 2003-04-01
- */
-#include "postgres.h"
-
-#include "executor/spi.h"
-#include "fmgr.h"
-#include "funcapi.h"
-#include "miscadmin.h"
-#include "utils/builtins.h"
-
-/* libxml includes */
-
-#include <libxml/xpath.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
-
-/* libxslt includes */
-
-#include <libxslt/xslt.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/transform.h>
-#include <libxslt/xsltutils.h>
-
-
-/* declarations to come from xpath.c */
-extern void elog_error(int level, char *explain, int force);
-extern void pgxml_parser_init();
-extern xmlChar *pgxml_texttoxmlchar(text *textstring);
-
-/* local defs */
-static void parse_params(const char **params, text *paramstr);
-
-Datum		xslt_process(PG_FUNCTION_ARGS);
-
-
-#define MAXPARAMS 20			/* must be even, see parse_params() */
-
-
-PG_FUNCTION_INFO_V1(xslt_process);
-
-Datum
-xslt_process(PG_FUNCTION_ARGS)
-{
-	text	   *doct = PG_GETARG_TEXT_P(0);
-	text	   *ssheet = PG_GETARG_TEXT_P(1);
-	text	   *paramstr;
-	const char *params[MAXPARAMS + 1];	/* +1 for the terminator */
-	xsltStylesheetPtr stylesheet = NULL;
-	xmlDocPtr	doctree;
-	xmlDocPtr	restree;
-	xmlDocPtr	ssdoc = NULL;
-	xmlChar    *resstr;
-	int			resstat;
-	int			reslen;
-
-	if (fcinfo->nargs == 3)
-	{
-		paramstr = PG_GETARG_TEXT_P(2);
-		parse_params(params, paramstr);
-	}
-	else
-		/* No parameters */
-		params[0] = NULL;
-
-	/* Setup parser */
-	pgxml_parser_init();
-
-	/* Check to see if document is a file or a literal */
-
-	if (VARDATA(doct)[0] == '<')
-		doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
-	else
-		doctree = xmlParseFile(text_to_cstring(doct));
-
-	if (doctree == NULL)
-	{
-		xmlCleanupParser();
-		elog_error(ERROR, "error parsing XML document", 0);
-
-		PG_RETURN_NULL();
-	}
-
-	/* Same for stylesheet */
-	if (VARDATA(ssheet)[0] == '<')
-	{
-		ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
-							   VARSIZE(ssheet) - VARHDRSZ);
-		if (ssdoc == NULL)
-		{
-			xmlFreeDoc(doctree);
-			xmlCleanupParser();
-			elog_error(ERROR, "error parsing stylesheet as XML document", 0);
-			PG_RETURN_NULL();
-		}
-
-		stylesheet = xsltParseStylesheetDoc(ssdoc);
-	}
-	else
-		stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet));
-
-
-	if (stylesheet == NULL)
-	{
-		xmlFreeDoc(doctree);
-		xsltCleanupGlobals();
-		xmlCleanupParser();
-		elog_error(ERROR, "failed to parse stylesheet", 0);
-		PG_RETURN_NULL();
-	}
-
-	restree = xsltApplyStylesheet(stylesheet, doctree, params);
-	resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
-
-	xsltFreeStylesheet(stylesheet);
-	xmlFreeDoc(restree);
-	xmlFreeDoc(doctree);
-
-	xsltCleanupGlobals();
-	xmlCleanupParser();
-
-	if (resstat < 0)
-		PG_RETURN_NULL();
-
-	PG_RETURN_TEXT_P(cstring_to_text_with_len((char *) resstr, reslen));
-}
-
-
-static void
-parse_params(const char **params, text *paramstr)
-{
-	char	   *pos;
-	char	   *pstr;
-	int			i;
-	char	   *nvsep = "=";
-	char	   *itsep = ",";
-
-	pstr = text_to_cstring(paramstr);
-
-	pos = pstr;
-
-	for (i = 0; i < MAXPARAMS; i++)
-	{
-		params[i] = pos;
-		pos = strstr(pos, nvsep);
-		if (pos != NULL)
-		{
-			*pos = '\0';
-			pos++;
-		}
-		else
-		{
-			/* No equal sign, so ignore this "parameter" */
-			/* We'll reset params[i] to NULL below the loop */
-			break;
-		}
-		/* Value */
-		i++;
-		/* since MAXPARAMS is even, we still have i < MAXPARAMS */
-		params[i] = pos;
-		pos = strstr(pos, itsep);
-		if (pos != NULL)
-		{
-			*pos = '\0';
-			pos++;
-		}
-		else
-		{
-			i++;
-			break;
-		}
-	}
-
-	params[i] = NULL;
-}
diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml
index cd8775d..00b2ce5 100644
--- a/doc/src/sgml/contrib.sgml
+++ b/doc/src/sgml/contrib.sgml
@@ -117,6 +117,5 @@ psql -d dbname -f <replaceable>SHAREDIR</>/contrib/<replaceable>module</>.sql
  &unaccent;
  &uuid-ossp;
  &vacuumlo;
- &xml2;
 
 </appendix>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 4d2a0d7..204daba 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -130,7 +130,6 @@
 <!entity unaccent      SYSTEM "unaccent.sgml">
 <!entity uuid-ossp       SYSTEM "uuid-ossp.sgml">
 <!entity vacuumlo        SYSTEM "vacuumlo.sgml">
-<!entity xml2            SYSTEM "xml2.sgml"> 
 
 <!-- appendixes -->
 <!entity contacts   SYSTEM "contacts.sgml">
diff --git a/doc/src/sgml/install-win32.sgml b/doc/src/sgml/install-win32.sgml
index a6b97f4..28814be 100644
--- a/doc/src/sgml/install-win32.sgml
+++ b/doc/src/sgml/install-win32.sgml
@@ -212,8 +212,7 @@
     </varlistentry>
 
     <varlistentry>
-     <term><productname>libxml2</productname> and
-      <productname>libxslt</productname></term>
+     <term><productname>libxml2</productname></term>
      <listitem><para>
       Required for XML support. Binaries can be downloaded from
       <ulink url="http://zlatkovic.com/pub/libxml"></> or source from
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 30041ad..4d5a427 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1027,17 +1027,6 @@ su - postgres
       </varlistentry>
 
       <varlistentry>
-       <term><option>--with-libxslt</option></term>
-       <listitem>
-        <para>
-         Use libxslt when building <filename>contrib/xml2</>.
-         <filename>contrib/xml2</> relies on this library to perform
-         XSL transformations of XML.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term><option>--disable-integer-datetimes</option></term>
        <listitem>
         <para>
diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml
deleted file mode 100644
index 3507684..0000000
--- a/doc/src/sgml/xml2.sgml
+++ /dev/null
@@ -1,425 +0,0 @@
-<!-- $PostgreSQL$ -->
-
-<sect1 id="xml2">
- <title>xml2</title>
-
- <indexterm zone="xml2">
-  <primary>xml2</primary>
- </indexterm>
-
- <para>
-  The <filename>xml2</> module provides XPath querying and
-  XSLT functionality.
- </para>
-
- <sect2>
-  <title>Deprecation notice</title>
-
-  <para>
-   From <productname>PostgreSQL</> 8.3 on, there is XML-related
-   functionality based on the SQL/XML standard in the core server.
-   That functionality covers XML syntax checking and XPath queries,
-   which is what this module does, and more, but the API is
-   not at all compatible.  It is planned that this module will be
-   removed in PostgreSQL 8.4 in favor of the newer standard API, so
-   you are encouraged to try converting your applications.  If you
-   find that some of the functionality of this module is not
-   available in an adequate form with the newer API, please explain
-   your issue to pgsql-hackers@postgresql.org so that the deficiency
-   can be addressed.
-  </para>
- </sect2>
-
- <sect2>
-  <title>Description of functions</title>
-
-  <para>
-   <xref linkend="xml2-functions-table"> shows the functions provided by this module.
-   These functions provide straightforward XML parsing and XPath queries.
-   All arguments are of type <type>text</>, so for brevity that is not shown.
-  </para>
-
-  <table id="xml2-functions-table">
-   <title>Functions</title>
-   <tgroup cols="2">
-    <tbody>
-     <row>
-      <entry>
-       <synopsis>
-        xml_is_well_formed(document) returns bool
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-        This parses the document text in its parameter and returns true if the
-        document is well-formed XML.  (Note: before PostgreSQL 8.2, this
-        function was called <function>xml_valid()</>.  That is the wrong name
-        since validity and well-formedness have different meanings in XML.
-        The old name is still available, but is deprecated.)
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_string(document,query) returns text
-        xpath_number(document,query) returns float4
-        xpath_bool(document,query) returns bool
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-        These functions evaluate the XPath query on the supplied document, and
-        cast the result to the specified type.
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_nodeset(document,query,toptag,itemtag) returns text
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-       This evaluates query on document and wraps the result in XML tags. If
-       the result is multivalued, the output will look like:
-       </para>
-       <literal>
-        &lt;toptag&gt;
-        &lt;itemtag&gt;Value 1 which could be an XML fragment&lt;/itemtag&gt;
-        &lt;itemtag&gt;Value 2....&lt;/itemtag&gt;
-        &lt;/toptag&gt;
-       </literal>
-       <para>
-        If either toptag or itemtag is an empty string, the relevant tag is omitted.
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_nodeset(document,query) returns text
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-        Like xpath_nodeset(document,query,toptag,itemtag) but result omits both tags.
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_nodeset(document,query,itemtag) returns text
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-        Like xpath_nodeset(document,query,toptag,itemtag) but result omits toptag.
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_list(document,query,separator) returns text
-       </synopsis>
-      </entry>
-      <entry>
-       <para>
-        This function returns multiple values separated by the specified
-        separator, for example <literal>Value 1,Value 2,Value 3</> if
-        separator is <literal>,</>.
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry>
-       <synopsis>
-        xpath_list(document,query) returns text
-       </synopsis>
-      </entry>
-      <entry>
-       This is a wrapper for the above function that uses <literal>,</>
-       as the separator.
-      </entry>
-     </row>
-    </tbody>
-   </tgroup>
-  </table>
- </sect2>
-
- <sect2>
-  <title><literal>xpath_table</literal></title>
-
-  <synopsis>
-   xpath_table(text key, text document, text relation, text xpaths, text criteria) returns setof record
-  </synopsis>
-
-  <para>
-   <function>xpath_table</> is a table function that evaluates a set of XPath
-   queries on each of a set of documents and returns the results as a
-   table. The primary key field from the original document table is returned
-   as the first column of the result so that the result set
-   can readily be used in joins.
-  </para>
-
-  <table>
-   <title>Parameters</title>
-   <tgroup cols="2">
-    <tbody>
-     <row>
-      <entry><parameter>key</parameter></entry>
-      <entry>
-       <para>
-        the name of the <quote>key</> field &mdash; this is just a field to be used as
-        the first column of the output table, i.e., it identifies the record from
-        which each output row came (see note below about multiple values)
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry><parameter>document</parameter></entry>
-      <entry>
-       <para>
-        the name of the field containing the XML document
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry><parameter>relation</parameter></entry>
-      <entry>
-       <para>
-        the name of the table or view containing the documents
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry><parameter>xpaths</parameter></entry>
-      <entry>
-       <para>
-        one or more XPath expressions, separated by <literal>|</literal>
-       </para>
-      </entry>
-     </row>
-     <row>
-      <entry><parameter>criteria</parameter></entry>
-      <entry>
-       <para>
-        the contents of the WHERE clause. This cannot be omitted, so use
-        <literal>true</literal> or <literal>1=1</literal> if you want to
-        process all the rows in the relation
-       </para>
-      </entry>
-     </row>
-    </tbody>
-   </tgroup>
-  </table>
-
-  <para>
-   These parameters (except the XPath strings) are just substituted
-   into a plain SQL SELECT statement, so you have some flexibility &mdash; the
-   statement is
-  </para>
-
-  <para>
-   <literal>
-    SELECT &lt;key&gt;, &lt;document&gt; FROM &lt;relation&gt; WHERE &lt;criteria&gt;
-   </literal>
-  </para>
-
-  <para>
-   so those parameters can be <emphasis>anything</> valid in those particular
-   locations. The result from this SELECT needs to return exactly two
-   columns (which it will unless you try to list multiple fields for key
-   or document). Beware that this simplistic approach requires that you
-   validate any user-supplied values to avoid SQL injection attacks.
-  </para>
-
-  <para>
-   The function has to be used in a <literal>FROM</> expression, with an
-   <literal>AS</> clause to specify the output columns; for example
-  </para>
-
-  <programlisting>
-SELECT * FROM
-xpath_table('article_id',
-            'article_xml',
-            'articles',
-            '/article/author|/article/pages|/article/title',
-            'date_entered > ''2003-01-01'' ')
-AS t(article_id integer, author text, page_count integer, title text);
-  </programlisting>
-
-  <para>
-   The <literal>AS</> clause defines the names and types of the columns in the
-   output table.  The first is the <quote>key</> field and the rest correspond
-   to the XPath queries.
-   If there are more XPath queries than result columns,
-   the extra queries will be ignored. If there are more result columns
-   than XPath queries, the extra columns will be NULL.
-  </para>
-
-  <para>
-   Notice that this example defines the <structname>page_count</> result
-   column as an integer.  The function deals internally with string
-   representations, so when you say you want an integer in the output, it will
-   take the string representation of the XPath result and use PostgreSQL input
-   functions to transform it into an integer (or whatever type the <type>AS</>
-   clause requests). An error will result if it can't do this &mdash; for
-   example if the result is empty &mdash; so you may wish to just stick to
-   <type>text</> as the column type if you think your data has any problems.
-  </para>
-
-  <para>
-   The calling <command>SELECT</> statement doesn't necessarily have be
-   be just <literal>SELECT *</> &mdash; it can reference the output
-   columns by name or join them to other tables. The function produces a
-   virtual table with which you can perform any operation you wish (e.g.
-   aggregation, joining, sorting etc). So we could also have:
-  </para>
-
-  <programlisting>
-SELECT t.title, p.fullname, p.email
-FROM xpath_table('article_id', 'article_xml', 'articles',
-                 '/article/title|/article/author/@id',
-                 'xpath_string(article_xml,''/article/@date'') > ''2003-03-20'' ')
-       AS t(article_id integer, title text, author_id integer),
-     tblPeopleInfo AS p
-WHERE t.author_id = p.person_id;
-  </programlisting>
-
-  <para>
-   as a more complicated example. Of course, you could wrap all
-   of this in a view for convenience.
-  </para>
-
-  <sect3>
-   <title>Multivalued results</title>
-
-   <para>
-    The <function>xpath_table</> function assumes that the results of each XPath query
-    might be multi-valued, so the number of rows returned by the function
-    may not be the same as the number of input documents. The first row
-    returned contains the first result from each query, the second row the
-    second result from each query. If one of the queries has fewer values
-    than the others, NULLs will be returned instead.
-   </para>
-
-   <para>
-    In some cases, a user will know that a given XPath query will return
-    only a single result (perhaps a unique document identifier) &mdash; if used
-    alongside an XPath query returning multiple results, the single-valued
-    result will appear only on the first row of the result. The solution
-    to this is to use the key field as part of a join against a simpler
-    XPath query. As an example:
-   </para>
-
-   <programlisting>
-    CREATE TABLE test (
-        id int4 NOT NULL,
-        xml text,
-        CONSTRAINT pk PRIMARY KEY (id)
-    );
-
-    INSERT INTO test VALUES (1, '&lt;doc num="C1"&gt;
-    &lt;line num="L1"&gt;&lt;a&gt;1&lt;/a&gt;&lt;b&gt;2&lt;/b&gt;&lt;c&gt;3&lt;/c&gt;&lt;/line&gt;
-    &lt;line num="L2"&gt;&lt;a&gt;11&lt;/a&gt;&lt;b&gt;22&lt;/b&gt;&lt;c&gt;33&lt;/c&gt;&lt;/line&gt;
-    &lt;/doc&gt;');
-
-    INSERT INTO test VALUES (2, '&lt;doc num="C2"&gt;
-    &lt;line num="L1"&gt;&lt;a&gt;111&lt;/a&gt;&lt;b&gt;222&lt;/b&gt;&lt;c&gt;333&lt;/c&gt;&lt;/line&gt;
-    &lt;line num="L2"&gt;&lt;a&gt;111&lt;/a&gt;&lt;b&gt;222&lt;/b&gt;&lt;c&gt;333&lt;/c&gt;&lt;/line&gt;
-    &lt;/doc&gt;');
-
-    SELECT * FROM
-      xpath_table('id','xml','test',
-                  '/doc/@num|/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
-                  'true')
-      AS t(id int4, doc_num varchar(10), line_num varchar(10), val1 int4, val2 int4, val3 int4)
-    WHERE id = 1 ORDER BY doc_num, line_num
-
-     id | doc_num | line_num | val1 | val2 | val3
-    ----+---------+----------+------+------+------
-      1 | C1      | L1       |    1 |    2 |    3
-      1 |         | L2       |   11 |   22 |   33
-   </programlisting>
-
-   <para>
-    To get doc_num on every line, the solution is to use two invocations
-    of xpath_table and join the results:
-   </para>
-
-   <programlisting>
-   SELECT t.*,i.doc_num FROM
-     xpath_table('id', 'xml', 'test',
-                 '/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
-                 'true')
-       AS t(id int4, line_num varchar(10), val1 int4, val2 int4, val3 int4),
-     xpath_table('id', 'xml', 'test', '/doc/@num', 'true')
-       AS i(id int4, doc_num varchar(10))
-   WHERE i.id=t.id AND i.id=1
-   ORDER BY doc_num, line_num;
-
-    id | line_num | val1 | val2 | val3 | doc_num
-   ----+----------+------+------+------+---------
-     1 | L1       |    1 |    2 |    3 | C1
-     1 | L2       |   11 |   22 |   33 | C1
-   (2 rows)
-   </programlisting>
-  </sect3>
- </sect2>
-
- <sect2>
-  <title>XSLT functions</title>
-
-  <para>
-   The following functions are available if libxslt is installed:
-  </para>
-
-  <sect3>
-   <title><literal>xslt_process</literal></title>
-
-   <synopsis>
-    xslt_process(text document, text stylesheet, text paramlist) returns text
-   </synopsis>
-
-   <para>
-    This function appplies the XSL stylesheet to the document and returns
-    the transformed result. The paramlist is a list of parameter
-    assignments to be used in the transformation, specified in the form
-    <literal>a=1,b=2</>. Note that the
-    parameter parsing is very simple-minded: parameter values cannot
-    contain commas!
-   </para>
-
-   <para>
-    Also note that if either the document or stylesheet values do not
-    begin with a &lt; then they will be treated as URLs and libxslt will
-    fetch them. It follows that you can use <function>xslt_process</> as a
-    means to fetch the contents of URLs &mdash; you should be aware of the
-    security implications of this.
-   </para>
-
-   <para>
-    There is also a two-parameter version of <function>xslt_process</> which
-    does not pass any parameters to the transformation.
-   </para>
-  </sect3>
- </sect2>
-
- <sect2>
-  <title>Author</title>
-
-  <para>
-   John Gray <email>jgray@azuli.co.uk</email>
-  </para>
-
-  <para>
-   Development of this module was sponsored by Torchbox Ltd. (www.torchbox.com).
-   It has the same BSD licence as PostgreSQL.
-  </para>
- </sect2>
-
-</sect1>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 7a6e3a9..813a824 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -155,7 +155,6 @@ with_tcl	= @with_tcl@
 with_openssl	= @with_openssl@
 with_ossp_uuid	= @with_ossp_uuid@
 with_libxml	= @with_libxml@
-with_libxslt	= @with_libxslt@
 with_system_tzdata = @with_system_tzdata@
 with_zlib	= @with_zlib@
 enable_shared	= @enable_shared@
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 69799a5..d851c6a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -317,9 +317,6 @@
 /* Define to 1 if you have the `xml2' library (-lxml2). */
 #undef HAVE_LIBXML2
 
-/* Define to 1 if you have the `xslt' library (-lxslt). */
-#undef HAVE_LIBXSLT
-
 /* Define to 1 if you have the `z' library (-lz). */
 #undef HAVE_LIBZ
 
@@ -759,10 +756,6 @@
 /* Define to 1 to build with XML support. (--with-libxml) */
 #undef USE_LIBXML
 
-/* Define to 1 to use XSLT support when building contrib/xml2.
-   (--with-libxslt) */
-#undef USE_LIBXSLT
-
 /* Define to select named POSIX semaphores. */
 #undef USE_NAMED_POSIX_SEMAPHORES
 
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index b0164bb..0d9fbb4 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -286,13 +286,11 @@ sub mkvcbuild
     {
         $contrib_extraincludes->{'pgxml'} = [
             $solution->{options}->{xml} . '\include',
-            $solution->{options}->{xslt} . '\include',
             $solution->{options}->{iconv} . '\include'
         ];
 
         $contrib_extralibs->{'pgxml'} = [
-            $solution->{options}->{xml} . '\lib\libxml2.lib',
-            $solution->{options}->{xslt} . '\lib\libxslt.lib'
+            $solution->{options}->{xml} . '\lib\libxml2.lib'
         ];
     }
     else
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 850ad5a..801874c 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -29,9 +29,9 @@ sub new
         unless exists $options->{float4byval};
     if ($options->{xml})
     {
-        if (!($options->{xslt} && $options->{iconv}))
+        if (! $options->{iconv})
         {
-            die "XML requires both XSLT and ICONV\n";
+            die "XML requires ICONV\n";
         }
     }
 	$options->{blocksize} = 8
@@ -515,7 +515,6 @@ sub GetFakeConfigure
     $cfg .= ' --with-openssl' if ($self->{options}->{ssl});
     $cfg .= ' --with-ossp-uuid' if ($self->{options}->{uuid});
     $cfg .= ' --with-libxml' if ($self->{options}->{xml});
-    $cfg .= ' --with-libxslt' if ($self->{options}->{xslt});
     $cfg .= ' --with-krb5' if ($self->{options}->{krb5});
     $cfg .= ' --with-tcl' if ($self->{options}->{tcl});
     $cfg .= ' --with-perl' if ($self->{options}->{perl});
diff --git a/src/tools/msvc/config_default.pl b/src/tools/msvc/config_default.pl
index eea4a70..9677b52 100644
--- a/src/tools/msvc/config_default.pl
+++ b/src/tools/msvc/config_default.pl
@@ -19,7 +19,6 @@ our $config = {
     openssl=>undef,			# --with-ssl=<path>
     uuid=>undef,			# --with-ossp-uuid
     xml=>undef,				# --with-libxml=<path>
-    xslt=>undef,			# --with-libxslt=<path>
     iconv=>undef,			# (not in configure, path to iconv)
     zlib=>undef				# --with-zlib=<path>
 };
