Open4
python class
自分が使うためだけのHTML DOMツリーを作成した。
class Node:
def __init__(self, name: str):
self.__name = name
self.__attr = {}
self.__child = []
self.__level = 0
# a[key] = value
def __setitem__(self, key: str, value: str):
self.__attr[key] = value
# b = a[key]
def __getitem__(self, key: str) -> str:
return self.__attr.get(key, "")
# key = "value"
def __str_attr(self) -> str:
a = [f'{k}="{v}"' if type(v) is str else k for k, v in self.__attr.items()]
return " ".join(a)
# この関数でlevelを指定すれば子要素のlevelも調整してくれる
def __set_level(self, level: int):
self.__level = level + 1
for i in self.__child:
if type(i) is Node:
i.__set_level(self.__level)
# 子要素の追加
def append(self, node):
"""
node: Node or str
"""
if type(node) is Node:
node.__set_level(self.__level)
self.__child.append(node)
def __str__(self) -> str:
attr = self.__str_attr()
if attr:
attr = " " + attr
level = " " * self.__level
if len(self.__child) > 0:
# 子要素がテキストだけなら1行で表示
if len(self.__child) == 1 and type(self.__child[0]) is str:
return (
level + f"<{self.__name}{attr}>{self.__child[0]}</{self.__name}>\n"
)
else:
result = level + f"<{self.__name}{attr}>\n"
for i in self.__child:
result += str(i)
result += level + f"</{self.__name}>\n"
return result
else:
# 子要素がない場合
return level + f"<{self.__name}{attr}/>\n"
使い方は以下の通り
html = Node("html")
html["lang"] = "ja" # 属性を指定する場合は左記のように
head = Node("head")
chara = Node("meta")
chara["charset"] = "UTF-8"
title = Node("title")
title.append("sample")
body = Node("body")
html.append(head)
head.append(chara)
head.append(title)
html.append(body)
script = Node("script")
script["src"] = "js/script.js"
script["defer"] = None # <script defer></script>のように属性に=を使用しない場合はNoneを指定する
script.append("") # scriptタグは終了タグも必要なので空文字を追加
head.append(script)
print(html)
実行結果
<html lang="ja">
<head>
<meta charset="UTF-8"/>
<title>sample</title>
<script src="js/script.js" defer></script>
</head>
<body/>
</html>
Nodeを作成する時に属性も一緒に指定したい
キーワード変数は全て属性と考える?
class Node:
def __init__(self, name: str, **kwargs): # kwargsを全て属性扱い
self.__name = name
self.__attr = kwargs
.
.
動作はするみたい
html = Node("html", lang="ja")
print(html)
result
<html lang="ja"/>
TODO
- 子要素をタグ名,ID,CLASSを指定して取得する関数
- Emmetを引数に渡してツリーを作成する関数
- DOCTYPE指定
- コメントも追加できるといいね
levelを中止、parentとrootを持たせた
class Node:
def __init__(
self, name: str, id: str | None = None, class_: str | None = None, **kwargs
):
self.__name = name
self.__attr = kwargs
if id:
self.__attr[id] = id
if class_:
self.__attr["class"] = class_
self.__child = []
self.__root = self
self.__parent = None
def __setitem__(self, key: str, value: str):
self.__attr[key] = value
def __getitem__(self, key: str) -> str:
return self.__attr.get(key, "")
def html_string(self, lank: int = 0) -> str:
result = lank * " " + f"<{self.__name}"
for k, v in self.__attr.items():
result += f' {k}="{v}"'
if self.__child:
result += ">\n"
for i in self.__child:
result += i.html_string(lank + 1)
result += lank * " " + f"</{self.__name}>\n"
else:
result += "/>\n"
return result
def append(self, node):
if issubclass(type(node), Node):
node.__root = self.__root
node.__parent = self
self.__child.append(node)
class TextNode(Node):
def __init__(self, text: str):
super().__init__("text")
self.text = text
self.__root = self
self.__parent = None
def __setitem__(self, key: str, value: str):
pass
def __getitem__(self, key: str) -> str:
return ""
def html_string(self, lank: int = 0) -> str:
return lank * " " + f"{self.text}\n"
a = Node("html", lang="ja")
b = Node("head")
c = Node("meta", charset="utf-8")
d = Node("title")
e = Node("body")
d.append(TextNode("Sample"))
a.append(b)
b.append(c)
b.append(d)
a.append(e)
print(a.html_string())
出力
<html lang="ja">
<head>
<meta charset="utf-8"/>
<title>
Sample
</title>
</head>
<body/>
</html>