Blame lib/dbtexmf/core/xmlparser.py

Packit 0f19cf
import os
Packit 0f19cf
import re
Packit 0f19cf
import xml.etree.ElementTree as ET
Packit Service 7080c1
from txtparser import texinputs_parse
Packit 0f19cf
Packit 0f19cf
class BaseOption:
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        self.config = config
Packit 0f19cf
        self.optname = optname
Packit 0f19cf
        self._value = None
Packit 0f19cf
Packit 0f19cf
    def optvalue(self):
Packit 0f19cf
        return self._value
Packit 0f19cf
Packit 0f19cf
    def get(self, what, default=None):
Packit 0f19cf
        return None
Packit 0f19cf
Packit 0f19cf
    def options(self):
Packit 0f19cf
        value = self.optvalue()
Packit 0f19cf
        if self.optname and value:
Packit 0f19cf
            return ["%s=%s" % (self.optname, value)]
Packit 0f19cf
        else:
Packit 0f19cf
            return []
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self._value = xmlnode.text
Packit 0f19cf
Packit 0f19cf
    def modules(self):
Packit 0f19cf
        return {}
Packit 0f19cf
Packit 0f19cf
class CommandConfig:
Packit 0f19cf
    def __init__(self, config, type="command"):
Packit 0f19cf
        self.config = config
Packit 0f19cf
        self.type = type
Packit 0f19cf
        self.args = []
Packit 0f19cf
        self.stdin = None
Packit 0f19cf
        self.stdout = None
Packit 0f19cf
        self.shell = False
Packit 0f19cf
Packit 0f19cf
    def options(self):
Packit 0f19cf
        return self.args
Packit 0f19cf
Packit 0f19cf
    def modules(self):
Packit 0f19cf
        return {}
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.stdin = xmlnode.get("input")
Packit 0f19cf
        self.stdout = xmlnode.get("output")
Packit 0f19cf
        self.shell = xmlnode.get("shell")
Packit 0f19cf
        args = (xmlnode.text or "").split()
Packit 0f19cf
        for arg in xmlnode:
Packit 0f19cf
            if arg.text: args.append(arg.text)
Packit 0f19cf
            args.extend((arg.tail or "").split())
Packit 0f19cf
        self.args = args
Packit 0f19cf
Packit 0f19cf
class TexStyle(BaseOption):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        BaseOption.__init__(self, config, optname)
Packit 0f19cf
        self.filepath = ""
Packit 0f19cf
Packit 0f19cf
    def optvalue(self):
Packit 0f19cf
        return self.filepath
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.filepath = xmlnode.get("fileref") or xmlnode.get("use")
Packit 0f19cf
Packit 0f19cf
class TexPath(BaseOption):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        BaseOption.__init__(self, config, optname)
Packit 0f19cf
        self.paths = []
Packit 0f19cf
Packit 0f19cf
    def optvalue(self):
Packit 0f19cf
        return os.pathsep.join(self.paths)
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        if not(xmlnode.text): return
Packit 0f19cf
        self.paths = texinputs_parse(xmlnode.text, self.config.basedir)
Packit 0f19cf
Packit 0f19cf
class FilePath(BaseOption):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        BaseOption.__init__(self, config, optname)
Packit 0f19cf
        self.filepath = ""
Packit 0f19cf
Packit 0f19cf
    def optvalue(self):
Packit 0f19cf
        return self.filepath
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        filepath = xmlnode.get("fileref")
Packit 0f19cf
        if not(filepath):
Packit 0f19cf
            return
Packit 0f19cf
        if not(os.path.isabs(filepath)):
Packit 0f19cf
            filepath = os.path.normpath(os.path.join(self.config.basedir,
Packit 0f19cf
                                                     filepath))
Packit 0f19cf
        self.filepath = filepath
Packit 0f19cf
Packit 0f19cf
Packit 0f19cf
class ModuleConfig(BaseOption):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        BaseOption.__init__(self, config, optname)
Packit 0f19cf
        self.commands = []
Packit 0f19cf
        self.extra_args = None
Packit 0f19cf
        self.module_name = ""
Packit 0f19cf
        self.module_file = ""
Packit 0f19cf
Packit 0f19cf
    def optvalue(self):
Packit 0f19cf
        return self.module_name or self.module_file
Packit 0f19cf
Packit 0f19cf
    def modules(self):
Packit 0f19cf
        if self.module_name:
Packit 0f19cf
            return {self.module_name: self}
Packit 0f19cf
        else:
Packit 0f19cf
            return {}
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        ns = { "x": self.config.xmlns }
Packit 0f19cf
        self._handle_location(xmlnode)
Packit 0f19cf
        xmlopts = xmlnode.find("x:options", ns)
Packit 0f19cf
        xmlcmds = xmlnode.find("x:command", ns)
Packit 0f19cf
        xmlchain = xmlnode.find("x:commandchain", ns)
Packit 0f19cf
        if not(xmlchain is None):
Packit 0f19cf
            xmlcmds = xmlchain.findall("x:command", ns)
Packit 0f19cf
            for cmd in xmlcmds:
Packit 0f19cf
                args = CommandConfig(self.config)
Packit 0f19cf
                args.fromnode(cmd)
Packit 0f19cf
                self.commands.append(args)
Packit 0f19cf
        elif not(xmlcmds is None):
Packit 0f19cf
            args = CommandConfig(self.config)
Packit 0f19cf
            args.fromnode(xmlcmds)
Packit 0f19cf
            self.commands.append(args)
Packit 0f19cf
        elif not(xmlopts is None):
Packit 0f19cf
            # FIXME
Packit 0f19cf
            self.extra_args = CommandConfig(self.config, type="option")
Packit 0f19cf
            self.extra_args.fromnode(xmlopts)
Packit 0f19cf
Packit 0f19cf
    def _handle_location(self, xmlnode):
Packit 0f19cf
        self.module_name = xmlnode.get("use")
Packit 0f19cf
        self.module_file = xmlnode.get("fileref")
Packit 0f19cf
        if not(self.module_name) and self.module_file:
Packit 0f19cf
            p = FilePath(self.config, "")
Packit 0f19cf
            p.fromnode(xmlnode)
Packit 0f19cf
            self.module_file = p.filepath
Packit 0f19cf
Packit 0f19cf
class ImageConverterConfig(ModuleConfig):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        ModuleConfig.__init__(self, config, optname)
Packit 0f19cf
Packit 0f19cf
    def __repr__(self):
Packit 0f19cf
        return self.module_name
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.imgsrc = xmlnode.get("src")
Packit 0f19cf
        self.imgdst = xmlnode.get("dst")
Packit 0f19cf
        self.docformat = xmlnode.get("docformat") or "*"
Packit 0f19cf
        self.backend = xmlnode.get("backend") or "*"
Packit 0f19cf
        ModuleConfig.fromnode(self, xmlnode)
Packit 0f19cf
        name = "%s/%s/%s/%s" % (self.imgsrc, self.imgdst,
Packit 0f19cf
                                self.docformat, self.backend)
Packit 0f19cf
        self.module_name = name
Packit 0f19cf
Packit 0f19cf
class ImageFormatConfig(BaseOption):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        BaseOption.__init__(self, config, optname)
Packit 0f19cf
        self.imgsrc = ""
Packit 0f19cf
        self.imgdst = ""
Packit 0f19cf
        self.docformat = ""
Packit 0f19cf
        self.backend = ""
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.imgsrc = xmlnode.get("src")
Packit 0f19cf
        self.imgdst = xmlnode.get("dst")
Packit 0f19cf
        self.docformat = xmlnode.get("docformat") or "*"
Packit 0f19cf
        self.backend = xmlnode.get("backend") or "*"
Packit 0f19cf
Packit 0f19cf
class XsltEngineConfig(ModuleConfig):
Packit 0f19cf
    def __init__(self, config, optname):
Packit 0f19cf
        ModuleConfig.__init__(self, config, optname)
Packit 0f19cf
Packit 0f19cf
    def __repr__(self):
Packit 0f19cf
        return self.module_name
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.param_format = xmlnode.get("param-format")
Packit 0f19cf
        ModuleConfig.fromnode(self, xmlnode)
Packit 0f19cf
        if not(self.module_name or self.module_file):
Packit 0f19cf
            self.module_name = "xsltconf"
Packit 0f19cf
Packit 0f19cf
class XmlConfigGroup:
Packit 0f19cf
    node_parsers = {}
Packit 0f19cf
Packit 0f19cf
    def __init__(self, config):
Packit 0f19cf
        self.config = config
Packit 0f19cf
        self.tagname = ""
Packit 0f19cf
        self.infos = {}
Packit 0f19cf
Packit 0f19cf
    def get(self, tag, default=""):
Packit 0f19cf
        if default == "": default = BaseOption(self, "")
Packit 0f19cf
        return self.infos.get(tag, default)
Packit 0f19cf
Packit 0f19cf
    def _register(self, xmlnode, info):
Packit 0f19cf
        tag = self.strip_ns(xmlnode.tag)
Packit 0f19cf
        taglist = self.infos.get(tag, [])
Packit 0f19cf
        taglist.append(info)
Packit 0f19cf
        self.infos[tag] = taglist
Packit 0f19cf
Packit 0f19cf
    def strip_ns(self, tag):
Packit 0f19cf
        return self.config.strip_ns(tag)
Packit 0f19cf
Packit 0f19cf
    def options(self):
Packit 0f19cf
        opts = []
Packit 0f19cf
        for parsers in self.infos.values():
Packit 0f19cf
            for parser in parsers:
Packit 0f19cf
                opts.extend(parser.options())
Packit 0f19cf
        return opts
Packit 0f19cf
Packit 0f19cf
    def modules(self):
Packit 0f19cf
        mods = {}
Packit 0f19cf
        for parsers in self.infos.values():
Packit 0f19cf
            for parser in parsers:
Packit 0f19cf
                mods.update(parser.modules())
Packit 0f19cf
        return mods
Packit 0f19cf
Packit 0f19cf
    def fromnode(self, xmlnode):
Packit 0f19cf
        self.tagname = xmlnode.tag
Packit 0f19cf
        for child in xmlnode:
Packit 0f19cf
            found = self.node_parsers.get(self.strip_ns(child.tag))
Packit 0f19cf
            if found:
Packit 0f19cf
                optname, parser_cls = found
Packit 0f19cf
                parser = parser_cls(self.config, optname)
Packit 0f19cf
                parser.fromnode(child)
Packit 0f19cf
                self._register(child, parser)
Packit 0f19cf
Packit 0f19cf
class LatexConfig(XmlConfigGroup):
Packit 0f19cf
    node_parsers = {
Packit 0f19cf
        "texinputs":  ("--texinputs", TexPath),
Packit 0f19cf
        "bibinputs":  ("--bib-path", TexPath),
Packit 0f19cf
        "bstinputs":  ("--bst-path", TexPath),
Packit 0f19cf
        "texstyle":   ("--texstyle", TexStyle),
Packit 0f19cf
        "indexstyle": ("--indexstyle", FilePath),
Packit 0f19cf
        "backend":    ("--backend", ModuleConfig),
Packit 0f19cf
        "texpost":    ("--texpost", ModuleConfig)
Packit 0f19cf
    }
Packit 0f19cf
Packit 0f19cf
class XsltConfig(XmlConfigGroup):
Packit 0f19cf
    node_parsers = {
Packit 0f19cf
        "stylesheet": ("--xsl-user", FilePath),
Packit 0f19cf
        "engine":     ("--xslt", XsltEngineConfig)
Packit 0f19cf
    }
Packit 0f19cf
Packit 0f19cf
class ImageConfig(XmlConfigGroup):
Packit 0f19cf
    node_parsers = {
Packit 0f19cf
        "figpath": ("--fig-path", FilePath),
Packit 0f19cf
        "figformat": ("--fig-format", BaseOption),
Packit 0f19cf
        "converter": ("", ImageConverterConfig),
Packit 0f19cf
        "formatrule": ("", ImageFormatConfig)
Packit 0f19cf
    }
Packit 0f19cf
Packit 0f19cf
Packit 0f19cf
class XmlConfig:
Packit 0f19cf
    """
Packit 0f19cf
    Parses an XML configuration file and stores its data in
Packit 0f19cf
    configuration objects.
Packit 0f19cf
    """
Packit 0f19cf
    node_parsers = {
Packit 0f19cf
        "latex": LatexConfig,
Packit 0f19cf
        "xslt": XsltConfig,
Packit 0f19cf
        "imagedata": ImageConfig,
Packit 0f19cf
        "options": CommandConfig
Packit 0f19cf
    }
Packit 0f19cf
    xmlns = "http://dblatex.sourceforge.net/config"
Packit 0f19cf
    root_tag = "config"
Packit 0f19cf
Packit 0f19cf
    def __init__(self):
Packit 0f19cf
        self.basedir = ""
Packit 0f19cf
        self.infos = {}
Packit 0f19cf
Packit 0f19cf
    def _register(self, xmlnode, info):
Packit 0f19cf
        self.infos[self.strip_ns(xmlnode.tag)] = info
Packit 0f19cf
Packit 0f19cf
    def get(self, tag, default=""):
Packit 0f19cf
        if default == "": default = BaseOption(self, "")
Packit 0f19cf
        return self.infos.get(tag, default)
Packit 0f19cf
Packit 0f19cf
    def options(self):
Packit 0f19cf
        opts = []
Packit 0f19cf
        for parser in self.infos.values():
Packit 0f19cf
            opts.extend(parser.options())
Packit 0f19cf
        return opts
Packit 0f19cf
Packit 0f19cf
    def modules(self):
Packit 0f19cf
        mods = {}
Packit 0f19cf
        for parser in self.infos.values():
Packit 0f19cf
            mods.update(parser.modules())
Packit 0f19cf
        return mods
Packit 0f19cf
Packit 0f19cf
    def strip_ns(self, tag):
Packit 0f19cf
        return tag.replace("{%s}" % self.xmlns, "", 1)
Packit 0f19cf
Packit 0f19cf
    def fromfile(self, filename):
Packit 0f19cf
        self.basedir = os.path.dirname(os.path.realpath(filename))
Packit 0f19cf
Packit 0f19cf
        document = ET.parse(filename)
Packit 0f19cf
        root = document.getroot()
Packit 0f19cf
        self._check_root(root.tag)
Packit 0f19cf
        for child in root:
Packit 0f19cf
            parser_cls = self.node_parsers.get(self.strip_ns(child.tag))
Packit 0f19cf
            if parser_cls:
Packit 0f19cf
                parser = parser_cls(self)
Packit 0f19cf
                parser.fromnode(child)
Packit 0f19cf
                self._register(child, parser)
Packit 0f19cf
Packit 0f19cf
    def _check_root(self, root):
Packit 0f19cf
        xmlns, tag = self._split_xmlns(root)
Packit 0f19cf
        if tag != self.root_tag:
Packit 0f19cf
            raise ValueError("Expect the XML config root element being '%s'" % \
Packit 0f19cf
                             self.root_tag)
Packit 0f19cf
        if xmlns and xmlns != self.xmlns:
Packit 0f19cf
            raise ValueError("Invalid XML config xmlns: '%s'" % xmlns)
Packit 0f19cf
Packit 0f19cf
    def _split_xmlns(self, tag):
Packit 0f19cf
        m = re.match("{([^}]+)}(.*)", tag)
Packit 0f19cf
        if m:
Packit 0f19cf
            return m.group(1), m.group(2)
Packit 0f19cf
        else:
Packit 0f19cf
            return "", tag
Packit 0f19cf