[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
This commit is contained in:
Simon Lejeune
2017-01-02 16:07:06 +01:00
parent 2d3c928d47
commit 0d3af7ce1c
2 changed files with 47 additions and 1 deletions
+1 -1
View File
@@ -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
+46
View File
@@ -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):