Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
rushter committed Oct 9, 2024
2 parents e05d228 + f0825ae commit 714afbe
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/make_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4.1.7
with:
name: artifact
path: dist
Expand Down
40 changes: 40 additions & 0 deletions examples/walkthrough.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,46 @@
"\n",
"print([node.html for node in tree.select('div').css(\"span\").css(\".red\").matches])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Inserting nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"html = \"\"\"\n",
"<div id=\"container\">\n",
" <span class=\"red\"></span>\n",
" <span class=\"green\"></span>\n",
" <span class=\"red\"></span>\n",
" <span class=\"green\"></span>\n",
"</div>\n",
"\"\"\"\n",
"tree = HTMLParser(html)\n",
"\n",
"# Insert text\n",
"dest_node = html_parser.css_first('.red')\n",
"dest_node.insert_before(\"Hello\")\n",
"\n",
"# Insert nodes\n",
"subtree = HTMLParser(\"<div>Hi</div>\")\n",
"dest_node = html_parser.css_first('.red')\n",
"dest_node.insert_before(subtree)\n",
"\n",
"# Insert before, after, or append inside\n",
"subtree = HTMLParser(\"<div>Car</div>\")\n",
"dest_node = html_parser.css_first('.green')\n",
"dest_node.insert_before(subtree)\n",
"dest_node.insert_after(subtree)\n",
"dest_node.insert_child(subtree)"
]
}
],
"metadata": {
Expand Down
51 changes: 51 additions & 0 deletions selectolax/lexbor/node.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,57 @@ cdef class LexborNode:
else:
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)

def insert_child(self, str_or_LexborNode value):
"""
Insert a node inside (at the end of) the current Node.
Parameters
----------
value : str, bytes or Node
The text or Node instance to insert inside the Node.
When a text string is passed, it's treated as text. All HTML tags will be escaped.
Convert and pass the ``Node`` object when you want to work with HTML.
Does not clone the ``Node`` object.
All future changes to the passed ``Node`` object will also be taken into account.
Examples
--------
>>> tree = LexborHTMLParser('<div>Get <img src=""></div>')
>>> div = tree.css_first('div')
>>> div.insert_child('Laptop')
>>> tree.body.child.html
'<div>Get <img src="">Laptop</div>'
>>> html_parser = LexborHTMLParser('<div>Get <span alt="Laptop"> <div>Laptop</div> </span></div>')
>>> html_parser2 = LexborHTMLParser('<div>Test</div>')
>>> span_node = html_parser.css_first('span')
>>> span_node.insert_child(html_parser2.body.child)
<div>Get <span alt="Laptop"> <div>Laptop</div> <div>Test</div> </span></div>'
"""
cdef lxb_dom_node_t * new_node

if isinstance(value, (str, bytes, unicode)):
bytes_val = to_bytes(value)
new_node = <lxb_dom_node_t *> lxb_dom_document_create_text_node(
&self.parser.document.dom_document,
<lxb_char_t *> bytes_val, len(bytes_val)
)
if new_node == NULL:
raise SelectolaxError("Can't create a new node")
lxb_dom_node_insert_child(self.node, new_node)
elif isinstance(value, LexborNode):
new_node = lxb_dom_document_import_node(
&self.parser.document.dom_document,
<lxb_dom_node_t *> value.node,
<bint> True
)
if new_node == NULL:
raise SelectolaxError("Can't create a new node")
lxb_dom_node_insert_child(self.node, <lxb_dom_node_t *> new_node)
else:
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)

@property
def raw_value(self):
"""Return the raw (unparsed, original) value of a node.
Expand Down
40 changes: 40 additions & 0 deletions selectolax/modest/node.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,46 @@ cdef class Node:
else:
raise TypeError("Expected a string or Node instance, but %s found" % type(value).__name__)

def insert_child(self, str_or_Node value):
"""
Insert a node inside (at the end of) the current Node.
Parameters
----------
value : str, bytes or Node
The text or Node instance to insert inside the Node.
When a text string is passed, it's treated as text. All HTML tags will be escaped.
Convert and pass the ``Node`` object when you want to work with HTML.
Does not clone the ``Node`` object.
All future changes to the passed ``Node`` object will also be taken into account.
Examples
--------
>>> tree = HTMLParser('<div>Get <img src=""></div>')
>>> div = tree.css_first('div')
>>> div.insert_child('Laptop')
>>> tree.body.child.html
'<div>Get <img src="">Laptop</div>'
>>> html_parser = HTMLParser('<div>Get <span alt="Laptop"> <div>Laptop</div> </span></div>')
>>> html_parser2 = HTMLParser('<div>Test</div>')
>>> span_node = html_parser.css_first('span')
>>> span_node.insert_child(html_parser2.body.child)
<div>Get <span alt="Laptop"> <div>Laptop</div> <div>Test</div> </span></div>'
"""
cdef myhtml_tree_node_t *node
if isinstance(value, (str, bytes, unicode)):
bytes_val = to_bytes(value)
node = myhtml_node_create(self.parser.html_tree, MyHTML_TAG__TEXT, MyHTML_NAMESPACE_HTML)
myhtml_node_text_set(node, <char*> bytes_val, len(bytes_val), MyENCODING_UTF_8)
myhtml_node_append_child(self.node, node)
elif isinstance(value, Node):
node = myhtml_node_clone_deep(self.parser.html_tree, <myhtml_tree_node_t *> value.node)
myhtml_node_append_child(self.node, node)
else:
raise TypeError("Expected a string or Node instance, but %s found" % type(value).__name__)

def unwrap_tags(self, list tags):
"""Unwraps specified tags from the HTML tree.
Expand Down
19 changes: 19 additions & 0 deletions tests/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,25 @@ def test_node_insert_after(parser):
== '<div>Get <span alt="Laptop"><img src="/jpg"><div>Test</div> <div></div></span></div>')


@pytest.mark.parametrize(*_PARSERS_PARAMETRIZER)
def test_insert_child(parser):
html_parser = parser('<div>Get <img src=""></div>')
div = html_parser.css_first('div')
div.insert_child('Laptop')
assert html_parser.body.child.html == '<div>Get <img src="">Laptop</div>'


@pytest.mark.parametrize(*_PARSERS_PARAMETRIZER)
def test_node_insert_child(parser):
html_parser = parser('<div>Get <span alt="Laptop"> <div>Laptop</div> </span></div>')
html_parser2 = parser('<div>Test</div>')
span_node = html_parser.css_first('span')
span_node.insert_child(html_parser2.body.child)
assert (
html_parser.body.child.html
== '<div>Get <span alt="Laptop"> <div>Laptop</div> <div>Test</div></span></div>')


@pytest.mark.parametrize(*_PARSERS_PARAMETRIZER)
def test_attrs_adds_attribute(parser):
html_parser = parser('<div id="id"></div>')
Expand Down

0 comments on commit 714afbe

Please sign in to comment.