From 6f9a8a4fd54b90ea71ca7f2703059e660608ca82 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 22 Nov 2013 01:48:09 +0400 Subject: [PATCH] Refactor _list() to be completely generic --- xml | 170 ++++++++++++++++++++------------------------------- xml-ANNOUNCE | 4 +- 2 files changed, 67 insertions(+), 107 deletions(-) diff --git a/xml b/xml index 5ed82db..7c7ffd5 100755 --- a/xml +++ b/xml @@ -37,13 +37,13 @@ The VFS was inspired by a FUSE xmlfs: https://github.com/halhen/xmlfs """ -__version__ = "0.5.1" +__version__ = "0.6.0" __author__ = "Oleg Broytman " __copyright__ = "Copyright (C) 2013 PhiloSoft Design" __license__ = "GPL" -default_implementation = None # Can be None for default choice, - # 'lxml', 'elementtree' or 'minidom' +force_implementation = None # Can be None for default choice, + # 'lxml', 'elementtree' or 'minidom' use_minidom = True use_elementtree = False @@ -115,12 +115,49 @@ locale.setlocale(locale.LC_ALL, '') class XmlVfs(object): + """Abstract base class""" + + supports_namespaces = False + def __init__(self): self.parse() def list(self): self._list(self.getroot()) + def _list(self, node, path=''): + n = len(self.getchildren(node)) + if n: + width = int(math.log10(n)) + 1 + template = "%%0%dd" % width + else: + template = "%d" + n = 0 + for element in self.getchildren(node): + if not self.istag(element): + continue + n += 1 + tag = self.getlocalname(self.gettag(element)) + if path: + subpath = '%s/%s %s' % (path, template % n, tag) + else: + subpath = '%s %s' % (template % n, tag) + subpath_encoded = subpath.encode(default_encoding, "replace") + print "dr-xr-xr-x 1 user group 0 Jan 1 00:00 %s" % subpath_encoded + if self.hasattrs(element): + attr_text = self.attrs2text(element) + print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/attributes" % ( + len(attr_text), subpath_encoded) + if self.supports_namespaces and self.has_ns(element): + ns_text = self.ns2text(element) + print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/namespaces" % ( + len(ns_text), subpath_encoded) + text = self.collect_text(element) + if text: + print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/text" % ( + len(text), subpath_encoded) + self._list(element, subpath) + def has_ns(self, node): return False @@ -163,46 +200,21 @@ class MiniDOMXmlVfs(XmlVfs): if text: text_accumulator.append(text) return '\n'.join(text_accumulator).encode(default_encoding, "replace") - def _list(self, node, path=''): - childNodes = node.childNodes - n = 0 - for element in childNodes: - if element.localName: - n += 1 - if n: - width = int(math.log10(n)) + 1 - template = "%%0%dd" % width - else: - template = "%d" - n = 0 - for element in childNodes: - if element.localName: - n += 1 - if path: - subpath = '%s/%s %s' % (path, template % n, element.localName) - else: - subpath = '%s %s' % (template % n, element.localName) - subpath_encoded = subpath.encode(default_encoding, "replace") - print "dr-xr-xr-x 1 user group 0 Jan 1 00:00 %s" % subpath_encoded - if self.hasattrs(element): - attr_text = self.attrs2text(element) - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/attributes" % ( - len(attr_text), subpath_encoded) - text = self.collect_text(element) - if text: - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/text" % ( - len(text), subpath_encoded) - self._list(element, subpath) - def getroot(self): return self.document def getchildren(self, node): return node.childNodes + def gettag(self, node): + return node.localName + def istag(self, node): return bool(node.localName) + def getlocalname(self, name): + return name + if use_elementtree or use_lxml: class CommonEtreeXmlVfs(XmlVfs): @@ -229,6 +241,9 @@ if use_elementtree or use_lxml: def getchildren(self, node): return list(node) + def gettag(self, node): + return node.tag + def istag(self, node): return isinstance(node.tag, basestring) @@ -269,44 +284,20 @@ if use_elementtree: name = name.encode(default_encoding, "replace") value = value.encode(default_encoding, "replace") if name.startswith('{'): - name = name.split('}', 1)[1] # Remove XML namespace + name = name.split('}', 1)[1] # Remove XML namespace attr_accumulator.append("%s=%s" % (name, value)) return '\n'.join(attr_accumulator) - def _list(self, node, path=''): - n = len(node) - if n: - width = int(math.log10(n))+1 - template = "%%0%dd" % width - else: - template = "%d" - n = 0 - for element in node: - if not isinstance(element.tag, basestring): - continue - n += 1 - tag = element.tag - if tag.startswith('{'): - tag = tag.split('}', 1)[1] # Remove XML namespace - if path: - subpath = '%s/%s %s' % (path, template % n, tag) - else: - subpath = '%s %s' % (template % n, tag) - subpath_encoded = subpath.encode(default_encoding, "replace") - print "dr-xr-xr-x 1 user group 0 Jan 1 00:00 %s" % subpath_encoded - if self.hasattrs(element): - attr_text = self.attrs2text(element) - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/attributes" % ( - len(attr_text), subpath_encoded) - text = self.collect_text(element) - if text: - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/text" % ( - len(text), subpath_encoded) - self._list(element, subpath) + def getlocalname(self, name): + if name.startswith('{'): + name = name.split('}', 1)[1] # Remove XML namespace + return name if use_lxml: class LxmlEtreeXmlVfs(CommonEtreeXmlVfs): + supports_namespaces = True + def parse(self): self.document = etree.parse(sys.argv[2]) @@ -329,60 +320,29 @@ if use_lxml: ns_accumulator.append("%s=%s" % (name, value)) return '\n'.join(ns_accumulator) - def list(self): - self._list(self.getroot()) - - def _list(self, node, path=''): - n = len(node) - if n: - width = int(math.log10(n))+1 - template = "%%0%dd" % width - else: - template = "%d" - n = 0 - for element in node: - if not isinstance(element.tag, basestring): - continue - n += 1 - tag = etree.QName(element.tag).localname - if path: - subpath = '%s/%s %s' % (path, template % n, tag) - else: - subpath = '%s %s' % (template % n, tag) - subpath_encoded = subpath.encode(default_encoding, "replace") - print "dr-xr-xr-x 1 user group 0 Jan 1 00:00 %s" % subpath_encoded - if self.hasattrs(element): - attr_text = self.attrs2text(element) - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/attributes" % ( - len(attr_text), subpath_encoded) - if element.nsmap: - ns_text = self.ns2text(element) - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/namespaces" % ( - len(ns_text), subpath_encoded) - text = self.collect_text(element) - if text: - print "-r--r--r-- 1 user group %d Jan 1 00:00 %s/text" % ( - len(text), subpath_encoded) - self._list(element, subpath) - def getroot(self): return [self.document.getroot()] + def getlocalname(self, name): + return etree.QName(name).localname + def build_xmlvfs(): - if default_implementation is None: + if force_implementation is None: if use_lxml: return LxmlEtreeXmlVfs() elif use_elementtree: return ElementTreeXmlVfs() else: return MiniDOMXmlVfs() - elif default_implementation == 'minidom': + elif force_implementation == 'minidom': return MiniDOMXmlVfs() - elif default_implementation == 'elementtree': + elif force_implementation == 'elementtree': return ElementTreeXmlVfs() - elif default_implementation == 'lxml': + elif force_implementation == 'lxml': return LxmlEtreeXmlVfs() + else: + raise ValueError('Unknown implementation "%s", expected "minidom", "elementtree" or "lxml"' % force_implementation) def mcxml_list(): diff --git a/xml-ANNOUNCE b/xml-ANNOUNCE index 263f1d9..98ff711 100644 --- a/xml-ANNOUNCE +++ b/xml-ANNOUNCE @@ -5,8 +5,8 @@ WHAT IS IT View an XML file in Midnight Commander as a filesystem. -WHAT'S NEW in version 0.5.1 (2013-11-20) - Fixed a bug in handling comments. +WHAT'S NEW in version 0.6.0 (2013-11-22) + Refactored _list() to be completely generic. WHAT'S NEW in version 0.5.0 (2013-11-19) Added lxml.etree-based implementation. -- 2.39.2