Skip to content

Commit

Permalink
Rely on XLSForm "name" setting to detect root tag with disclaimer
Browse files Browse the repository at this point in the history
  • Loading branch information
noliveleger committed Nov 14, 2024
1 parent 77bef4e commit 214b1d0
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
12 changes: 12 additions & 0 deletions kobo/apps/openrosa/apps/logger/models/xform.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,18 @@ def url(self):
}
)

@property
def xforms_root_node_name(self):
"""
Retrieves the name of the XML tag representing the root node of the "survey"
in the XForm XML structure.
It should always be present in `self.json`.
"""

form_json = json.loads(self.json)
return form_json['name']

@property
def xml_with_disclaimer(self):
return XMLFormWithDisclaimer(self).get_object().xml
Expand Down
15 changes: 15 additions & 0 deletions kpi/models/asset_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,18 @@ def generate_xml_from_source(self,
'warnings': warnings,
})
return xml, details

@property
def xforms_root_node_name(self):
"""
Retrieves the name of the XML tag representing the root node of the "survey"
in the XForm XML structure.
This method uses the `name` setting from the XLSForm to determine the tag name.
If no name is provided, it falls back to using the asset UID.
"""

try:
return self.asset.content['settings']['name']
except KeyError:
return self.asset.uid
18 changes: 11 additions & 7 deletions kpi/utils/xml.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# coding: utf-8
from __future__ import annotations

import re
Expand Down Expand Up @@ -373,6 +372,10 @@ class XMLFormWithDisclaimer:
def __init__(self, obj: Union['kpi.AssetSnapshot', 'logger.XForm']):
self._object = obj
self._unique_id = obj.asset.uid

# Avoid initializing `_root_tag_name` immediately to prevent extra
# database queries. It will be set only when it is actually needed.
self._root_tag_name = None
self._add_disclaimer()

def get_object(self):
Expand All @@ -391,6 +394,7 @@ def _add_disclaimer(self):
translated, disclaimers_dict, default_language_code = value

self._root_node = minidom.parseString(self._object.xml)
self._root_tag_name = self._object.xforms_root_node_name

if translated:
self._add_translation_nodes(disclaimers_dict, default_language_code)
Expand All @@ -413,17 +417,17 @@ def _add_instance_and_bind_nodes(self):
# Inject <bind nodeset /> inside <model odk:xforms-version="1.0.0">
bind_node = self._root_node.createElement('bind')
bind_node.setAttribute(
'nodeset', f'/{self._unique_id}/_{self._unique_id}__disclaimer'
'nodeset', f'/{self._root_tag_name}/_{self._unique_id}__disclaimer'
)
bind_node.setAttribute('readonly', 'true()')
bind_node.setAttribute('required', 'false()')
bind_node.setAttribute('type', 'string')
bind_node.setAttribute('relevant', 'false()')
model_node.appendChild(bind_node)

# Inject note node inside <{self._unique_id}>
# Inject note node inside <{self._root_tag_name}>
instance_node = model_node.getElementsByTagName('instance')[0]
instance_node = instance_node.getElementsByTagName(self._unique_id)[0]
instance_node = instance_node.getElementsByTagName(self._root_tag_name)[0]
instance_node.appendChild(
self._root_node.createElement(f'_{self._unique_id}__disclaimer')
)
Expand All @@ -442,11 +446,11 @@ def _add_disclaimer_input(
disclaimer_input_label = self._root_node.createElement('label')
disclaimer_input.setAttribute('appearance', 'kobo-disclaimer')
disclaimer_input.setAttribute(
'ref', f'/{self._unique_id}/_{self._unique_id}__disclaimer'
'ref', f'/{self._root_tag_name}/_{self._unique_id}__disclaimer'
)

if translated:
itext = f'/{self._unique_id}/_{self._unique_id}__disclaimer:label'
itext = f'/{self._root_tag_name}/_{self._unique_id}__disclaimer:label'
disclaimer_input_label.setAttribute(
'ref',
f"jr:itext('{itext}')",
Expand Down Expand Up @@ -474,7 +478,7 @@ def _add_translation_nodes(
disclaimer_translation = self._root_node.createElement('text')
disclaimer_translation.setAttribute(
'id',
f'/{self._unique_id}/_{self._unique_id}__disclaimer:label',
f'/{self._root_tag_name}/_{self._unique_id}__disclaimer:label',
)
value = self._root_node.createElement('value')
language = n.getAttribute('lang').lower().strip()
Expand Down

0 comments on commit 214b1d0

Please sign in to comment.