creole/creole/xmlreflector.py

108 lines
4.3 KiB
Python

# coding: utf-8
from os.path import join, isfile, basename, isdir
from os import listdir
from base64 import decodestring
from io import BytesIO
from collections import OrderedDict
import sys
from lxml.etree import DTD, parse, tostring, XMLParser # pylint: disable=E0611
from .i18n import _
from .utils import normalize_family
from .error import CreoleDictConsistencyError
from .config import VIRTBASE, VIRTROOT, VIRTMASTER, templatedir
HIGH_COMPATIBILITY = True
class XMLReflector(object):
"""Helper class for loading the Creole XML file,
parsing it, validating against the Creole DTD,
writing the xml result on the disk
"""
def __init__(self):
self.dtd = None
def parse_dtd(self, dtdfilename):
"""Loads the Creole DTD
:raises IOError: if the DTD is not found
:param dtdfilename: the full filename of the Creole DTD
"""
if not isfile(dtdfilename):
raise IOError(_("no such DTD file: {}").format(dtdfilename))
with open(dtdfilename, 'r') as dtdfd:
self.dtd = DTD(dtdfd)
def parse_xmlfile(self, xmlfile, from_zephir=None, zephir2=False):
"""Parses and validates some Creole XML against the Creole DTD
:returns: the root element tree object
"""
if from_zephir:
if zephir2:
document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True))
else:
document = parse(BytesIO(decodestring(xmlfile)), XMLParser(remove_blank_text=True))
else:
document = parse(xmlfile)
assert self.dtd.validate(document), _("not a valid xml file: {}").format(xmlfile)
return document.getroot()
def load_xml_from_folders(self, xmlfolders, from_zephir):
"""Loads all the XML files located in the xmlfolders' list
:param xmlfolders: list of full folder's name
"""
documents = []
if from_zephir:
for idx, xmlfile in enumerate(xmlfolders):
documents.append(('generate_{}'.format(idx), self.parse_xmlfile(xmlfile, from_zephir=from_zephir)))
else:
if not isinstance(xmlfolders, list):
xmlfolders = [xmlfolders]
for xmlfolder in xmlfolders:
if isinstance(xmlfolder, list) or isinstance(xmlfolder, tuple):
# directory group : collect files from each
# directory and sort them before loading
group_files = []
for idx, subdir in enumerate(xmlfolder):
if isdir(subdir):
for filename in listdir(subdir):
group_files.append((filename, idx, subdir))
else:
group_files.append(basename(subdir), idx, dirname(subdir))
def sort_group(file1, file2):
if file1[0] == file2[0]:
# sort by initial xmlfolder order if same name
return file1[1].__cmp__(file2[1])
# sort by filename
elif file1[0] > file2[0]:
return 1
else:
return -1
group_files.sort(sort_group)
filenames = [join(f[2], f[0]) for f in group_files]
elif isdir(xmlfolder):
filenames = []
for filename in listdir(xmlfolder):
filenames.append(join(xmlfolder, filename))
filenames.sort()
else:
filenames = [xmlfolder]
for xmlfile in filenames:
if xmlfile.endswith('.xml'):
#xmlfile_path = join(xmlfolder, xmlfile)
documents.append((xmlfile, self.parse_xmlfile(xmlfile)))
return documents
def save_xmlfile(self, xmlfilename, xml): # pylint: disable=R0201
"""Write a bunch of XML on the disk
"""
with open(xmlfilename, 'w') as xmlfh:
if sys.version_info[0] < 3:
xmlfh.write(tostring(xml, pretty_print=True, encoding="UTF-8", xml_declaration=True))
else:
xmlfh.write(tostring(xml, pretty_print=True, encoding="UTF-8", xml_declaration=True).decode('utf8'))