Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/lxml/builder.py
811 views
1
# cython: language_level=2
2
3
#
4
# Element generator factory by Fredrik Lundh.
5
#
6
# Source:
7
# http://online.effbot.org/2006_11_01_archive.htm#et-builder
8
# http://effbot.python-hosting.com/file/stuff/sandbox/elementlib/builder.py
9
#
10
# --------------------------------------------------------------------
11
# The ElementTree toolkit is
12
#
13
# Copyright (c) 1999-2004 by Fredrik Lundh
14
#
15
# By obtaining, using, and/or copying this software and/or its
16
# associated documentation, you agree that you have read, understood,
17
# and will comply with the following terms and conditions:
18
#
19
# Permission to use, copy, modify, and distribute this software and
20
# its associated documentation for any purpose and without fee is
21
# hereby granted, provided that the above copyright notice appears in
22
# all copies, and that both that copyright notice and this permission
23
# notice appear in supporting documentation, and that the name of
24
# Secret Labs AB or the author not be used in advertising or publicity
25
# pertaining to distribution of the software without specific, written
26
# prior permission.
27
#
28
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
29
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
30
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
31
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
32
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
33
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
34
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
35
# OF THIS SOFTWARE.
36
# --------------------------------------------------------------------
37
38
"""
39
The ``E`` Element factory for generating XML documents.
40
"""
41
42
from __future__ import absolute_import
43
44
import lxml.etree as ET
45
46
from functools import partial
47
48
try:
49
basestring
50
except NameError:
51
basestring = str
52
53
try:
54
unicode
55
except NameError:
56
unicode = str
57
58
59
class ElementMaker(object):
60
"""Element generator factory.
61
62
Unlike the ordinary Element factory, the E factory allows you to pass in
63
more than just a tag and some optional attributes; you can also pass in
64
text and other elements. The text is added as either text or tail
65
attributes, and elements are inserted at the right spot. Some small
66
examples::
67
68
>>> from lxml import etree as ET
69
>>> from lxml.builder import E
70
71
>>> ET.tostring(E("tag"))
72
'<tag/>'
73
>>> ET.tostring(E("tag", "text"))
74
'<tag>text</tag>'
75
>>> ET.tostring(E("tag", "text", key="value"))
76
'<tag key="value">text</tag>'
77
>>> ET.tostring(E("tag", E("subtag", "text"), "tail"))
78
'<tag><subtag>text</subtag>tail</tag>'
79
80
For simple tags, the factory also allows you to write ``E.tag(...)`` instead
81
of ``E('tag', ...)``::
82
83
>>> ET.tostring(E.tag())
84
'<tag/>'
85
>>> ET.tostring(E.tag("text"))
86
'<tag>text</tag>'
87
>>> ET.tostring(E.tag(E.subtag("text"), "tail"))
88
'<tag><subtag>text</subtag>tail</tag>'
89
90
Here's a somewhat larger example; this shows how to generate HTML
91
documents, using a mix of prepared factory functions for inline elements,
92
nested ``E.tag`` calls, and embedded XHTML fragments::
93
94
# some common inline elements
95
A = E.a
96
I = E.i
97
B = E.b
98
99
def CLASS(v):
100
# helper function, 'class' is a reserved word
101
return {'class': v}
102
103
page = (
104
E.html(
105
E.head(
106
E.title("This is a sample document")
107
),
108
E.body(
109
E.h1("Hello!", CLASS("title")),
110
E.p("This is a paragraph with ", B("bold"), " text in it!"),
111
E.p("This is another paragraph, with a ",
112
A("link", href="http://www.python.org"), "."),
113
E.p("Here are some reserved characters: <spam&egg>."),
114
ET.XML("<p>And finally, here is an embedded XHTML fragment.</p>"),
115
)
116
)
117
)
118
119
print ET.tostring(page)
120
121
Here's a prettyprinted version of the output from the above script::
122
123
<html>
124
<head>
125
<title>This is a sample document</title>
126
</head>
127
<body>
128
<h1 class="title">Hello!</h1>
129
<p>This is a paragraph with <b>bold</b> text in it!</p>
130
<p>This is another paragraph, with <a href="http://www.python.org">link</a>.</p>
131
<p>Here are some reserved characters: &lt;spam&amp;egg&gt;.</p>
132
<p>And finally, here is an embedded XHTML fragment.</p>
133
</body>
134
</html>
135
136
For namespace support, you can pass a namespace map (``nsmap``)
137
and/or a specific target ``namespace`` to the ElementMaker class::
138
139
>>> E = ElementMaker(namespace="http://my.ns/")
140
>>> print(ET.tostring( E.test ))
141
<test xmlns="http://my.ns/"/>
142
143
>>> E = ElementMaker(namespace="http://my.ns/", nsmap={'p':'http://my.ns/'})
144
>>> print(ET.tostring( E.test ))
145
<p:test xmlns:p="http://my.ns/"/>
146
"""
147
148
def __init__(self, typemap=None,
149
namespace=None, nsmap=None, makeelement=None):
150
if namespace is not None:
151
self._namespace = '{' + namespace + '}'
152
else:
153
self._namespace = None
154
155
if nsmap:
156
self._nsmap = dict(nsmap)
157
else:
158
self._nsmap = None
159
160
if makeelement is not None:
161
assert callable(makeelement)
162
self._makeelement = makeelement
163
else:
164
self._makeelement = ET.Element
165
166
# initialize type map for this element factory
167
168
if typemap:
169
typemap = dict(typemap)
170
else:
171
typemap = {}
172
173
def add_text(elem, item):
174
try:
175
elem[-1].tail = (elem[-1].tail or "") + item
176
except IndexError:
177
elem.text = (elem.text or "") + item
178
179
def add_cdata(elem, cdata):
180
if elem.text:
181
raise ValueError("Can't add a CDATA section. Element already has some text: %r" % elem.text)
182
elem.text = cdata
183
184
if str not in typemap:
185
typemap[str] = add_text
186
if unicode not in typemap:
187
typemap[unicode] = add_text
188
if ET.CDATA not in typemap:
189
typemap[ET.CDATA] = add_cdata
190
191
def add_dict(elem, item):
192
attrib = elem.attrib
193
for k, v in item.items():
194
if isinstance(v, basestring):
195
attrib[k] = v
196
else:
197
attrib[k] = typemap[type(v)](None, v)
198
if dict not in typemap:
199
typemap[dict] = add_dict
200
201
self._typemap = typemap
202
203
def __call__(self, tag, *children, **attrib):
204
typemap = self._typemap
205
206
if self._namespace is not None and tag[0] != '{':
207
tag = self._namespace + tag
208
elem = self._makeelement(tag, nsmap=self._nsmap)
209
if attrib:
210
typemap[dict](elem, attrib)
211
212
for item in children:
213
if callable(item):
214
item = item()
215
t = typemap.get(type(item))
216
if t is None:
217
if ET.iselement(item):
218
elem.append(item)
219
continue
220
for basetype in type(item).__mro__:
221
# See if the typemap knows of any of this type's bases.
222
t = typemap.get(basetype)
223
if t is not None:
224
break
225
else:
226
raise TypeError("bad argument type: %s(%r)" %
227
(type(item).__name__, item))
228
v = t(elem, item)
229
if v:
230
typemap.get(type(v))(elem, v)
231
232
return elem
233
234
def __getattr__(self, tag):
235
return partial(self, tag)
236
237
238
# create factory object
239
E = ElementMaker()
240
241