diff options
Diffstat (limited to 'util/local_database/xpathlite.py')
-rw-r--r-- | util/local_database/xpathlite.py | 152 |
1 files changed, 105 insertions, 47 deletions
diff --git a/util/local_database/xpathlite.py b/util/local_database/xpathlite.py index 7b5da5d..7d569f3 100644 --- a/util/local_database/xpathlite.py +++ b/util/local_database/xpathlite.py @@ -52,29 +52,42 @@ class DraftResolution: provisional = 'provisional' contributed = 'contributed' approved = 'approved' + _values = { unconfirmed : 1, provisional : 2, contributed : 3, approved : 4 } + def __init__(self, resolution): + self.resolution = resolution + def toInt(self): + return DraftResolution._values[self.resolution] +class Error: + def __init__(self, msg): + self.msg = msg + def __str__(self): + return self.msg -def findChild(parent, tag_name, arg_value, draft=None): +def findChild(parent, tag_name, arg_name=None, arg_value=None, draft=None): for node in parent.childNodes: if node.nodeType != node.ELEMENT_NODE: continue if node.nodeName != tag_name: continue if arg_value: - if not node.attributes.has_key('type'): + if not node.attributes.has_key(arg_name): continue - if node.attributes['type'].nodeValue != arg_value: + if node.attributes[arg_name].nodeValue != arg_value: continue if draft: - if node.attributes.has_key('draft'): - if node.attributes['draft'].nodeValue != draft: - continue - elif draft != DraftResolution.approved: + if not node.attributes.has_key('draft'): + # if draft is not specified then it's approved + return node + value = node.attributes['draft'].nodeValue + value = DraftResolution(value).toInt() + exemplar = DraftResolution(draft).toInt() + if exemplar > value: continue return node return False -def _findEntry(file, path, draft=None): +def _findEntryInFile(file, path, draft=None, attribute=None): doc = False if doc_cache.has_key(file): doc = doc_cache[file] @@ -85,65 +98,110 @@ def _findEntry(file, path, draft=None): elt = doc.documentElement tag_spec_list = path.split("/") last_entry = None - if draft is not None: - last_entry = tag_spec_list[-1] - tag_spec_list = tag_spec_list[:-1] - for tag_spec in tag_spec_list: + for i in range(len(tag_spec_list)): + tag_spec = tag_spec_list[i] tag_name = tag_spec + arg_name = 'type' arg_value = '' left_bracket = tag_spec.find('[') if left_bracket != -1: tag_name = tag_spec[:left_bracket] - arg_value = tag_spec[left_bracket+1:-1] - elt = findChild(elt, tag_name, arg_value) + arg_value = tag_spec[left_bracket+1:-1].split("=") + if len(arg_value) == 2: + arg_name = arg_value[0] + arg_value = arg_value[1] + else: + arg_value = arg_value[0] + alias = findChild(elt, 'alias') + if alias and alias.attributes['source'].nodeValue == 'locale': + path = alias.attributes['path'].nodeValue + aliaspath = tag_spec_list[:i] + path.split("/") + def resolve(x, y): + if y == '..': + return x[:-1] + return x + [y] + # resolve all dot-dot parts of the path + aliaspath = reduce(resolve, aliaspath, []) + # remove attribute specification that our xpathlite doesnt support + aliaspath = map(lambda x: x.replace("@type=", "").replace("'", ""), aliaspath) + # append the remaining path + aliaspath = aliaspath + tag_spec_list[i:] + aliaspath = "/".join(aliaspath) + # "locale" aliases are special - we need to start lookup from scratch + return (None, aliaspath) + elt = findChild(elt, tag_name, arg_name, arg_value, draft) if not elt: - return "" - if last_entry is not None: - elt = findChild(elt, last_entry, '', draft) - if not elt: - return "" - return elt.firstChild.nodeValue + return ("", None) + if attribute is not None: + if elt.attributes.has_key(attribute): + return (elt.attributes[attribute].nodeValue, None) + return (None, None) + return (elt.firstChild.nodeValue, None) def findAlias(file): + if not doc_cache.has_key(file): + return False doc = doc_cache[file] - alias_elt = findChild(doc.documentElement, "alias", "") + alias_elt = findChild(doc.documentElement, "alias") if not alias_elt: return False if not alias_elt.attributes.has_key('source'): return False return alias_elt.attributes['source'].nodeValue -def findEntry(base, path, draft=None): - file = base + ".xml" +def _findEntry(base, path, draft=None, attribute=None): + file = base + if base.endswith(".xml"): + filename = base + base = base[:-4] + else: + file = base + ".xml" + (dirname, filename) = os.path.split(base) + items = filename.split("_") + # split locale name into items and iterate through them from back to front + # example: az_Latn_AZ => [az_Latn_AZ, az_Latn, az] + items = reversed(map(lambda x: "_".join(items[:x+1]), range(len(items)))) + for item in items: + file = dirname + "/" + item + ".xml" + if os.path.isfile(file): + alias = findAlias(file) + if alias: + # if alias is found we should follow it and stop processing current file + # see http://www.unicode.org/reports/tr35/#Common_Elements + aliasfile = os.path.dirname(file) + "/" + alias + ".xml" + if not os.path.isfile(aliasfile): + raise Error("findEntry: fatal error: found an alias '%s' to '%s', but the alias file couldnt be found" % (filename, alias)) + # found an alias, recurse into parsing it + result = _findEntry(aliasfile, path, draft, attribute) + return result + (result, aliaspath) = _findEntryInFile(file, path, draft, attribute) + if aliaspath: + # start lookup again because of the alias source="locale" + return _findEntry(base, aliaspath, draft, attribute) + if result: + return result + return None - if os.path.isfile(file): - result = _findEntry(file, path, draft) +def findEntry(base, path, draft=None, attribute=None): + file = base + if base.endswith(".xml"): + file = base + base = base[:-4] + else: + file = base + ".xml" + (dirname, filename) = os.path.split(base) + + result = None + while path: + result = _findEntry(base, path, draft, attribute) if result: return result - - alias = findAlias(file) - if alias: - file = os.path.dirname(base) + "/" + alias + ".xml" - if os.path.isfile(file): - result = _findEntry(file, path, draft) - if result: - return result - - file = base[:-3] + ".xml" - if os.path.isfile(file): - result = _findEntry(file, path, draft) + (result, aliaspath) = _findEntryInFile(dirname + "/root.xml", path, draft, attribute) if result: return result - alias = findAlias(file) - if alias: - file = os.path.dirname(base) + "/" + alias + ".xml" - if os.path.isfile(file): - result = _findEntry(file, path, draft) - if result: - return result + if not aliaspath: + raise Error("findEntry: fatal error: %s: did not found key %s" % (filename, path)) + path = aliaspath - if not draft: - file = os.path.dirname(base) + "/root.xml" - result = _findEntry(file, path, draft) return result |