DESCRIPTION.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. Dominate
  2. ========
  3. `Dominate` is a Python library for creating and manipulating HTML documents using an elegant DOM API.
  4. It allows you to write HTML pages in pure Python very concisely, which eliminates the need to learn another template language, and lets you take advantage of the more powerful features of Python.
  5. Python:
  6. ```python
  7. import dominate
  8. from dominate.tags import *
  9. doc = dominate.document(title='Dominate your HTML')
  10. with doc.head:
  11. link(rel='stylesheet', href='style.css')
  12. script(type='text/javascript', src='script.js')
  13. with doc:
  14. with div(id='header').add(ol()):
  15. for i in ['home', 'about', 'contact']:
  16. li(a(i.title(), href='/%s.html' % i))
  17. with div():
  18. attr(cls='body')
  19. p('Lorem ipsum..')
  20. print(doc)
  21. ```
  22. Output:
  23. ```html
  24. <!DOCTYPE html>
  25. <html>
  26. <head>
  27. <title>Dominate your HTML</title>
  28. <link href="style.css" rel="stylesheet">
  29. <script src="script.js" type="text/javascript"></script>
  30. </head>
  31. <body>
  32. <div id="header">
  33. <ol>
  34. <li>
  35. <a href="/home.html">Home</a>
  36. </li>
  37. <li>
  38. <a href="/about.html">About</a>
  39. </li>
  40. <li>
  41. <a href="/contact.html">Contact</a>
  42. </li>
  43. </ol>
  44. </div>
  45. <div class="body">
  46. <p>Lorem ipsum..</p>
  47. </div>
  48. </body>
  49. </html>
  50. ```
  51. Compatibility
  52. -------------
  53. `Dominate` is compatible with both Python 2.7 and Python 3.3. There are known issues with Python 3.2 and below.
  54. [![Build Status](https://travis-ci.org/Knio/dominate.png?branch=master)](https://travis-ci.org/Knio/dominate)
  55. [![Coverage Status](https://coveralls.io/repos/Knio/dominate/badge.png?branch=master)](https://coveralls.io/r/Knio/dominate?branch=master)
  56. Installation
  57. ------------
  58. The recommended way to install `dominate` is with
  59. [`pip`](http://pypi.python.org/pypi/pip/):
  60. sudo pip install dominate
  61. [![PyPI version](https://badge.fury.io/py/dominate.png)](http://badge.fury.io/py/dominate)
  62. Developed By
  63. ------------
  64. * Tom Flanagan - <tom@zkpq.ca>
  65. * Jake Wharton - <jakewharton@gmail.com>
  66. * [Brad Janke](//github.com/bradj)
  67. Git repository located at
  68. [github.com/Knio/dominate](//github.com/Knio/dominate)
  69. Examples
  70. ========
  71. All examples assume you have imported the appropriate tags or entire tag set:
  72. ```python
  73. from dominate.tags import *
  74. ```
  75. Hello, World!
  76. -------------
  77. The most basic feature of `dominate` exposes a class for each HTML element, where the constructor
  78. accepts child elements, text, or keyword attributes. `dominate` nodes return their HTML representation
  79. from the `__str__`, `__unicode__`, and `render()` methods.
  80. ```python
  81. print(html(body(h1('Hello, World!'))))
  82. ```
  83. ```html
  84. <html>
  85. <body>
  86. <h1>Hello, World!</h1>
  87. </body>
  88. </html>
  89. ```
  90. Attributes
  91. ----------
  92. `Dominate` can also use keyword arguments to append attributes onto your tags. Most of the attributes are a direct copy from the HTML spec with a few variations.
  93. For attributes `class` and `for` which conflict with Python's [reserved keywords](http://docs.python.org/2/reference/lexical_analysis.html#keywords "Reserved Keywords"), you can use the following aliases:
  94. | class | for |
  95. |-------|-----|
  96. |_class | _for |
  97. |cls | fr |
  98. |className|htmlFor|
  99. |class_name|html_for|
  100. ```python
  101. test = label(cls='classname anothername', fr='someinput')
  102. print(test)
  103. ```
  104. ```html
  105. <label class="classname anothername" for="someinput"></label>
  106. ```
  107. Use `data_*` for [custom HTML5 data attributes](http://www.w3.org/html/wg/drafts/html/master/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes "HTML5 Data Attributes").
  108. ```python
  109. test = div(data_employee='101011')
  110. print(test)
  111. ```
  112. ```html
  113. <div data-employee="101011"></div>
  114. ```
  115. You can also modify the attributes of tags through a dictionary-like interface:
  116. ```python
  117. header = div()
  118. header['id'] = 'header'
  119. print(header)
  120. ```
  121. ```html
  122. <div id="header"></div>
  123. ```
  124. Complex Structures
  125. ------------------
  126. Through the use of the `+=` operator and the `.add()` method you can easily create more advanced structures.
  127. Create a simple list:
  128. ```python
  129. list = ul()
  130. for item in range(4):
  131. list += li('Item #', item)
  132. print(list)
  133. ```
  134. ```html
  135. <ul>
  136. <li>Item #0</li>
  137. <li>Item #1</li>
  138. <li>Item #2</li>
  139. <li>Item #3</li>
  140. </ul>
  141. ```
  142. `dominate` supports iterables to help streamline your code:
  143. ```python
  144. print(ul(li(a(name, href=link), __pretty=False) for name, link in menu_items))
  145. ```
  146. ```html
  147. <ul>
  148. <li><a href="/home/">Home</a></li>
  149. <li><a href="/about/">About</a></li>
  150. <li><a href="/downloads/">Downloads</a></li>
  151. <li><a href="/links/">Links</a></li>
  152. </ul>
  153. ```
  154. A simple document tree:
  155. ```python
  156. _html = html()
  157. _body = _html.add(body())
  158. header = _body.add(div(id='header'))
  159. content = _body.add(div(id='content'))
  160. footer = _body.add(div(id='footer'))
  161. print(_html)
  162. ```
  163. ```html
  164. <html>
  165. <body>
  166. <div id="header"></div>
  167. <div id="content"></div>
  168. <div id="footer"></div>
  169. </body>
  170. </html>
  171. ```
  172. For clean code, the `.add()` method returns children in tuples. The above example can be cleaned up and expanded like this:
  173. ```python
  174. _html = html()
  175. _head, _body = _html.add(head(title('Simple Document Tree')), body())
  176. names = ['header', 'content', 'footer']
  177. header, content, footer = _body.add(div(id=name) for name in names)
  178. print(_html)
  179. ```
  180. ```html
  181. <html>
  182. <head>
  183. <title>Simple Document Tree</title>
  184. </head>
  185. <body>
  186. <div id="header"></div>
  187. <div id="content"></div>
  188. <div id="footer"></div>
  189. </body>
  190. </html>
  191. ```
  192. You can modify the attributes of tags through a dictionary-like interface:
  193. ```python
  194. header = div()
  195. header['id'] = 'header'
  196. print(header)
  197. ```
  198. ```html
  199. <div id="header"></div>
  200. ```
  201. Or the children of a tag though an array-line interface:
  202. ```python
  203. header = div('Test')
  204. header[0] = 'Hello World'
  205. print(header)
  206. ```
  207. ```html
  208. <div>Hello World</div>
  209. ```
  210. Comments can be created using objects too!
  211. ```python
  212. print(comment('BEGIN HEADER'))
  213. ```
  214. ```html
  215. <!--BEGIN HEADER-->
  216. ```
  217. ```python
  218. print(comment(p('Upgrade to newer IE!'), condition='lt IE9'))
  219. ```
  220. ```html
  221. <!--[if lt IE9]>
  222. <p>Upgrade to newer IE!</p>
  223. <![endif]-->
  224. ```
  225. Rendering
  226. ---------
  227. By default, `render()` tries to make all output human readable, with one HTML
  228. element per line and two spaces of indentation.
  229. This behavior can be controlled by the `__pretty` (default: `True` except for
  230. certain element types like `pre`) attribute when creating an element, and by
  231. the `pretty` (default: `True`), `indent` (default: ` `) and `xhtml` (default: `False`)
  232. arguments to `render()`. Rendering options propagate to all descendant nodes.
  233. ```python
  234. a = div(span('Hello World'))
  235. print(a.render())
  236. ```
  237. ```html
  238. <div>
  239. <span>Hello World</span>
  240. </div>
  241. ```
  242. ```python
  243. print(a.render(pretty=False))
  244. ```
  245. ```html
  246. <div><span>Hello World</span></div>
  247. ```
  248. ```python
  249. print(a.render(indent='\t'))
  250. ```
  251. ```html
  252. <div>
  253. <span>Hello World</span>
  254. </div>
  255. ```
  256. ```python
  257. a = div(span('Hello World'), __pretty=False)
  258. print(a.render())
  259. ```
  260. ```html
  261. <div><span>Hello World</span></div>
  262. ```
  263. ```python
  264. d = div()
  265. with d:
  266. hr()
  267. p("Test")
  268. br()
  269. print(d.render())
  270. print(d.render(xhtml=True))
  271. ```
  272. ```html
  273. <div>
  274. <hr>
  275. <p>Test</p><br>
  276. </div>
  277. <div>
  278. <hr />
  279. <p>Test</p><br />
  280. </div>
  281. ```
  282. Context Managers
  283. ----------------
  284. You can also add child elements using Python's `with` statement:
  285. ```python
  286. h = ul()
  287. with h:
  288. li('One')
  289. li('Two')
  290. li('Three')
  291. print(h)
  292. ```
  293. ```html
  294. <ul>
  295. <li>One</li>
  296. <li>Two</li>
  297. <li>Three</li>
  298. </ul>
  299. ```
  300. You can use this along with the other mechanisms of adding children elements, including nesting `with` statements, and it works as expected:
  301. ```python
  302. h = html()
  303. with h.add(body()).add(div(id='content')):
  304. h1('Hello World!')
  305. p('Lorem ipsum ...')
  306. with table().add(tbody()):
  307. l = tr()
  308. l += td('One')
  309. l.add(td('Two'))
  310. with l:
  311. td('Three')
  312. print(h)
  313. ```
  314. ```html
  315. <html>
  316. <body>
  317. <div id="content">
  318. <h1>Hello World!</h1>
  319. <p>Lorem ipsum ...</p>
  320. <table>
  321. <tbody>
  322. <tr>
  323. <td>One</td>
  324. <td>Two</td>
  325. <td>Three</td>
  326. </tr>
  327. </tbody>
  328. </table>
  329. </div>
  330. </body>
  331. </html>
  332. ```
  333. When the context is closed, any nodes that were not already added to something get added to the current context.
  334. Attributes can be added to the current context with the `attr` function:
  335. ```python
  336. d = div()
  337. with d:
  338. attr(id='header')
  339. print(d)
  340. ```
  341. ```html
  342. <div id="header"></div>
  343. ```
  344. Decorators
  345. ----------
  346. `Dominate` is great for creating reusable widgets for parts of your page. Consider this example:
  347. ```python
  348. def greeting(name):
  349. with div() as d:
  350. p('Hello, %s' % name)
  351. return d
  352. print(greeting('Bob'))
  353. ```
  354. ```html
  355. <div>
  356. <p>Hello, Bob</p>
  357. </div>
  358. ```
  359. You can see the following pattern being repeated here:
  360. ```python
  361. def widget(parameters):
  362. with tag() as t:
  363. ...
  364. return t
  365. ```
  366. This boilerplate can be avoided by using tags (objects and instances) as decorators
  367. ```python
  368. @div
  369. def greeting(name):
  370. p('Hello %s' % name)
  371. print(greeting('Bob'))
  372. ```
  373. ```html
  374. <div>
  375. <p>Hello Bob</p>
  376. </div>
  377. ```
  378. The decorated function will return a new instance of the tag used to decorate it, and execute in a `with` context which will collect all the nodes created inside it.
  379. You can also use instances of tags as decorators, if you need to add attributes or other data to the root node of the widget.
  380. Each call to the decorated function will return a copy of the node used to decorate it.
  381. ```python
  382. @div(h2('Welcome'), cls='greeting')
  383. def greeting(name):
  384. p('Hello %s' % name)
  385. print(greeting('Bob'))
  386. ```
  387. ```html
  388. <div class="greeting">
  389. <h2>Welcome</h2>
  390. <p>Hello Bob</p>
  391. </div>
  392. ```
  393. Creating Documents
  394. ------------------
  395. Since creating the common structure of an HTML document everytime would be excessively tedious dominate provides a class to create and manage them for you: `document`.
  396. When you create a new document, the basic HTML tag structure is created for you.
  397. ```python
  398. d = document()
  399. print(d)
  400. ```
  401. ```html
  402. <!DOCTYPE html>
  403. <html>
  404. <head>
  405. <title>Dominate</title>
  406. </head>
  407. <body></body>
  408. </html>
  409. ```
  410. The `document` class accepts `title`, `doctype`, and `request` keyword arguments.
  411. The default values for these arguments are `Dominate`, `<!DOCTYPE html>`, and `None` respectively.
  412. The `document` class also provides helpers to allow you to access the `html`, `head`, and `body` nodes directly.
  413. ```python
  414. d = document()
  415. ```
  416. ```python
  417. >>> d.html
  418. <dominate.tags.html: 0 attributes, 2 children>
  419. >>> d.head
  420. <dominate.tags.head: 0 attributes, 0 children>
  421. >>> d.body
  422. <dominate.tags.body: 0 attributes, 0 children>
  423. ```
  424. You should notice that here the `head` tag contains zero children.
  425. This is because the default `title` tag is only added when the document is rendered and the `head` element does not explicitly contain one.
  426. The `document` class also provides helpers to allow you to directly add nodes to the `body` tag.
  427. ```python
  428. d = document()
  429. d += h1('Hello, World!')
  430. d += p('This is a paragraph.')
  431. print(d)
  432. ```
  433. ```html
  434. <!DOCTYPE html>
  435. <html>
  436. <head>
  437. <title>Dominate</title>
  438. </head>
  439. <body>
  440. <h1>Hello, World!</h1>
  441. <p>This is a paragraph.</p>
  442. </body>
  443. </html>
  444. ```