diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2015-01-06 23:06:13 -0500 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2015-01-17 22:37:07 -0500 |
commit | c975fa4713c2325623d7bbfd81806327234281ac (patch) | |
tree | 9f37de4a6e62cc04bd98ebc725a323bdb1d59a1b /src | |
parent | 1c49561762933b6d0502bd852cf4acbcbfedd66b (diff) |
Fix namespace handling in xpath function
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>
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/utils/adt/xml.c | 17 | ||||
-rw-r--r-- | src/test/regress/expected/xml.out | 15 | ||||
-rw-r--r-- | src/test/regress/expected/xml_1.out | 12 | ||||
-rw-r--r-- | src/test/regress/sql/xml.sql | 2 |
4 files changed, 45 insertions, 1 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index bfaf0a0be70..bcf058d9c3c 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -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 diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index b6ec98502b7..a236afd04b3 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -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 ------------------------- diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index 38a98ad3216..abff7a5f635 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -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>'... diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 366e2798d40..c7ceeb168e8 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -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 |