]> granicus.if.org Git - postgresql/commitdiff
Fix namespace handling in xpath function
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 7 Jan 2015 04:06:13 +0000 (23:06 -0500)
committerPeter Eisentraut <peter_e@gmx.net>
Sun, 18 Jan 2015 03:37:32 +0000 (22:37 -0500)
Previously, the xml value resulting from an xpath query would not have
namespace declarations if the namespace declarations were attached to
an ancestor element in the input xml value.  That means the output value
was not correct XML.  Fix that by running the result value through
xmlCopyNode(), which produces the correct namespace declarations.

Author: Ali Akbar <the.apaan@gmail.com>

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 46f8987fd767003cb0a87f0733fcbbe1d57d6afc..b2a9d50587ab18d8f63dbb320ac834ae74606fd5 100644 (file)
@@ -3286,19 +3286,34 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
        if (cur->type == XML_ELEMENT_NODE)
        {
                xmlBufferPtr buf;
+               xmlNodePtr      cur_copy;
 
                buf = xmlBufferCreate();
+
+               /*
+                * The result of xmlNodeDump() won't contain namespace definitions
+                * from parent nodes, but xmlCopyNode() duplicates a node along with
+                * its required namespace definitions.
+                */
+               cur_copy = xmlCopyNode(cur, 1);
+
+               if (cur_copy == NULL)
+                       xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+                                               "could not copy node");
+
                PG_TRY();
                {
-                       xmlNodeDump(buf, NULL, cur, 0, 1);
+                       xmlNodeDump(buf, NULL, cur_copy, 0, 1);
                        result = xmlBuffer_to_xmltype(buf);
                }
                PG_CATCH();
                {
+                       xmlFreeNode(cur_copy);
                        xmlBufferFree(buf);
                        PG_RE_THROW();
                }
                PG_END_TRY();
+               xmlFreeNode(cur_copy);
                xmlBufferFree(buf);
        }
        else
index 7db5f917bed1189cb3246b1c73c48e29a0d661db..1f165a6cd8edae7d75ba2c70563c4bdaa313e822 100644 (file)
@@ -496,6 +496,21 @@ SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><loc
  {1,2}
 (1 row)
 
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+                                                                     xpath                                                                      
+------------------------------------------------------------------------------------------------------------------------------------------------
+ {"<local:piece xmlns:local=\"http://127.0.0.1\" id=\"1\">number one</local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\" id=\"2\"/>"}
+(1 row)
+
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+                                        xpath                                         
+--------------------------------------------------------------------------------------
+ {"<local:piece xmlns:local=\"http://127.0.0.1\" xmlns=\"http://127.0.0.2\" id=\"1\">+
+   <internal>number one</internal>                                                   +
+   <internal2/>                                                                      +
+ </local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\" id=\"2\"/>"}
+(1 row)
+
 SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
           xpath          
 -------------------------
index d654056b08b2020ed4ff4b995cacd0a5eb5f986d..15f93e687d3b39ef8025d485cdf83c1a07c7e57c 100644 (file)
@@ -450,6 +450,18 @@ LINE 1: SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="ht...
                                         ^
 DETAIL:  This functionality requires the server to be built with libxml support.
 HINT:  You need to rebuild PostgreSQL using --with-libxml.
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ERROR:  unsupported XML feature
+LINE 1: SELECT xpath('//loc:piece', '<local:data xmlns:local="http:/...
+                                    ^
+DETAIL:  This functionality requires the server to be built with libxml support.
+HINT:  You need to rebuild PostgreSQL using --with-libxml.
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ERROR:  unsupported XML feature
+LINE 1: SELECT xpath('//loc:piece', '<local:data xmlns:local="http:/...
+                                    ^
+DETAIL:  This functionality requires the server to be built with libxml support.
+HINT:  You need to rebuild PostgreSQL using --with-libxml.
 SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
 ERROR:  unsupported XML feature
 LINE 1: SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'...
index 1e5026b04c8f6c74476c89f0af6b46d1ac3a1181..6eb7deded00d081e8e9f5eee120b45441e8ce858 100644 (file)
@@ -162,6 +162,8 @@ SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
 SELECT xpath('', '<!-- error -->');
 SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
 SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
 SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
 
 -- External entity references should not leak filesystem information.