]> granicus.if.org Git - postgresql/commitdiff
Handle content and document options in xmlparse() correctly.
authorPeter Eisentraut <peter_e@gmx.net>
Thu, 28 Dec 2006 03:17:38 +0000 (03:17 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Thu, 28 Dec 2006 03:17:38 +0000 (03:17 +0000)
src/backend/utils/adt/xml.c
src/test/regress/expected/xml.out
src/test/regress/expected/xml_1.out
src/test/regress/sql/xml.sql

index 7babc82551c34a1c3119f1d18acfdcc85e4e8b51..83704f6c7941795e1ed4d15ee6c1cd86fe7ac9a7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.5 2006/12/24 18:25:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.6 2006/12/28 03:17:38 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,7 +58,7 @@ static void   xml_errorHandler(void *ctxt, const char *msg, ...);
 static void    xml_ereport_by_code(int level, int sqlcode,
                                                                        const char *msg, int errcode);
 static xmlChar *xml_text2xmlChar(text *in);
-static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
+static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
 
 #endif /* USE_LIBXML */
 
@@ -86,7 +86,7 @@ xml_in(PG_FUNCTION_ARGS)
         * that ERROR occurred if parsing failed.  Do we need DTD
         * validation (if DTD exists)?
         */
-       xml_parse(vardata, XML_PARSE_DTDATTR | XML_PARSE_DTDVALID, false);
+       xml_parse(vardata, false, true);
 
        PG_RETURN_XML_P(vardata);
 #else
@@ -179,18 +179,7 @@ xmltype *
 xmlparse(text *data, bool is_document, bool preserve_whitespace)
 {
 #ifdef USE_LIBXML
-       if (!preserve_whitespace)
-               ereport(WARNING,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("XMLPARSE with STRIP WHITESPACE is not implemented")));
-
-       /*
-        * Note, that here we try to apply DTD defaults
-        * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
-        * valies defined by internal DTD are applied'.  As for external
-        * DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
-        */
-       xml_parse(data, XML_PARSE_DTDATTR, is_document);
+       xml_parse(data, is_document, preserve_whitespace);
 
        return (xmltype *) data;
 #else
@@ -421,27 +410,18 @@ xml_init(void)
 
 /*
  * Convert a C string to XML internal representation
- * (same things as for TEXT, but with checking the data for well-formedness
- * and, moreover, validation against DTD, if needed).
- * NOTICE: We use TEXT type as internal storage type. In the future,
- * we plan to create own storage type (maybe several types/strategies)
- * TODO predefined DTDs / XSDs and validation
- * TODO validation against XML Schema
+ *
  * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
  * TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
  */
 static xmlDocPtr
-xml_parse(text *data, int opts, bool is_document)
+xml_parse(text *data, bool is_document, bool preserve_whitespace)
 {
-       bool                            validationFailed = false;
        int                                     res_code;
        int32                           len;
        xmlChar                         *string;
        xmlParserCtxtPtr        ctxt = NULL;
        xmlDocPtr                       doc = NULL;
-#ifdef XML_DEBUG_DTD_CONST
-       xmlDtdPtr                       dtd = NULL;
-#endif
 
        len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
        string = xml_text2xmlChar(data);
@@ -456,51 +436,40 @@ xml_parse(text *data, int opts, bool is_document)
                        xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
                                                "could not allocate parser context", ctxt);
 
-               /* first, we try to parse the string as XML doc, then, as XML chunk */
-               if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
+               if (is_document)
                {
-                       /* consider it as DOCUMENT */
+                       /*
+                        * Note, that here we try to apply DTD defaults
+                        * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d:
+                        * 'Default valies defined by internal DTD are applied'.
+                        * As for external DTDs, we try to support them too, (see
+                        * SQL/XML:10.16.7.e)
+                        */
                        doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
-                                                                       PG_XML_DEFAULT_URI, NULL, opts);
+                                                                       PG_XML_DEFAULT_URI, NULL,
+                                                                       XML_PARSE_NOENT | XML_PARSE_DTDATTR
+                                                                       | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
                        if (doc == NULL)
                                xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                                       "could not parse XML data", ctxt);
+                                                       "invalid XML document", ctxt);
                }
                else
                {
-                       /* attempt to parse the string as if it is an XML fragment */
                        doc = xmlNewDoc(NULL);
+
+                       /*
+                        * FIXME: An XMLDecl is supposed to be accepted before the
+                        * content, but libxml doesn't allow this.  Parse that
+                        * ourselves?
+                        */
+
                        /* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
                        res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
                        if (res_code != 0)
-                               xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                                                       "could not parse XML data", res_code);
+                               xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
+                                                                       "invalid XML content", res_code);
                }
 
-#ifdef XML_DEBUG_DTD_CONST
-               dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
-               if (dtd == NULL)
-                       xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "could not parse DTD data", ctxt);
-               if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
-                       validationFailed = true;
-#else
-               /* if dtd for our xml data is detected... */
-               if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
-               {
-                       /* assume inline DTD exists - validation should be performed */
-                       if (ctxt->valid == 0)
-                       {
-                               /* DTD exists, but validator reported 'validation failed' */
-                               validationFailed = true;
-                       }
-               }
-#endif
-
-               if (validationFailed)
-                       xml_ereport(WARNING, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "validation against DTD failed", ctxt);
-
                /* TODO encoding issues
                 * (thoughts:
                 *              CASE:
@@ -517,10 +486,6 @@ xml_parse(text *data, int opts, bool is_document)
                 * ) */
                /* ... */
 
-#ifdef XML_DEBUG_DTD_CONST
-               if (dtd)
-                       xmlFreeDtd(dtd);
-#endif
                if (doc)
                        xmlFreeDoc(doc);
                if (ctxt)
@@ -529,10 +494,6 @@ xml_parse(text *data, int opts, bool is_document)
        }
        PG_CATCH();
        {
-#ifdef XML_DEBUG_DTD_CONST
-               if (dtd)
-                       xmlFreeDtd(dtd);
-#endif
                if (doc)
                        xmlFreeDoc(doc);
                if (ctxt)
index 20a2d4fa02ea2d0f345870f40b6154163db4f01d..14744656124008b0a7f24f3d5dff2d295a1bc18a 100644 (file)
@@ -5,7 +5,7 @@ CREATE TABLE xmltest (
 INSERT INTO xmltest VALUES (1, '<value>one</value>');
 INSERT INTO xmltest VALUES (2, '<value>two</value>');
 INSERT INTO xmltest VALUES (3, '<wrong');
-ERROR:  could not parse XML data
+ERROR:  invalid XML content
 DETAIL:  Expected '>'
 SELECT * FROM xmltest;
  id |        data        
@@ -53,7 +53,7 @@ SELECT xmlconcat('hello', 'you');
 SELECT xmlconcat(1, 2);
 ERROR:  argument of XMLCONCAT must be type xml, not type integer
 SELECT xmlconcat('bad', '<syntax');
-ERROR:  could not parse XML data
+ERROR:  invalid XML content
 DETAIL:  Expected '>'
 SELECT xmlelement(name element,
                   xmlattributes (1 as one, 'deuce' as two),
@@ -85,6 +85,27 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 
 SELECT xmlelement(name wrong, 37);
 ERROR:  argument of XMLELEMENT must be type xml, not type integer
+SELECT xmlparse(content 'abc');
+ xmlparse 
+----------
+ abc
+(1 row)
+
+SELECT xmlparse(content '<abc>x</abc>');
+   xmlparse   
+--------------
+ <abc>x</abc>
+(1 row)
+
+SELECT xmlparse(document 'abc');
+ERROR:  invalid XML document
+DETAIL:  Start tag expected, '<' not found.
+SELECT xmlparse(document '<abc>x</abc>');
+   xmlparse   
+--------------
+ <abc>x</abc>
+(1 row)
+
 SELECT xmlpi(name foo);
   xmlpi  
 ---------
index e756b3830e12e49cdc8f5467d6ddd96712b74d2a..259bccbf4ba45aacee75354a9be5ff29e9db35eb 100644 (file)
@@ -46,6 +46,14 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 ERROR:  no XML support in this installation
 SELECT xmlelement(name wrong, 37);
 ERROR:  no XML support in this installation
+SELECT xmlparse(content 'abc');
+ERROR:  no XML support in this installation
+SELECT xmlparse(content '<abc>x</abc>');
+ERROR:  no XML support in this installation
+SELECT xmlparse(document 'abc');
+ERROR:  no XML support in this installation
+SELECT xmlparse(document '<abc>x</abc>');
+ERROR:  no XML support in this installation
 SELECT xmlpi(name foo);
 ERROR:  no XML support in this installation
 SELECT xmlpi(name xmlstuff);
index 061f6329f9bae91dd9a3d9cdfb9737d2946667d7..11db4905c7674b1c756f9edde7a09eebdfaedb33 100644 (file)
@@ -40,6 +40,13 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
 SELECT xmlelement(name wrong, 37);
 
 
+SELECT xmlparse(content 'abc');
+SELECT xmlparse(content '<abc>x</abc>');
+
+SELECT xmlparse(document 'abc');
+SELECT xmlparse(document '<abc>x</abc>');
+
+
 SELECT xmlpi(name foo);
 SELECT xmlpi(name xmlstuff);
 SELECT xmlpi(name foo, 'bar');