I wrote:
> Andrew Dunstan <[email protected]> writes:
>> I think we can probably use xmlParseInNodeContext(), which does take an 
>> options argument. Did you look at that?

> Hmm ... I think I was confused by the fact that it takes "const char
> *data" not "const xmlChar *string".  On further research, those are
> more equivalent than I'd thought.  So maybe it'll work.

Here's a quick draft that passes check-world, which is enough to give
me no faith whatsoever.  Maybe somebody who knows XML better than me
can break it.  One thing I'm pretty unsure about is having to cons up
a dummy root node, which is necessary because xmlParseInNodeContext
takes a parent node not a parent doc.  Is that correct?  In the case
where we don't call xmlParseInNodeContext because the string is empty,
should we still make that node or just leave the document root-less?

                        regards, tom lane

diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 0953ad2becb..624851e83e6 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -1773,7 +1773,7 @@ xml_doctype_in_content(const xmlChar *str)
  * xmloption_arg, but a DOCTYPE node in the input can force DOCUMENT mode).
  *
  * If parsed_nodes isn't NULL and we parse in CONTENT mode, the list
- * of parsed nodes from the xmlParseBalancedChunkMemory call will be returned
+ * of parsed nodes from the xmlParseInNodeContext call will be returned
  * to *parsed_nodes.  (It is caller's responsibility to free that.)
  *
  * Errors normally result in ereport(ERROR), but if escontext is an
@@ -1799,7 +1799,6 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 	PgXmlErrorContext *xmlerrcxt;
 	volatile xmlParserCtxtPtr ctxt = NULL;
 	volatile xmlDocPtr doc = NULL;
-	volatile int save_keep_blanks = -1;
 
 	/*
 	 * This step looks annoyingly redundant, but we must do it to have a
@@ -1827,10 +1826,10 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 	PG_TRY();
 	{
 		bool		parse_as_document = false;
-		int			res_code;
 		size_t		count = 0;
 		xmlChar    *version = NULL;
 		int			standalone = 0;
+		int			options;
 
 		/* Any errors here are reported as hard ereport's */
 		xmlInitParser();
@@ -1841,6 +1840,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 		else
 		{
 			/* Parse and skip over the XML declaration, if any */
+			int			res_code;
+
 			res_code = parse_xml_decl(utf8string,
 									  &count, &version, NULL, &standalone);
 			if (res_code != 0)
@@ -1857,6 +1858,18 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 				parse_as_document = true;
 		}
 
+		/*
+		 * Select parse options.
+		 *
+		 * Note that here we try to apply DTD defaults (XML_PARSE_DTDATTR)
+		 * according to SQL/XML:2008 GR 10.16.7.d: 'Default values defined by
+		 * internal DTD are applied'.  As for external DTDs, we try to support
+		 * them too (see SQL/XML:2008 GR 10.16.7.e), but that doesn't really
+		 * happen because xmlPgEntityLoader prevents it.
+		 */
+		options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
+			| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
+
 		/* initialize output parameters */
 		if (parsed_xmloptiontype != NULL)
 			*parsed_xmloptiontype = parse_as_document ? XMLOPTION_DOCUMENT :
@@ -1866,26 +1879,12 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 
 		if (parse_as_document)
 		{
-			int			options;
-
 			/* set up parser context used by xmlCtxtReadDoc */
 			ctxt = xmlNewParserCtxt();
 			if (ctxt == NULL || xmlerrcxt->err_occurred)
 				xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
 							"could not allocate parser context");
 
-			/*
-			 * Select parse options.
-			 *
-			 * Note that here we try to apply DTD defaults (XML_PARSE_DTDATTR)
-			 * according to SQL/XML:2008 GR 10.16.7.d: 'Default values defined
-			 * by internal DTD are applied'.  As for external DTDs, we try to
-			 * support them too (see SQL/XML:2008 GR 10.16.7.e), but that
-			 * doesn't really happen because xmlPgEntityLoader prevents it.
-			 */
-			options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
-				| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
-
 			doc = xmlCtxtReadDoc(ctxt, utf8string,
 								 NULL,	/* no URL */
 								 "UTF-8",
@@ -1907,7 +1906,9 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 		}
 		else
 		{
-			/* set up document that xmlParseBalancedChunkMemory will add to */
+			xmlNodePtr	root;
+
+			/* set up document that xmlParseInNodeContext will add to */
 			doc = xmlNewDoc(version);
 			if (doc == NULL || xmlerrcxt->err_occurred)
 				xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
@@ -1920,16 +1921,35 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
 							"could not allocate XML document");
 			doc->standalone = standalone;
 
-			/* set parse options --- have to do this the ugly way */
-			save_keep_blanks = xmlKeepBlanksDefault(preserve_whitespace ? 1 : 0);
+			root = xmlNewNode(NULL, (const xmlChar *) "content-root");
+			if (root == NULL || xmlerrcxt->err_occurred)
+				xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
+							"could not allocate xml node");
+			xmlDocSetRootElement(doc, root);
 
 			/* allow empty content */
 			if (*(utf8string + count))
 			{
-				res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
-													   utf8string + count,
-													   parsed_nodes);
-				if (res_code != 0 || xmlerrcxt->err_occurred)
+				/* for some reason we need "char *" not "xmlChar *" here */
+				const char *data = (const char *) (utf8string + count);
+				xmlNodePtr *nodelist;
+				xmlNodePtr	locallist = NULL;
+				xmlParserErrors res_code;
+
+				/* xmlParseInNodeContext requires a non-null nodelist ptr */
+				nodelist = parsed_nodes ? parsed_nodes : &locallist;
+
+				res_code = xmlParseInNodeContext(root,
+												 data,
+												 strlen(data),
+												 options,
+												 nodelist);
+
+				/* drop the nodelist if caller didn't want it */
+				if (!parsed_nodes)
+					xmlFreeNodeList(locallist);
+
+				if (res_code != XML_ERR_OK || xmlerrcxt->err_occurred)
 				{
 					xml_errsave(escontext, xmlerrcxt,
 								ERRCODE_INVALID_XML_CONTENT,
@@ -1944,8 +1964,6 @@ fail:
 	}
 	PG_CATCH();
 	{
-		if (save_keep_blanks != -1)
-			xmlKeepBlanksDefault(save_keep_blanks);
 		if (doc != NULL)
 			xmlFreeDoc(doc);
 		if (ctxt != NULL)
@@ -1957,9 +1975,6 @@ fail:
 	}
 	PG_END_TRY();
 
-	if (save_keep_blanks != -1)
-		xmlKeepBlanksDefault(save_keep_blanks);
-
 	if (ctxt != NULL)
 		xmlFreeParserCtxt(ctxt);
 

Reply via email to