Last active
February 14, 2017 17:14
-
-
Save rmax/c7ad34cf1f70d114ec64b072581fb1f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from js2xml import parse, pretty_print as tostring | |
from js2xml.jsonlike import make_dict, getall as get_json_objs | |
MAKE_DICT_TYPES = ( | |
# Types that can be handled by make_dict. | |
'array', | |
'object', | |
'property', | |
'string', | |
'boolean', | |
'number', | |
'undefined', | |
) | |
def make_obj(tree, ignore_tags=(), _ignore=object()): | |
if tree.tag == 'null': | |
return | |
if tree.tag == 'identifier': | |
return tree.get('name') | |
if tree.tag in MAKE_DICT_TYPES: | |
return make_dict(tree) | |
if tree.tag == 'var': | |
obj = {} | |
children = tree.getchildren() | |
# var can have no children if there is no value. | |
if children: | |
assert len(children) == 1 | |
value = make_obj(children[0], ignore_tags=ignore_tags, _ignore=_ignore) | |
if value is not _ignore: | |
obj[tree.attrib['name']] = value | |
return obj | |
if tree.tag == 'assign': | |
assert tree.attrib['operator'] == '=', "only = operator supported" | |
left_element = _xpath_one(tree, 'left/*') | |
right_element = _xpath_one(tree, 'right/*') | |
obj = {} | |
name = make_varname(left_element) | |
value = make_obj(right_element, ignore_tags=ignore_tags, _ignore=_ignore) | |
if value is not _ignore: | |
obj[name] = value | |
return obj | |
if '*' in ignore_tags or tree.tag in ignore_tags: | |
return _ignore | |
raise ValueError("Unknown tag: %s" % tree.tag) | |
def make_varname(tree): | |
""" | |
<left> tree </left> | |
""" | |
if tree.tag == 'identifier': | |
return tree.attrib['name'] | |
if tree.tag in ('string', 'boolean'): | |
return tree.text | |
if tree.tag == 'number': | |
return tree.attrib['value'] | |
if tree.tag in ('property', 'object'): | |
return make_varname(_xpath_one(tree, '*')) | |
if tree.tag.endswith('accessor'): | |
kind = tree.tag[:-len('accessor')] | |
obj = make_varname(_xpath_one(tree, 'object')) | |
prop = make_varname(_xpath_one(tree, 'property')) | |
if kind == 'dot': | |
fmt = '%s.%s' | |
elif kind == 'bracket': | |
fmt = '%s[%s]' | |
else: | |
raise ValueError("Unknown accessor: %s" % tree.tag) | |
return fmt % (obj, prop) | |
raise ValueError("Unknown tag: %s" % tree.tag) | |
def get_vars(code, doseq=False, ignore_tags=()): | |
""" | |
>>> get_vars('Mage.Cookies.path = "/"')['Mage.Cookies.path'] | |
'/' | |
>>> get_vars('Mage.Cookies.path = "/"')['Mage.Cookies.path'] | |
""" | |
vars = {} | |
dom = parse(code) | |
elements = dom.xpath('/program/*[self::var[@name] or self::assign[@operator="="]]') | |
for el in elements: | |
obj = make_obj(el, ignore_tags=ignore_tags) | |
assert isinstance(obj, dict) | |
if doseq: | |
for key, val in obj.items(): | |
vars.setdefault(key, []).append(val) | |
else: | |
vars.update(obj) | |
return vars | |
def _xpath_one(tree, xpath): | |
elements = tree.xpath(xpath) | |
if not elements: | |
raise ValueError("no matching element") | |
if len(elements) > 1: | |
raise ValueError("more than one matching element") | |
return elements[0] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment