Skip to content

File xml_parser.py

File List > mkdoxy > xml_parser.py

Go to the documentation of this file

from xml.etree.ElementTree import Element as Element

from mkdoxy.cache import Cache
from mkdoxy.markdown import (
    Br,
    Code,
    Md,
    MdBlockQuote,
    MdBold,
    MdCodeBlock,
    MdHeader,
    MdImage,
    MdItalic,
    MdLink,
    MdList,
    MdParagraph,
    MdRenderer,
    MdTable,
    MdTableCell,
    MdTableRow,
    Text,
)
from mkdoxy.utils import lookahead

# https://www.doxygen.nl/manual/commands.html
SIMPLE_SECTIONS = {
    "see": "See also:",
    "note": "Note:",
    "bug": "Bug:",
    "warning": "Warning:",
    "return": "Returns:",
    "returns": "Returns:",
    "param": "Parameters:",
    "templateparam": "Template parameters:",
    "retval": "Return value:",
    "author": "Author:",
    "authors": "Authors:",
    "since": "Since:",
    "pre": "Precondition:",
    "remark": "Remark:",
    "copyright": "Copyright:",
    "post": "Postcondition:",
    "rcs": "Rcs:",
    "attention": "Attention:",
    "invariant": "Invariant:",
    "exception": "Exception:",
    "date": "Date:",
    "version": "Version:",
    "par": "\r\n",
}


class XmlParser:
    def __init__(self, cache: Cache, debug: bool = False):
        self.cachecache = cache
        self.debugdebug = debug

    def anchor(self, name: str) -> str:
        return f'<a name="{name}"></a>'

    def paras_as_str(self, p: Element, italic: bool = False, plain: bool = False) -> str:
        if plain:
            return self.plain_as_strplain_as_str(p)
        renderer = MdRenderer()
        for m in self.parasparas(p, italic=italic):
            m.render(renderer, "")
        return renderer.output

    def reference_as_str(self, p: Element) -> str:
        renderer = MdRenderer()
        refid = p.get("refid")
        if refid is None:
            return p.text
        m = MdLink([MdBold([Text(p.text)])], refid)
        m.render(renderer, "")
        return renderer.output

    def programlisting_as_str(self, p: Element) -> str:
        renderer = MdRenderer()
        for m in self.programlistingprogramlisting(p):
            m.render(renderer, "")
        return renderer.output

    def plain_as_str(self, p: Element) -> str:
        return " ".join(self.plainplain(p)).strip()

    def plain(self, p: Element) -> [str]:
        ret = []
        if p is None:
            return ret
        if p.text:
            ret.append(p.text.strip())
        for item in list(p):
            ret.extend(self.plainplain(item))
        if p.tail:
            ret.append(p.tail.strip())
        return ret

    def programlisting(self, p: Element) -> [Md]:
        ret = []
        # programlisting
        if p.tag == "programlisting":
            code = MdCodeBlock([])
            for codeline in p.findall("codeline"):
                line = ""
                for highlight in codeline.findall("highlight"):
                    if highlight.text is not None:
                        line += highlight.text
                    for c in list(highlight):
                        if c.tag == "sp":
                            line += " "
                        if c.text:
                            line += c.text
                        if c.tail:
                            line += c.tail
                code.append(line)
            ret.extend((Text("\n"), code))
        return ret

    def paras(self, p: Element, italic: bool = False) -> [Md]:
        ret = []
        if p is None:
            return ret
        if p.text:
            if italic:
                ret.extend((MdItalic([Text(p.text.strip())]), Text(" ")))
            else:
                ret.append(Text(p.text))
        for item in list(p):
            # para
            if item.tag == "para":
                ret.extend((MdParagraph(self.parasparas(item)), Text("\n")))
            elif item.tag == "image":
                url = item.get("name")
                ret.append(MdImage(url))

            elif item.tag == "computeroutput":
                text = []
                if item.text:
                    text.append(item.text)
                for i in list(item):
                    text.extend(self.plainplain(i))
                ret.append(Code(" ".join(text)))

            elif item.tag == "programlisting":
                ret.extend(self.programlistingprogramlisting(item))

            elif item.tag == "table":
                t = MdTable()
                for row in item.findall("row"):
                    r = MdTableRow([])
                    for cell in row.findall("entry"):
                        for para in cell.findall("para"):
                            r.append(MdTableCell(self.parasparas(para)))
                    t.append(r)
                ret.append(t)

            elif item.tag == "blockquote":
                b = MdBlockQuote([])
                for para in item.findall("para"):
                    b.extend(self.parasparas(para))
                ret.append(b)

            elif item.tag == "heading":
                ret.append(MdHeader(int(item.get("level")), self.parasparas(item)))

            elif item.tag in ["orderedlist", "itemizedlist"]:
                lst = MdList([])
                for listitem in item.findall("listitem"):
                    i = MdParagraph([])
                    for para in listitem.findall("para"):
                        i.extend(self.parasparas(para))
                    lst.append(i)
                ret.append(lst)

            elif item.tag == "ref":
                refid = item.get("refid")
                try:
                    ref = self.cachecache.get(refid)
                    if italic:
                        if item.text:
                            ret.append(MdLink([MdItalic([MdBold([Text(item.text)])])], ref.url))
                        else:
                            ret.append(
                                MdLink(
                                    [MdItalic([MdBold([Text(ref.get_full_name())])])],
                                    ref.url,
                                )
                            )
                    elif item.text:
                        ret.append(MdLink([MdBold([Text(item.text)])], ref.url))
                    else:
                        ret.append(MdLink([MdBold([Text(ref.get_full_name())])], ref.url))
                except Exception:
                    if item.text:
                        ret.append(Text(item.text))

            elif item.tag == "sect1":
                title = item.find("title").text
                ret.append(MdHeader(2, [Text(title)]))
                ret.extend(self.parasparas(item))

            elif item.tag == "sect2":
                title = item.find("title").text
                ret.append(MdHeader(3, [Text(title)]))
                ret.extend(self.parasparas(item))

            elif item.tag == "sect3":
                title = item.find("title").text
                ret.append(MdHeader(4, [Text(title)]))
                ret.extend(self.parasparas(item))

            elif item.tag == "sect4":
                title = item.find("title").text
                ret.append(MdHeader(5, [Text(title)]))
                ret.extend(self.parasparas(item))

            elif item.tag == "sect5":
                title = item.find("title").text
                ret.append(MdHeader(6, [Text(title)]))
                ret.extend(self.parasparas(item))

            elif item.tag == "variablelist":
                varlistentry = item.find("varlistentry")

                ret.append(MdHeader(4, self.parasparas(varlistentry.find("term"))))

                varlistentry.find("term")
                for listitem in item.findall("listitem"):
                    ret.extend(MdParagraph(self.parasparas(para)) for para in listitem.findall("para"))
            elif item.tag == "parameterlist":
                parameteritems = item.findall("parameteritem")
                lst = MdList([])
                for parameteritem in parameteritems:
                    name = parameteritem.find("parameternamelist").find("parametername")
                    description = parameteritem.find("parameterdescription").findall("para")
                    par = MdParagraph([])
                    if name is not None and len(name) > 0:
                        par.extend(self.parasparas(name))
                    else:
                        par.append(Code(name.text))
                    par.append(Text(" "))
                    for ip in description:
                        par.extend(self.parasparas(ip))
                    lst.append(par)
                ret.extend((Br(), MdBold([Text(SIMPLE_SECTIONS[item.get("kind")])]), Br(), lst))
            elif item.tag == "simplesect":
                kind = item.get("kind")
                ret.extend((Br(), MdBold([Text(SIMPLE_SECTIONS[kind])])))
                if kind != "see":
                    ret.append(Br())
                else:
                    ret.append(Text(" "))

                for sp, has_more in lookahead(item.findall("para")):
                    ret.extend(self.parasparas(sp))
                    if kind == "see":
                        if has_more:
                            ret.append(Text(", "))
                    else:
                        ret.append(Br())

            elif item.tag == "xrefsect":
                xreftitle = item.find("xreftitle")
                xrefdescription = item.find("xrefdescription")
                kind = xreftitle.text.lower()
                ret.extend((Br(), MdBold(self.parasparas(xreftitle)), Br()))
                for sp in xrefdescription.findall("para"):
                    ret.extend(self.parasparas(sp))
                    ret.append(Br())

            elif item.tag == "ulink":
                ret.append(MdLink(self.parasparas(item), item.get("url")))

            elif item.tag == "bold":
                ret.append(MdBold(self.parasparas(item)))

            elif item.tag == "emphasis":
                ret.append(MdItalic(self.parasparas(item)))

            if item.tail:
                if italic:
                    ret.extend((Text(" "), MdItalic([Text(item.tail.strip())])))
                else:
                    ret.append(Text(item.tail))
        return ret