util/local_database/xpathlite.py
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
    50     # See http://www.unicode.org/cldr/process.html for description
    50     # See http://www.unicode.org/cldr/process.html for description
    51     unconfirmed = 'unconfirmed'
    51     unconfirmed = 'unconfirmed'
    52     provisional = 'provisional'
    52     provisional = 'provisional'
    53     contributed = 'contributed'
    53     contributed = 'contributed'
    54     approved = 'approved'
    54     approved = 'approved'
    55 
    55     _values = { unconfirmed : 1, provisional : 2, contributed : 3, approved : 4 }
    56 
    56     def __init__(self, resolution):
    57 def findChild(parent, tag_name, arg_value, draft=None):
    57         self.resolution = resolution
       
    58     def toInt(self):
       
    59         return DraftResolution._values[self.resolution]
       
    60 
       
    61 class Error:
       
    62     def __init__(self, msg):
       
    63         self.msg = msg
       
    64     def __str__(self):
       
    65         return self.msg
       
    66 
       
    67 def findChild(parent, tag_name, arg_name=None, arg_value=None, draft=None):
    58     for node in parent.childNodes:
    68     for node in parent.childNodes:
    59         if node.nodeType != node.ELEMENT_NODE:
    69         if node.nodeType != node.ELEMENT_NODE:
    60             continue
    70             continue
    61         if node.nodeName != tag_name:
    71         if node.nodeName != tag_name:
    62             continue
    72             continue
    63         if arg_value:
    73         if arg_value:
    64             if not node.attributes.has_key('type'):
    74             if not node.attributes.has_key(arg_name):
    65                 continue
    75                 continue
    66             if node.attributes['type'].nodeValue != arg_value:
    76             if node.attributes[arg_name].nodeValue != arg_value:
    67                 continue
    77                 continue
    68         if draft:
    78         if draft:
    69             if node.attributes.has_key('draft'):
    79             if not node.attributes.has_key('draft'):
    70                 if node.attributes['draft'].nodeValue != draft:
    80                 # if draft is not specified then it's approved
    71                     continue
    81                 return node
    72             elif draft != DraftResolution.approved:
    82             value = node.attributes['draft'].nodeValue
       
    83             value = DraftResolution(value).toInt()
       
    84             exemplar = DraftResolution(draft).toInt()
       
    85             if exemplar > value:
    73                 continue
    86                 continue
    74         return node
    87         return node
    75     return False
    88     return False
    76 
    89 
    77 def _findEntry(file, path, draft=None):
    90 def _findEntryInFile(file, path, draft=None, attribute=None):
    78     doc = False
    91     doc = False
    79     if doc_cache.has_key(file):
    92     if doc_cache.has_key(file):
    80         doc = doc_cache[file]
    93         doc = doc_cache[file]
    81     else:
    94     else:
    82         doc = xml.dom.minidom.parse(file)
    95         doc = xml.dom.minidom.parse(file)
    83         doc_cache[file] = doc
    96         doc_cache[file] = doc
    84 
    97 
    85     elt = doc.documentElement
    98     elt = doc.documentElement
    86     tag_spec_list = path.split("/")
    99     tag_spec_list = path.split("/")
    87     last_entry = None
   100     last_entry = None
    88     if draft is not None:
   101     for i in range(len(tag_spec_list)):
    89         last_entry = tag_spec_list[-1]
   102         tag_spec = tag_spec_list[i]
    90         tag_spec_list = tag_spec_list[:-1]
       
    91     for tag_spec in tag_spec_list:
       
    92         tag_name = tag_spec
   103         tag_name = tag_spec
       
   104         arg_name = 'type'
    93         arg_value = ''
   105         arg_value = ''
    94         left_bracket = tag_spec.find('[')
   106         left_bracket = tag_spec.find('[')
    95         if left_bracket != -1:
   107         if left_bracket != -1:
    96             tag_name = tag_spec[:left_bracket]
   108             tag_name = tag_spec[:left_bracket]
    97             arg_value = tag_spec[left_bracket+1:-1]
   109             arg_value = tag_spec[left_bracket+1:-1].split("=")
    98         elt = findChild(elt, tag_name, arg_value)
   110             if len(arg_value) == 2:
       
   111                 arg_name = arg_value[0]
       
   112                 arg_value = arg_value[1]
       
   113             else:
       
   114                 arg_value = arg_value[0]
       
   115         alias = findChild(elt, 'alias')
       
   116         if alias and alias.attributes['source'].nodeValue == 'locale':
       
   117             path = alias.attributes['path'].nodeValue
       
   118             aliaspath = tag_spec_list[:i] + path.split("/")
       
   119             def resolve(x, y):
       
   120                 if y == '..':
       
   121                     return x[:-1]
       
   122                 return x + [y]
       
   123             # resolve all dot-dot parts of the path
       
   124             aliaspath = reduce(resolve, aliaspath, [])
       
   125             # remove attribute specification that our xpathlite doesnt support
       
   126             aliaspath = map(lambda x: x.replace("@type=", "").replace("'", ""), aliaspath)
       
   127             # append the remaining path
       
   128             aliaspath = aliaspath + tag_spec_list[i:]
       
   129             aliaspath = "/".join(aliaspath)
       
   130             # "locale" aliases are special - we need to start lookup from scratch
       
   131             return (None, aliaspath)
       
   132         elt = findChild(elt, tag_name, arg_name, arg_value, draft)
    99         if not elt:
   133         if not elt:
   100             return ""
   134             return ("", None)
   101     if last_entry is not None:
   135     if attribute is not None:
   102         elt = findChild(elt, last_entry, '', draft)
   136         if elt.attributes.has_key(attribute):
   103         if not elt:
   137             return (elt.attributes[attribute].nodeValue, None)
   104             return ""
   138         return (None, None)
   105     return elt.firstChild.nodeValue
   139     return (elt.firstChild.nodeValue, None)
   106 
   140 
   107 def findAlias(file):
   141 def findAlias(file):
       
   142     if not doc_cache.has_key(file):
       
   143         return False
   108     doc = doc_cache[file]
   144     doc = doc_cache[file]
   109     alias_elt = findChild(doc.documentElement, "alias", "")
   145     alias_elt = findChild(doc.documentElement, "alias")
   110     if not alias_elt:
   146     if not alias_elt:
   111         return False
   147         return False
   112     if not alias_elt.attributes.has_key('source'):
   148     if not alias_elt.attributes.has_key('source'):
   113         return False
   149         return False
   114     return alias_elt.attributes['source'].nodeValue
   150     return alias_elt.attributes['source'].nodeValue
   115 
   151 
   116 def findEntry(base, path, draft=None):
   152 def _findEntry(base, path, draft=None, attribute=None):
   117     file = base + ".xml"
   153     file = base
   118 
   154     if base.endswith(".xml"):
   119     if os.path.isfile(file):
   155         filename = base
   120         result = _findEntry(file, path, draft)
   156         base = base[:-4]
       
   157     else:
       
   158         file = base + ".xml"
       
   159     (dirname, filename) = os.path.split(base)
       
   160     items = filename.split("_")
       
   161     # split locale name into items and iterate through them from back to front
       
   162     # example: az_Latn_AZ => [az_Latn_AZ, az_Latn, az]
       
   163     items = reversed(map(lambda x: "_".join(items[:x+1]), range(len(items))))
       
   164     for item in items:
       
   165         file = dirname + "/" + item + ".xml"
       
   166         if os.path.isfile(file):
       
   167             alias = findAlias(file)
       
   168             if alias:
       
   169                 # if alias is found we should follow it and stop processing current file
       
   170                 # see http://www.unicode.org/reports/tr35/#Common_Elements
       
   171                 aliasfile = os.path.dirname(file) + "/" + alias + ".xml"
       
   172                 if not os.path.isfile(aliasfile):
       
   173                     raise Error("findEntry: fatal error: found an alias '%s' to '%s', but the alias file couldnt be found" % (filename, alias))
       
   174                 # found an alias, recurse into parsing it
       
   175                 result = _findEntry(aliasfile, path, draft, attribute)
       
   176                 return result
       
   177             (result, aliaspath) = _findEntryInFile(file, path, draft, attribute)
       
   178             if aliaspath:
       
   179                 # start lookup again because of the alias source="locale"
       
   180                 return _findEntry(base, aliaspath, draft, attribute)
       
   181             if result:
       
   182                 return result
       
   183     return None
       
   184 
       
   185 def findEntry(base, path, draft=None, attribute=None):
       
   186     file = base
       
   187     if base.endswith(".xml"):
       
   188         file = base
       
   189         base = base[:-4]
       
   190     else:
       
   191         file = base + ".xml"
       
   192     (dirname, filename) = os.path.split(base)
       
   193 
       
   194     result = None
       
   195     while path:
       
   196         result = _findEntry(base, path, draft, attribute)
   121         if result:
   197         if result:
   122             return result
   198             return result
   123 
   199         (result, aliaspath) = _findEntryInFile(dirname + "/root.xml", path, draft, attribute)
   124         alias = findAlias(file)
       
   125         if alias:
       
   126             file = os.path.dirname(base) + "/" + alias + ".xml"
       
   127             if os.path.isfile(file):
       
   128                 result = _findEntry(file, path, draft)
       
   129                 if result:
       
   130                     return result
       
   131 
       
   132     file = base[:-3] + ".xml"
       
   133     if os.path.isfile(file):
       
   134         result = _findEntry(file, path, draft)
       
   135         if result:
   200         if result:
   136             return result
   201             return result
   137         alias = findAlias(file)
   202         if not aliaspath:
   138         if alias:
   203             raise Error("findEntry: fatal error: %s: did not found key %s" % (filename, path))
   139             file = os.path.dirname(base) + "/" + alias + ".xml"
   204         path = aliaspath
   140             if os.path.isfile(file):
   205 
   141                 result = _findEntry(file, path, draft)
       
   142                 if result:
       
   143                     return result
       
   144 
       
   145     if not draft:
       
   146         file = os.path.dirname(base) + "/root.xml"
       
   147         result = _findEntry(file, path, draft)
       
   148     return result
   206     return result
   149 
   207