summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Lejeune <sle@openerp.com>2016-12-28 13:54:29 +0100
committerSimon Lejeune <sle@openerp.com>2017-01-02 16:07:06 +0100
commit0d3af7ce1cf843cf00fbd719f2007cd0c6615404 (patch)
tree2ed346ca000804338ab37ffd02d22c52dc096fe9
parent2d3c928d4752bda69561a69ce92d14336b337732 (diff)
[FIX] ir.ui.view: `locate_node` of a ns prefixed element
According to [1], "If your XPath expression uses namespace prefixes, you must define them in a prefix mapping.". It makes sense because an xpath to a prefixed tag is not able to uniquely locate the tag in the parent view (it is possible to redefine the ns definition of a prefix, so you could have multiple elements matching). We chose to define the nsmap to locate the element in the parent view by using the lxml internal form to qualify a node ({ns def}tagname). This form is not compatible with etree.xpath but is with etree.ETXPath. Fortunately, etree.ETXPath is compatible with the classic xpath expressions so we'll use this one by default in `locate_node`. A test has been introduced to showcase the problem. http://lxml.de/xpathxslt.html#namespaces-and-prefixes: Namespaces and prefixes
-rw-r--r--odoo/addons/base/ir/ir_ui_view.py2
-rw-r--r--odoo/addons/base/tests/test_qweb.py46
2 files changed, 47 insertions, 1 deletions
diff --git a/odoo/addons/base/ir/ir_ui_view.py b/odoo/addons/base/ir/ir_ui_view.py
index daa8d72f26f..7f9d0340f02 100644
--- a/odoo/addons/base/ir/ir_ui_view.py
+++ b/odoo/addons/base/ir/ir_ui_view.py
@@ -466,7 +466,7 @@ actual arch.
:return: a node in the source matching the spec
"""
if spec.tag == 'xpath':
- nodes = arch.xpath(spec.get('expr'))
+ nodes = etree.ETXPath(spec.get('expr'))(arch)
return nodes[0] if nodes else None
elif spec.tag == 'field':
# Only compare the field name: a field can be only once in a given view
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index c4b279c2f43..284cc104840 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -373,6 +373,52 @@ class TestQWebNS(TransactionCase):
self.assertEquals(len(cac_lines), 2)
self.assertEquals(result.count('Appel'), 2)
+ def test_render_static_xml_with_extension(self):
+ """ Test the extension of a view by an xpath expression on a ns prefixed element.
+ """
+ # primary view
+ view1 = self.env['ir.ui.view'].create({
+ 'name': "dummy",
+ 'type': 'qweb',
+ 'arch': """
+ <t t-name="base.dummy">
+ <root>
+ <h:table xmlns:h="http://www.example.org/table">
+ <h:tr>
+ <h:td xmlns:h="http://www.w3.org/TD/html4/">Apples</h:td>
+ <h:td>Bananas</h:td>
+ </h:tr>
+ </h:table>
+ </root>
+ </t>
+ """
+ })
+ # extension patching the primary view
+ view2 = self.env['ir.ui.view'].create({
+ 'name': "dummy_ext",
+ 'type': 'qweb',
+ 'inherit_id': view1.id,
+ 'arch': """
+ <xpath expr="//{http://www.example.org/table}table/{http://www.example.org/table}tr">
+ <h:td xmlns:h="http://www.example.org/table">Oranges</h:td>
+ </xpath>
+ """
+ })
+
+ expected_result = """
+ <root>
+ <h:table xmlns:h="http://www.example.org/table">
+ <h:tr>
+ <h:td xmlns:h="http://www.w3.org/TD/html4/">Apples</h:td>
+ <h:td>Bananas</h:td>
+ <h:td>Oranges</h:td>
+ </h:tr>
+ </h:table>
+ </root>
+ """
+
+ self.assertEquals(dedent_and_strip(view1.with_context(check_view_ids=[view1.id, view2.id]).render()), dedent_and_strip(expected_result))
+
from copy import deepcopy
class FileSystemLoader(object):