diff options
| author | Simon Lejeune <sle@openerp.com> | 2016-12-28 13:54:29 +0100 |
|---|---|---|
| committer | Simon Lejeune <sle@openerp.com> | 2017-01-02 16:07:06 +0100 |
| commit | 0d3af7ce1cf843cf00fbd719f2007cd0c6615404 (patch) | |
| tree | 2ed346ca000804338ab37ffd02d22c52dc096fe9 | |
| parent | 2d3c928d4752bda69561a69ce92d14336b337732 (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.py | 2 | ||||
| -rw-r--r-- | odoo/addons/base/tests/test_qweb.py | 46 |
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): |
