diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py
index b337f6a509b..c69f3f71bb3 100644
--- a/odoo/addons/base/models/ir_ui_view.py
+++ b/odoo/addons/base/models/ir_ui_view.py
@@ -1927,7 +1927,12 @@ actual arch.
if not attrs.intersection(descendant.attrib):
continue
self._pop_view_branding(descendant)
- # TODO: find a better name and check if we have a string to boolean helper
+
+ # Remove the processing instructions indicating where nodes were
+ # removed (see apply_inheritance_specs)
+ for descendant in e.iterdescendants(tag=etree.ProcessingInstruction):
+ if descendant.target == 'apply-inheritance-specs-node-removal':
+ descendant.getparent().remove(descendant)
return
node_path = e.get('data-oe-xpath')
diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py
index c1579f15dd5..71fbb699e13 100644
--- a/odoo/addons/base/tests/test_views.py
+++ b/odoo/addons/base/tests/test_views.py
@@ -950,6 +950,73 @@ class TestTemplating(ViewCase):
initial.get('data-oe-xpath'),
"The node's xpath position should be correct")
+ def test_branding_inherit_remove_node_processing_instruction(self):
+ view1 = self.View.create({
+ 'name': "Base view",
+ 'type': 'qweb',
+ 'arch': """
+
+
+
+
+
+
+
+
+ """
+ })
+ self.View.create({
+ 'name': "Extension",
+ 'type': 'qweb',
+ 'inherit_id': view1.id,
+ 'arch': """
+
+
+
+
+ """
+ })
+
+ arch_string = view1.with_context(inherit_branding=True).get_combined_arch()
+ arch = etree.fromstring(arch_string)
+
+ head = arch.xpath('//head')[0]
+ head_child = head[0]
+ self.assertEqual(
+ head_child.target,
+ 'apply-inheritance-specs-node-removal',
+ "A node was removed at the start of the , a processing instruction should exist as first child node")
+ self.assertEqual(
+ head_child.text,
+ 'hello',
+ "The processing instruction should mention the tag of the node that was removed")
+
+ body = arch.xpath('//body')[0]
+ body_child = body[0]
+ self.assertEqual(
+ body_child.target,
+ 'apply-inheritance-specs-node-removal',
+ "A node was removed at the start of the , a processing instruction should exist as first child node")
+ self.assertEqual(
+ body_child.text,
+ 'world',
+ "The processing instruction should mention the tag of the node that was removed")
+
+ self.View.distribute_branding(arch)
+
+ # Test that both head and body have their processing instruction
+ # 'apply-inheritance-specs-node-removal' removed after branding
+ # distribution. Note: test head and body separately as the code in
+ # charge of the removal is different in each case.
+ self.assertEqual(
+ len(head),
+ 0,
+ "The processing instruction of the should have been removed")
+ self.assertEqual(
+ len(body),
+ 0,
+ "The processing instruction of the should have been removed")
+
def test_branding_inherit_top_t_field(self):
view1 = self.View.create({
'name': "Base view",