Home > Software engineering >  Checking whether an object is a parameter in another object
Checking whether an object is a parameter in another object

Time:04-24

I'm currently building a HTML renderer in Python and have this for the classes to handle the tags:

class SingleTag:
    """A class to represent an html tag"""

    # Class initialiser
    def __init__(self, inner_html):
        self.open_tag = "<"   self.__class__.__name__.lower()   ">"
        self.close_tag = "</" self.__class__.__name__.lower()   ">"
        self.inner_html = inner_html

    # Prints html
    def render(self):
        return self.open_tag   self.inner_html   self.close_tag

class ContainingTag:
    def __init__(self, children):
        self.open_tag = "<"   self.__class__.__name__.lower()   ">"
        self.close_tag = "</" self.__class__.__name__.lower()   ">"
        self.children = children
        

    def render(self):
        print("\t"   self.open_tag)
        for child in self.children:
            print("\t \t"   str(child.render()))
        print("\t"   self.close_tag)
        return ""
        

class Html(ContainingTag):
    def __init__(self, children):
        super().__init__(children) 
        self.open_tag = "<!DOCTYPE html>\n"  "<"   self.__class__.__name__.lower()   ">"
    
    def render(self):
        print(self.open_tag)

        for child in self.children:
            print("\t \t"   str(child.render()))
        print(self.close_tag)
        return ""

class Head(ContainingTag):
    def __init__(self, children):
        super().__init__(children)

class Style(ContainingTag):
    def __init__(self, children):
        super().__init__(children)

class Body(ContainingTag):
    def __init__(self, children):
        super().__init__(children)  

class Div(ContainingTag):
    def __init__(self, children):
        super().__init__(children)

class P(SingleTag):
    def __init__(self, inner_html):
        super().__init__(inner_html)
from tag import Html, P, Div, Head, Style, Body
 
html = Html([
        Div([
            Head([])
        ])    
    ])

print(html.render())
<!DOCTYPE html>
<html>
        <div>
        <head>
        </head>

        </div>

</html>

My single tags work fine printing inside a containing tag but when printing a containing tag inside another containing tag, the indention is on the same level, when I want it to be indented. Is there a way to check whether a containing tag is a child of another containing tag, so I can conditionally print the extra indentation?

CodePudding user response:

The way I've always handled recursive indents like this is with a keyword argument to render (or whatever name the equivalent function has).

Also, you can save a lot of code by inheriting property functions, which act like attributes, instead of setting static values in the __init__ functions.

class Tag:

    @property
    def open_tag(self): return f'<{self.__class__.__name__.lower()}>'

    @property
    def close_tag(self): return f'</{self.__class__.__name__.lower()}>'

    def __str__(self):
        return self.render()

class SingleTag(Tag):

    def __init__(self, inner_html):
        self.inner_html = inner_html

    def render(self, indent=''):
        return f'{indent}{self.open_tag}{self.inner_html}{self.close_tag}\n'

class ContainingTag(Tag):

    def __init__(self, children):
        self.children = children

    def render(self, indent=''):
        inner = ''.join(child.render(indent   '\t') for child in self.children)
        return f'{indent}{self.open_tag}\n{inner}{indent}{self.close_tag}\n'

class Html(ContainingTag):
    '''HTML tag'''

    @property
    def open_tag(self): return '<!DOCTYPE html>\n<html>'
    
class Head(ContainingTag): '''HEAD tag'''

class Style(ContainingTag): '''STYLE tag'''

class Body(ContainingTag): '''BODY tag'''

class Div(ContainingTag): '''DIV tag'''

class P(SingleTag): '''P tag'''

Then:

html = Html([Div([Head([])])])
print(html)
<!DOCTYPE html>
<html>
    <div>
        <head>
        </head>
    </div>
</html>

Note: I've used \t as the per-level indent here, but you could use whatever makes sense for your needs.

  • Related