Enable using xml:lang with normal interfaces.
Using the special language value '*' will return a dictionary of all such elements keyed by language. >>> msg = Message() >>> msg['body'] = 'Hi!' >>> msg['body|sv'] = 'Hej!' >>> print(msg) '<message xmlns="jabber:client"> <body>Hi!</body> <body xml:lang="sv">Hej!</body> </message>' >>> print(msg['body|*']) OrderedDict( ('', 'Hi!'), ('sv', 'Hej!')) Remaining items: - Stanza path matching does not support language specifiers for normal interfaces, only for plugins.
This commit is contained in:
parent
3d2d11f169
commit
f824950552
@ -108,7 +108,7 @@ def multifactory(stanza, plugin_attrib):
|
|||||||
|
|
||||||
def get_multi(self, lang=None):
|
def get_multi(self, lang=None):
|
||||||
parent = self.parent()
|
parent = self.parent()
|
||||||
if lang is None:
|
if not lang or lang == '*':
|
||||||
res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
|
res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
|
||||||
else:
|
else:
|
||||||
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent)
|
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent)
|
||||||
@ -116,19 +116,29 @@ def multifactory(stanza, plugin_attrib):
|
|||||||
|
|
||||||
def set_multi(self, val, lang=None):
|
def set_multi(self, val, lang=None):
|
||||||
parent = self.parent()
|
parent = self.parent()
|
||||||
del parent[self.plugin_attrib]
|
del_multi = getattr(self, 'del_%s' % plugin_attrib)
|
||||||
|
del_multi(lang)
|
||||||
for sub in val:
|
for sub in val:
|
||||||
parent.append(sub)
|
parent.append(sub)
|
||||||
|
|
||||||
def del_multi(self, lang=None):
|
def del_multi(self, lang=None):
|
||||||
parent = self.parent()
|
parent = self.parent()
|
||||||
if lang is None:
|
if not lang or lang == '*':
|
||||||
res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
|
res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
|
||||||
else:
|
else:
|
||||||
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent)
|
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent)
|
||||||
for stanza in list(res):
|
res = list(res)
|
||||||
parent.iterables.remove(stanza)
|
if not res:
|
||||||
parent.xml.remove(stanza.xml)
|
del parent.plugins[(plugin_attrib, None)]
|
||||||
|
parent.loaded_plugins.remove(plugin_attrib)
|
||||||
|
try:
|
||||||
|
parent.xml.remove(self.xml)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for stanza in list(res):
|
||||||
|
parent.iterables.remove(stanza)
|
||||||
|
parent.xml.remove(stanza.xml)
|
||||||
|
|
||||||
Multi.is_extension = True
|
Multi.is_extension = True
|
||||||
Multi.plugin_attrib = plugin_attrib
|
Multi.plugin_attrib = plugin_attrib
|
||||||
@ -477,7 +487,12 @@ class ElementBase(object):
|
|||||||
def _get_plugin(self, name, lang=None):
|
def _get_plugin(self, name, lang=None):
|
||||||
if lang is None:
|
if lang is None:
|
||||||
lang = self.get_lang()
|
lang = self.get_lang()
|
||||||
|
|
||||||
|
if name not in self.plugin_attrib_map:
|
||||||
|
return None
|
||||||
|
|
||||||
plugin_class = self.plugin_attrib_map[name]
|
plugin_class = self.plugin_attrib_map[name]
|
||||||
|
|
||||||
if plugin_class.is_extension:
|
if plugin_class.is_extension:
|
||||||
if (name, None) in self.plugins:
|
if (name, None) in self.plugins:
|
||||||
return self.plugins[(name, None)]
|
return self.plugins[(name, None)]
|
||||||
@ -549,6 +564,8 @@ class ElementBase(object):
|
|||||||
values = {}
|
values = {}
|
||||||
for interface in self.interfaces:
|
for interface in self.interfaces:
|
||||||
values[interface] = self[interface]
|
values[interface] = self[interface]
|
||||||
|
if interface in self.lang_interfaces:
|
||||||
|
values['%s|*' % interface] = self['%s|*' % interface]
|
||||||
for plugin, stanza in self.plugins.items():
|
for plugin, stanza in self.plugins.items():
|
||||||
lang = stanza['lang']
|
lang = stanza['lang']
|
||||||
if lang:
|
if lang:
|
||||||
@ -601,11 +618,12 @@ class ElementBase(object):
|
|||||||
self.iterables.append(sub)
|
self.iterables.append(sub)
|
||||||
break
|
break
|
||||||
elif interface in self.interfaces:
|
elif interface in self.interfaces:
|
||||||
self[interface] = value
|
self[full_interface] = value
|
||||||
elif interface in self.plugin_attrib_map:
|
elif interface in self.plugin_attrib_map:
|
||||||
if interface not in iterable_interfaces:
|
if interface not in iterable_interfaces:
|
||||||
plugin = self._get_plugin(interface, lang)
|
plugin = self._get_plugin(interface, lang)
|
||||||
plugin.values = value
|
if plugin:
|
||||||
|
plugin.values = value
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __getitem__(self, attrib):
|
def __getitem__(self, attrib):
|
||||||
@ -656,9 +674,10 @@ class ElementBase(object):
|
|||||||
name = self.plugin_overrides.get(get_method, None)
|
name = self.plugin_overrides.get(get_method, None)
|
||||||
if name:
|
if name:
|
||||||
plugin = self._get_plugin(name, lang)
|
plugin = self._get_plugin(name, lang)
|
||||||
handler = getattr(plugin, get_method, None)
|
if plugin:
|
||||||
if handler:
|
handler = getattr(plugin, get_method, None)
|
||||||
return handler(**kwargs)
|
if handler:
|
||||||
|
return handler(**kwargs)
|
||||||
|
|
||||||
if hasattr(self, get_method):
|
if hasattr(self, get_method):
|
||||||
return getattr(self, get_method)(**kwargs)
|
return getattr(self, get_method)(**kwargs)
|
||||||
@ -666,7 +685,7 @@ class ElementBase(object):
|
|||||||
return getattr(self, get_method2)(**kwargs)
|
return getattr(self, get_method2)(**kwargs)
|
||||||
else:
|
else:
|
||||||
if attrib in self.sub_interfaces:
|
if attrib in self.sub_interfaces:
|
||||||
return self._get_sub_text(attrib)
|
return self._get_sub_text(attrib, lang=lang)
|
||||||
elif attrib in self.bool_interfaces:
|
elif attrib in self.bool_interfaces:
|
||||||
elem = self.xml.find('{%s}%s' % (self.namespace, attrib))
|
elem = self.xml.find('{%s}%s' % (self.namespace, attrib))
|
||||||
return elem is not None
|
return elem is not None
|
||||||
@ -674,7 +693,7 @@ class ElementBase(object):
|
|||||||
return self._get_attr(attrib)
|
return self._get_attr(attrib)
|
||||||
elif attrib in self.plugin_attrib_map:
|
elif attrib in self.plugin_attrib_map:
|
||||||
plugin = self._get_plugin(attrib, lang)
|
plugin = self._get_plugin(attrib, lang)
|
||||||
if plugin.is_extension:
|
if plugin and plugin.is_extension:
|
||||||
return plugin[full_attrib]
|
return plugin[full_attrib]
|
||||||
return plugin
|
return plugin
|
||||||
else:
|
else:
|
||||||
@ -730,9 +749,10 @@ class ElementBase(object):
|
|||||||
name = self.plugin_overrides.get(set_method, None)
|
name = self.plugin_overrides.get(set_method, None)
|
||||||
if name:
|
if name:
|
||||||
plugin = self._get_plugin(name, lang)
|
plugin = self._get_plugin(name, lang)
|
||||||
handler = getattr(plugin, set_method, None)
|
if plugin:
|
||||||
if handler:
|
handler = getattr(plugin, set_method, None)
|
||||||
return handler(value, **kwargs)
|
if handler:
|
||||||
|
return handler(value, **kwargs)
|
||||||
|
|
||||||
if hasattr(self, set_method):
|
if hasattr(self, set_method):
|
||||||
getattr(self, set_method)(value, **kwargs)
|
getattr(self, set_method)(value, **kwargs)
|
||||||
@ -740,19 +760,22 @@ class ElementBase(object):
|
|||||||
getattr(self, set_method2)(value, **kwargs)
|
getattr(self, set_method2)(value, **kwargs)
|
||||||
else:
|
else:
|
||||||
if attrib in self.sub_interfaces:
|
if attrib in self.sub_interfaces:
|
||||||
return self._set_sub_text(attrib, text=value)
|
if lang == '*':
|
||||||
|
return self._set_all_sub_text(attrib, value, lang='*')
|
||||||
|
return self._set_sub_text(attrib, text=value, lang=lang)
|
||||||
elif attrib in self.bool_interfaces:
|
elif attrib in self.bool_interfaces:
|
||||||
if value:
|
if value:
|
||||||
return self._set_sub_text(attrib, '', keep=True)
|
return self._set_sub_text(attrib, '', keep=True, lang=lang)
|
||||||
else:
|
else:
|
||||||
return self._set_sub_text(attrib, '', keep=False)
|
return self._set_sub_text(attrib, '', keep=False, lang=lang)
|
||||||
else:
|
else:
|
||||||
self._set_attr(attrib, value)
|
self._set_attr(attrib, value)
|
||||||
else:
|
else:
|
||||||
self.__delitem__(attrib)
|
self.__delitem__(attrib)
|
||||||
elif attrib in self.plugin_attrib_map:
|
elif attrib in self.plugin_attrib_map:
|
||||||
plugin = self._get_plugin(attrib, lang)
|
plugin = self._get_plugin(attrib, lang)
|
||||||
plugin[full_attrib] = value
|
if plugin:
|
||||||
|
plugin[full_attrib] = value
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __delitem__(self, attrib):
|
def __delitem__(self, attrib):
|
||||||
@ -804,9 +827,10 @@ class ElementBase(object):
|
|||||||
name = self.plugin_overrides.get(del_method, None)
|
name = self.plugin_overrides.get(del_method, None)
|
||||||
if name:
|
if name:
|
||||||
plugin = self._get_plugin(attrib, lang)
|
plugin = self._get_plugin(attrib, lang)
|
||||||
handler = getattr(plugin, del_method, None)
|
if plugin:
|
||||||
if handler:
|
handler = getattr(plugin, del_method, None)
|
||||||
return handler(**kwargs)
|
if handler:
|
||||||
|
return handler(**kwargs)
|
||||||
|
|
||||||
if hasattr(self, del_method):
|
if hasattr(self, del_method):
|
||||||
getattr(self, del_method)(**kwargs)
|
getattr(self, del_method)(**kwargs)
|
||||||
@ -814,13 +838,15 @@ class ElementBase(object):
|
|||||||
getattr(self, del_method2)(**kwargs)
|
getattr(self, del_method2)(**kwargs)
|
||||||
else:
|
else:
|
||||||
if attrib in self.sub_interfaces:
|
if attrib in self.sub_interfaces:
|
||||||
return self._del_sub(attrib)
|
return self._del_sub(attrib, lang=lang)
|
||||||
elif attrib in self.bool_interfaces:
|
elif attrib in self.bool_interfaces:
|
||||||
return self._del_sub(attrib)
|
return self._del_sub(attrib, lang=lang)
|
||||||
else:
|
else:
|
||||||
self._del_attr(attrib)
|
self._del_attr(attrib)
|
||||||
elif attrib in self.plugin_attrib_map:
|
elif attrib in self.plugin_attrib_map:
|
||||||
plugin = self._get_plugin(attrib, lang)
|
plugin = self._get_plugin(attrib, lang)
|
||||||
|
if not plugin:
|
||||||
|
return self
|
||||||
if plugin.is_extension:
|
if plugin.is_extension:
|
||||||
del plugin[full_attrib]
|
del plugin[full_attrib]
|
||||||
del self.plugins[(attrib, None)]
|
del self.plugins[(attrib, None)]
|
||||||
@ -869,7 +895,7 @@ class ElementBase(object):
|
|||||||
"""
|
"""
|
||||||
return self.xml.attrib.get(name, default)
|
return self.xml.attrib.get(name, default)
|
||||||
|
|
||||||
def _get_sub_text(self, name, default=''):
|
def _get_sub_text(self, name, default='', lang=None):
|
||||||
"""Return the text contents of a sub element.
|
"""Return the text contents of a sub element.
|
||||||
|
|
||||||
In case the element does not exist, or it has no textual content,
|
In case the element does not exist, or it has no textual content,
|
||||||
@ -881,13 +907,37 @@ class ElementBase(object):
|
|||||||
not exists. An empty string is returned otherwise.
|
not exists. An empty string is returned otherwise.
|
||||||
"""
|
"""
|
||||||
name = self._fix_ns(name)
|
name = self._fix_ns(name)
|
||||||
stanza = self.xml.find(name)
|
if lang == '*':
|
||||||
if stanza is None or stanza.text is None:
|
return self._get_all_sub_text(name, default, None)
|
||||||
return default
|
|
||||||
else:
|
|
||||||
return stanza.text
|
|
||||||
|
|
||||||
def _set_sub_text(self, name, text=None, keep=False):
|
default_lang = self.get_lang()
|
||||||
|
if not lang:
|
||||||
|
lang = default_lang
|
||||||
|
|
||||||
|
stanzas = self.xml.findall(name)
|
||||||
|
if not stanzas:
|
||||||
|
return default
|
||||||
|
for stanza in stanzas:
|
||||||
|
if stanza.attrib.get('{%s}lang' % XML_NS, default_lang) == lang:
|
||||||
|
if stanza.text is None:
|
||||||
|
return default
|
||||||
|
return stanza.text
|
||||||
|
return default
|
||||||
|
|
||||||
|
def _get_all_sub_text(self, name, default='', lang=None):
|
||||||
|
name = self._fix_ns(name)
|
||||||
|
|
||||||
|
default_lang = self.get_lang()
|
||||||
|
results = OrderedDict()
|
||||||
|
stanzas = self.xml.findall(name)
|
||||||
|
if stanzas:
|
||||||
|
for stanza in stanzas:
|
||||||
|
stanza_lang = stanza.attrib.get('{%s}lang' % XML_NS, default_lang)
|
||||||
|
if not lang or lang == '*' or stanza_lang == lang:
|
||||||
|
results[stanza_lang] = stanza.text
|
||||||
|
return results
|
||||||
|
|
||||||
|
def _set_sub_text(self, name, text=None, keep=False, lang=None):
|
||||||
"""Set the text contents of a sub element.
|
"""Set the text contents of a sub element.
|
||||||
|
|
||||||
In case the element does not exist, a element will be created,
|
In case the element does not exist, a element will be created,
|
||||||
@ -905,9 +955,14 @@ class ElementBase(object):
|
|||||||
"""
|
"""
|
||||||
path = self._fix_ns(name, split=True)
|
path = self._fix_ns(name, split=True)
|
||||||
element = self.xml.find(name)
|
element = self.xml.find(name)
|
||||||
|
parent = self.xml
|
||||||
|
|
||||||
|
default_lang = self.get_lang()
|
||||||
|
if lang is None:
|
||||||
|
lang = default_lang
|
||||||
|
|
||||||
if not text and not keep:
|
if not text and not keep:
|
||||||
return self._del_sub(name)
|
return self._del_sub(name, lang=lang)
|
||||||
|
|
||||||
if element is None:
|
if element is None:
|
||||||
# We need to add the element. If the provided name was
|
# We need to add the element. If the provided name was
|
||||||
@ -921,14 +976,29 @@ class ElementBase(object):
|
|||||||
element = self.xml.find("/".join(walked))
|
element = self.xml.find("/".join(walked))
|
||||||
if element is None:
|
if element is None:
|
||||||
element = ET.Element(ename)
|
element = ET.Element(ename)
|
||||||
|
if lang:
|
||||||
|
element.attrib['{%s}lang' % XML_NS] = lang
|
||||||
last_xml.append(element)
|
last_xml.append(element)
|
||||||
|
parent = last_xml
|
||||||
last_xml = element
|
last_xml = element
|
||||||
element = last_xml
|
element = last_xml
|
||||||
|
|
||||||
|
if element.attrib.get('{%s}lang' % XML_NS, default_lang) != lang:
|
||||||
|
element = ET.Element(ename)
|
||||||
|
if lang:
|
||||||
|
element.attrib['{%s}lang' % XML_NS] = lang
|
||||||
|
parent.append(element)
|
||||||
|
|
||||||
element.text = text
|
element.text = text
|
||||||
return element
|
return element
|
||||||
|
|
||||||
def _del_sub(self, name, all=False):
|
def _set_all_sub_text(self, name, values, keep=False, lang=None):
|
||||||
|
self._del_sub(name, lang)
|
||||||
|
for value_lang, value in values.items():
|
||||||
|
if not lang or lang == '*' or value_lang == lang:
|
||||||
|
self._set_sub_text(name, text=value, keep=keep, lang=value_lang)
|
||||||
|
|
||||||
|
def _del_sub(self, name, all=False, lang=None):
|
||||||
"""Remove sub elements that match the given name or XPath.
|
"""Remove sub elements that match the given name or XPath.
|
||||||
|
|
||||||
If the element is in a path, then any parent elements that become
|
If the element is in a path, then any parent elements that become
|
||||||
@ -942,6 +1012,10 @@ class ElementBase(object):
|
|||||||
path = self._fix_ns(name, split=True)
|
path = self._fix_ns(name, split=True)
|
||||||
original_target = path[-1]
|
original_target = path[-1]
|
||||||
|
|
||||||
|
default_lang = self.get_lang()
|
||||||
|
if not lang:
|
||||||
|
lang = default_lang
|
||||||
|
|
||||||
for level, _ in enumerate(path):
|
for level, _ in enumerate(path):
|
||||||
# Generate the paths to the target elements and their parent.
|
# Generate the paths to the target elements and their parent.
|
||||||
element_path = "/".join(path[:len(path) - level])
|
element_path = "/".join(path[:len(path) - level])
|
||||||
@ -958,7 +1032,8 @@ class ElementBase(object):
|
|||||||
not element.getchildren():
|
not element.getchildren():
|
||||||
# Only delete the originally requested elements, and
|
# Only delete the originally requested elements, and
|
||||||
# any parent elements that have become empty.
|
# any parent elements that have become empty.
|
||||||
parent.remove(element)
|
if lang == '*' or element.attrib.get('{%s}lang' % XML_NS, default_lang) == lang:
|
||||||
|
parent.remove(element)
|
||||||
if not all:
|
if not all:
|
||||||
# If we don't want to delete elements up the tree, stop
|
# If we don't want to delete elements up the tree, stop
|
||||||
# after deleting the first level of elements.
|
# after deleting the first level of elements.
|
||||||
@ -1022,7 +1097,8 @@ class ElementBase(object):
|
|||||||
next_tag = xpath[1].split('@')[0].split('}')[-1]
|
next_tag = xpath[1].split('@')[0].split('}')[-1]
|
||||||
langs = [name[1] for name in self.plugins if name[0] == next_tag]
|
langs = [name[1] for name in self.plugins if name[0] == next_tag]
|
||||||
for lang in langs:
|
for lang in langs:
|
||||||
if self._get_plugin(next_tag, lang).match(xpath[1:]):
|
plugin = self._get_plugin(next_tag, lang)
|
||||||
|
if plugin and plugin.match(xpath[1:]):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user