Last active
February 13, 2023 05:15
-
-
Save CNSeniorious000/cff233f439393dfada6464fd63bca5fe to your computer and use it in GitHub Desktop.
重载各种运算符,实现用原生的运算符生成树结构,并导出为xml字符串
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>标题</title> | |
</head> | |
<body> | |
<img src="图片地址" alt="图片标题" /> | |
<div> | |
<p>第0句</p> | |
<p>第1句</p> | |
<p>第2句</p> | |
<p>第3句</p> | |
<p>第4句</p> | |
<p>第5句</p> | |
<p>第6句</p> | |
<p>第7句</p> | |
<p>第8句</p> | |
<p>第9句</p> | |
</div> | |
<div> | |
<div> | |
<p> | |
<ul> | |
<li>还可以链式调用</li> | |
</ul> | |
</p> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from enum import IntEnum | |
class Line: | |
def __init__(self, indent_level: int = 0, indent_step: int = 2, indent_char: str = " "): | |
assert isinstance(indent_level, int) | |
assert isinstance(indent_step, int) | |
assert indent_level >= 0 | |
assert indent_step >= 0 | |
self._level = indent_level | |
self._step = indent_step | |
self._char = indent_char | |
def indent(self, level: int): | |
return self._char * level | |
class Type(IntEnum): | |
Text = 0 | |
Node = 1 | |
class Element(Line): | |
def __init__(self, name: str, indent_level: int = 0, indent_step: int = 2, indent_char: str = " "): | |
Line.__init__(self, indent_level, indent_step, indent_char) | |
assert isinstance(name, str) | |
self.name = name | |
self.children: list[Element] = [] | |
self.attributes: dict[str, str] = {} | |
self.type: Type = Type.Text | |
@property | |
def attrs(self): | |
return " ".join(f'{key}="{value}"' for key, value in self.attributes.items()) | |
def iter_lines(self, level: int): | |
if self.type is Type.Text: | |
yield self.indent(level) + self.name | |
return | |
if not self.children: | |
if self.attributes: | |
yield f"{self.indent(level)}<{self.name} {self.attrs} />" | |
else: | |
yield f"{self.indent(level)}<{self.name} />" | |
elif len(self.children) == 1 and self.children[0].type is Type.Text: | |
if self.attributes: | |
yield f"{self.indent(level)}<{self.name} {self.attrs}>{self.children[0].stringify()}</{self.name}>" | |
else: | |
yield f"{self.indent(level)}<{self.name}>{self.children[0].stringify()}</{self.name}>" | |
else: | |
if self.attributes: | |
yield f"{self.indent(level)}<{self.name} {self.attrs}>" | |
else: | |
yield f"{self.indent(level)}<{self.name}>" | |
yield from map(lambda child: child.stringify(level + self._step), self.children) | |
yield f"{self.indent(level)}</{self.name}>" | |
def stringify(self, base_level: int = 0): | |
return "\n".join(self.iter_lines(base_level)) | |
__str__ = stringify | |
def __repr__(self): | |
return f"{self.__class__.__qualname__}({self.name!r})" | |
def append_child(self, other): | |
self.type = Type.Node | |
thing = self.__class__(other, self._level + 1, self._step) | |
self.children.append(thing) | |
return thing | |
__gt__ = __call__ = __add__ = append_child | |
def __radd__(self, other): | |
return other + self.stringify() | |
def __enter__(self): | |
self.type = Type.Node | |
return self | |
def __exit__(self, exc_type, exc_val, exc_tb): | |
pass | |
def __setitem__(self, key, value): | |
self.attributes[key] = value | |
class E(Element): | |
def __enter__(self): | |
Cursor.context.append(self) | |
return Element.__enter__(self) | |
def __exit__(self, exc_type, exc_val, exc_tb): | |
Cursor.context.pop() | |
class Cursor: | |
context: list[E] = [E("")] | |
@property | |
def current(self) -> E: | |
return self.context[-1] | |
def stringify(self): | |
return self.current.children[0].stringify() | |
__str__ = stringify | |
def __add__(self, other): | |
return self.current + other | |
def __call__(self, *args, **kwargs): | |
return self.current(*args, **kwargs) | |
def __gt__(self, other): | |
return self.current > other | |
if __name__ == '__main__': | |
_ = Cursor() | |
with _ > "html": | |
with _ > "head": | |
_("title") + "标题" | |
with _ > "body" as body: | |
with _("img") as img: | |
img["src"] = "图片地址" | |
img["alt"] = "图片标题" | |
with _("div"): | |
for i in range(10): | |
_("p") + f"第{i}句" | |
_("div")("div")("p")("ul")("li") + "还可以链式调用" | |
print(_) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment