]> 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:07 +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 bfaf0a0be705c59be3c7d69e3f9cfa4144a8cc16..bcf058d9c3cb9a02a5d9ef3adf54720744644857 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 b6ec98502b7ab77c302ca57f5d8dd8346f49fdbd..a236afd04b35a3e6243107c43a3d3d47215d7d04 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 38a98ad32169adc5d3647081386fe06b8022166a..abff7a5f635092fe47b48e3d60a4ca5e98172e23 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 366e2798d409f18861779c3d52dda9ad59d8bdbd..c7ceeb168e854a92d57393a8bca3cc67f28ee0e6 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>');
 
 -- Test xmlexists and xpath_exists