summaryrefslogtreecommitdiffstats
path: root/util/local_database/xpathlite.py
diff options
context:
space:
mode:
Diffstat (limited to 'util/local_database/xpathlite.py')
-rw-r--r--util/local_database/xpathlite.py152
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