Skip to content

Commit 6111558

Browse files
committed
Change the QualName.__repr__ and Element.__repr__ returning format and update docs
1 parent e6a416b commit 6111558

File tree

7 files changed

+313
-17
lines changed

7 files changed

+313
-17
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ crate-type = ["cdylib"]
1717
members = ["treedom", "matching"]
1818

1919
[workspace.package]
20-
version = "0.1.0"
20+
version = "0.1.1"
2121
edition = "2021"
2222
readme = "README.md"
2323
license = "MIT"

docs/docs/parser.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ root
177177
# Document
178178

179179
root.select_one("bookstore")
180-
# Element(name=QualName(local="bookstore", ns="", prefix=None), attrs=[], template=false, mathml_annotation_xml_integration_point=false)
180+
# Element(name=QualName(local="bookstore"), attrs=[], template=false, mathml_annotation_xml_integration_point=false)
181181

182182
for i in root.select("mag|*"): # get all elements which has namespace 'mag'
183183
print(i)

docs/docs/reference.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/docs/treedom.md

Lines changed: 297 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,301 @@
22
title: DOM Usage
33
---
44

5-
# TreeDom
5+
# DOM Usage
66

7-
Comming Soon ...
7+
8+
<div class="grid cards" markdown>
9+
10+
- :simple-buildkite:{ .lg } - __Build A Document__
11+
12+
---
13+
14+
In **MarkupEver**, we use a class named `TreeDom` (1) as a tree structure. This class allows you to ...
15+
16+
[More :material-arrow-top-right:](#build-a-document)
17+
18+
- :material-navigation-variant-outline:{ .lg } - __Navigating the tree__
19+
20+
---
21+
22+
The most important thing in trees is navigating between elements and how to interact with them ...
23+
24+
[More :material-arrow-top-right:](#navigating-the-tree)
25+
26+
</div>
27+
28+
29+
## Navigating the tree
30+
The most important thing in trees is navigating between elements and how to interact with them — specially after parsing a document.
31+
32+
Each node may contain text and other nodes. **MarkupEver** provides numerous properties, methods, and iterators to help you work with and navigate between them.
33+
34+
!!! note
35+
36+
We won't discuss .select and .select_one here. They are introduced in [Parsing](./parser.md) and [Querying](./querying.md).
37+
38+
Imagine this to start:
39+
40+
```python
41+
import markupever
42+
43+
dom: markupever.dom.TreeDom = markupever.parse(
44+
"""
45+
<note><to>Tove</to>
46+
<from>Jani</from>
47+
<heading>Reminder</heading>
48+
<body>Don't forget me this weekend!</body></note>
49+
""",
50+
markupever.XmlOptions()
51+
)
52+
root = dom.root()
53+
54+
# Document
55+
# └── Element(name=QualName(local="note"), attrs=[], template=false, integration_point=false)
56+
# ├── Element(name=QualName(local="to"), attrs=[], template=false, integration_point=false)
57+
# │ └── Text(content="Tove")
58+
# ├── Text(content="\n ")
59+
# ├── Element(name=QualName(local="from"), attrs=[], template=false, integration_point=false)
60+
# │ └── Text(content="Jani")
61+
# ├── Text(content="\n ")
62+
# ├── Element(name=QualName(local="heading"), attrs=[], template=false, integration_point=false)
63+
# │ └── Text(content="Reminder")
64+
# ├── Text(content="\n ")
65+
# └── Element(name=QualName(local="body"), attrs=[], template=false, integration_point=false)
66+
# └── Text(content="Don't forget me this weekend!")
67+
```
68+
69+
Let's discuss about `first_child`, `last_child`, `parent`, `next_sibling` and `prev_sibling` properties:
70+
71+
* **first_child**: This property retrieves the first child node of the given element. If the element has no children, it returns `None`.
72+
73+
* **last_child**: This property retrieves the last child node of the given element. If the element has no children, it returns `None`.
74+
75+
* **parent**: This property retrieves the parent node of the given element. If the element has no parent (e.g., it's the root), it returns `None`.
76+
77+
* **next_sibling**: This property retrieves the next sibling node of the given element. If there is no next sibling, it returns `None`.
78+
79+
* **prev_sibling**: This property retrieves the previous sibling node of the given element. If there is no previous sibling, it returns `None`.
80+
81+
=== "`first_child`"
82+
83+
```python
84+
root.first_child
85+
# Element(name=QualName(local="note"), attrs=[], template=false, integration_point=false)
86+
87+
root.first_child.first_child
88+
# Element(name=QualName(local="to"), attrs=[], template=false, integration_point=false)
89+
```
90+
91+
=== "`last_child`"
92+
93+
```python
94+
root.last_child
95+
# Element(name=QualName(local="note"), attrs=[], template=false, integration_point=false)
96+
97+
root.last_child.last_child
98+
# Element(name=QualName(local="body"), attrs=[], template=false, integration_point=false)
99+
```
100+
101+
=== "`parent`"
102+
103+
```python
104+
note_element = root.first_child
105+
# Element(name=QualName(local="note"), attrs=[], template=false, integration_point=false)
106+
107+
note_element.parent
108+
# Document
109+
110+
note_element.parent == root
111+
# True
112+
```
113+
114+
=== "`next_sibling`"
115+
116+
```python
117+
root.next_sibling
118+
# None
119+
120+
root.first_child.next_sibling
121+
# None
122+
123+
root.first_child.first_child
124+
# Element(name=QualName(local="body"), attrs=[], template=false, integration_point=false)
125+
126+
root.first_child.first_child.next_sibling
127+
# Text(content="\n ")
128+
```
129+
130+
=== "`prev_sibling`"
131+
132+
```python
133+
root.next_sibling
134+
# None
135+
136+
root.first_child.prev_sibling
137+
# None
138+
139+
root.first_child.last_children
140+
# Element(name=QualName(local="to"), attrs=[], template=false, integration_point=false)
141+
142+
root.first_child.first_child.prev_sibling
143+
# Text(content="\n ")
144+
```
145+
146+
"While these properties are useful, they might not always meet our needs. In such cases, methods like `.children()`, `.ancestors()`, `.prev_siblings()`, `.next_siblings()`, `.first_children()`, `.last_children()`, `.traverse()`, and `.descendants()` can provide additional functionality.
147+
148+
...
149+
150+
## Build a document
151+
In **MarkupEver**, we use a class named `TreeDom` (1) as a tree structure. This class allows you to work with the document — move, create, remove, select, serialize, and more. In this tutorial, <u>we'll create a document without using the `Parser` class</u>. We'll focus on `TreeDom` properties and methods.
152+
{ .annotate }
153+
154+
1. A tree structure which specialy designed for HTML and XML documents. Uses Rust's `Vec` type in backend.
155+
The memory consumed by the `TreeDom` is dynamic and depends on the number of tokens stored in the tree.
156+
The allocated memory is never reduced and is only released when it is dropped.
157+
158+
### Start
159+
To start creating a document, we first need to create a `TreeDom`.
160+
161+
```python
162+
>>> from markupever import dom
163+
>>> tree = dom.TreeDom()
164+
```
165+
166+
Each `TreeDom` always has a root node of the `dom.Document` type. We can access it using the `.root()` method.
167+
168+
```python hl_lines="4"
169+
>>> from markupever import dom
170+
>>> tree = dom.TreeDom()
171+
>>>
172+
>>> root = tree.root() # type is dom.Document
173+
>>> root
174+
Document
175+
```
176+
177+
!!! tip "Be Careful"
178+
179+
Avoid using `is` for node types in `markupever.dom` (such as `Document`, `Element`, `Text`, etc.) because they are not alive and serve only as a bridge for you to communicate with the core written in **Rust**.
180+
181+
```python
182+
>>> root = tree.root()
183+
>>> root is tree.root()
184+
False
185+
```
186+
187+
### Adding nodes
188+
`dom.Document` and `dom.Element` types have methods start with `create_`. These are help you to create and add new nodes to
189+
document. Let's add a DOCTYPE to our document:
190+
191+
```python hl_lines="4"
192+
>>> from markupever import dom
193+
>>> tree = dom.TreeDom()
194+
>>>
195+
>>> tree.root().create_doctype("html")
196+
Doctype(name="html", public_id="", system_id="")
197+
```
198+
199+
Let's check what we did by printing or serializing the tree:
200+
```python
201+
>>> print(tree)
202+
Document
203+
└── Doctype(name="html", public_id="", system_id="")
204+
205+
>>> tree.serialize(is_html=True)
206+
'<!DOCTYPE html>'
207+
```
208+
209+
OK. Let's add some elements and check again:
210+
```python
211+
>>> html = tree.root().create_element("html", {"lang": "en"}) # type is dom.Element
212+
>>> html.create_element("body")
213+
Element(name=QualName(local="body", ns="", prefix=None), attrs=[], template=false, integration_point=false)
214+
215+
>>> print(tree)
216+
Document
217+
└── Element(name=QualName(local="html", ns="", prefix=None), attrs=[(QualName(local="lang", ns="", prefix=None), "en")], template=false, integration_point=false)
218+
└── Element(name=QualName(local="body", ns="", prefix=None), attrs=[], template=false, integration_point=false)
219+
220+
>>> tree.serialize(is_html=True)
221+
'<!DOCTYPE html><html lang="en"><body></body></html>'
222+
```
223+
224+
This is very easy as you can see ...
225+
226+
### Ordering
227+
The `create_*` methods allow you to perform append, prepend, insert after, and insert before operations within the document.
228+
229+
* **append** means adding a child as the last child of a node (default).
230+
* **prepend** means adding a child as the first child of a node.
231+
* **insert after** means adding a node as the next sibling of another node.
232+
* **insert before** means adding a node as the previous sibling of another node.
233+
234+
You can specify the operation with `dom.Ordering` class and the `ordering` parameter in the `create_*` methods.
235+
236+
=== "Append"
237+
238+
```python hl_lines="9"
239+
from markupever import dom
240+
tree = dom.TreeDom()
241+
root = tree.root()
242+
243+
root.create_element("child1")
244+
# document
245+
# └── child1
246+
247+
root.create_element("child2", ordering=dom.Ordering.APPEND)
248+
# document
249+
# ├── child1
250+
# └── child2
251+
```
252+
253+
=== "Prepend"
254+
255+
```python hl_lines="9"
256+
from markupever import dom
257+
tree = dom.TreeDom()
258+
root = tree.root()
259+
260+
root.create_element("child1")
261+
# document
262+
# └── child1
263+
264+
root.create_element("child2", ordering=dom.Ordering.PREPEND)
265+
# document
266+
# ├── child2
267+
# └── child1
268+
```
269+
270+
=== "Insert After"
271+
272+
```python hl_lines="9"
273+
from markupever import dom
274+
tree = dom.TreeDom()
275+
root = tree.root()
276+
277+
child = root.create_element("child")
278+
# document
279+
# └── child
280+
281+
child.create_element("sibling", ordering=dom.Ordering.AFTER)
282+
# document
283+
# ├── child
284+
# └── sibling
285+
```
286+
287+
=== "Insert Before"
288+
289+
```python hl_lines="9"
290+
from markupever import dom
291+
tree = dom.TreeDom()
292+
root = tree.root()
293+
294+
child = root.create_element("child")
295+
# document
296+
# └── child
297+
298+
child.create_element("sibling", ordering=dom.Ordering.BEFORE)
299+
# document
300+
# ├── sibling
301+
# └── child
302+
```

docs/mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,3 @@ nav:
7575
- parser.md
7676
- treedom.md
7777
- querying.md
78-
- reference.md

src/nodes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,7 +1449,7 @@ impl PyElement {
14491449
let elem = node.value().element().unwrap();
14501450

14511451
format!(
1452-
"Element(name={}, attrs={}, template={}, mathml_annotation_xml_integration_point={})",
1452+
"Element(name={}, attrs={}, template={}, integration_point={})",
14531453
super::qualname::repr_qualname(&elem.name),
14541454
repr_attrlist(elem),
14551455
elem.template,

src/qualname.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ use std::hash::Hasher;
22

33
#[inline(always)]
44
pub(super) fn repr_qualname(q: &treedom::markup5ever::QualName) -> String {
5-
format!(
6-
"QualName(local={:?}, ns={:?}, prefix={:?})",
7-
q.local.as_ref(),
8-
q.ns.as_ref(),
9-
q.prefix.as_ref().map(|x| x.as_ref())
10-
)
5+
if q.ns.is_empty() && q.prefix.is_none() {
6+
format!(
7+
"QualName(local={:?})",
8+
q.local.as_ref(),
9+
)
10+
} else {
11+
format!(
12+
"QualName(local={:?}, ns={:?}, prefix={:?})",
13+
q.local.as_ref(),
14+
q.ns.as_ref(),
15+
q.prefix.as_ref().map(|x| x.as_ref())
16+
)
17+
}
1118
}
1219

1320
/// A fully qualified name (with a namespace), used to depict names of tags and attributes.

0 commit comments

Comments
 (0)