Original Article: PyMeld
Author: Entrian Solutions

PyMeld

Um sistema simples e leve para manipular HTML (e XML, informalmente) usando um modelo de objeto Pythonic. PyMeld é um único módulo Python, PyMeld.py.

Características:

  • Permite que a lógica do programa eo HTML sejam completamente separados - um designer gráfico pode projetar o HTML em um editor HTML visual, sem precisar lidar com nenhuma sintaxe não padrão ou nomes de atributos não padrão. O código do programa não sabe nada sobre XML ou HTML - apenas trata de objetos e atributos como qualquer outra parte do código Python.
  • Projetado com tarefas comuns de programação de aplicativos HTML em mente. Preencher um formulário HTML com um registro de um banco de dados é um one-liner (usando o operador % - veja abaixo). Construir uma tabela HTML de um conjunto de registros é tão fácil, como mostrado no exemplo abaixo.
  • Não são necessários requisitos especiais para o HTML / XML (ou apenas um: os valores dos atributos devem ser citados) - para que você possa usar qualquer editor e seu HTML / XML não precisa ser estritamente válido.
  • Funciona por substituição de cadeias, ao invés de decompor e reconstruir a marcação, portanto, não tem impacto nas partes da página que você não manipula.
  • Does nothing but manipulating HTML/XML, hence fits in with any other Web toolkits you're using.
  • Tracebacks sempre apontam para o lugar certo - muitos sistemas de mistura Python / HTML usam exec ou eval, dificultando o rastreamento dos erros.

Visão geral rápida

Um objeto PyMeld.Meld representa um documento XML, ou um pedaço de um. Todos os elementos em um documento com id=name os atributos são disponibilizados por um objeto Meld como object.name. Os atributos dos elementos estão disponíveis da mesma maneira. Um exemplo breve vale mais do que mil palavras:

>>> from PyMeld import Meld
>>> xhtml = '''<html><body>
... <textarea id="message" rows="2" wrap="off">Type your message.</textarea>
... </body></html>'''
>>> page = Meld(xhtml)                # Create a Meld object from XHTML.
>>> print page.message                # Access an element within the document.
<textarea id="message" rows="2" wrap="off">Type your message.</textarea>
>>> print page.message.rows           # Access an attribute of an element.
2
>>> page.message = "New message."     # Change the content of an element.
>>> page.message.rows = 4             # Change an attribute value.
>>> del page.message.wrap             # Delete an attribute.
>>> print page                        # Print the resulting page.
<html><body>
<textarea id="message" rows="4">New message.</textarea>
</body></html>

Portanto, a lógica do programa eo HTML estão completamente separados - um designer gráfico pode projetar o HTML em um editor visual XHTML, sem precisar lidar com nenhuma sintaxe não padrão ou nomes de atributos não padrão. O código do programa não sabe nada sobre XML ou HTML - trata-se apenas de objetos e atributos como qualquer outra parte do código Python. Preencher um formulário HTML com um registro de um banco de dados é um one-liner (usando o operador % - veja abaixo). Construir uma tabela HTML de um conjunto de registros é tão fácil, como mostrado no exemplo abaixo:

Exemplo do mundo real:

Aqui está um exemplo baseado em dados que povoa uma tabela de uma fonte de dados, baseando a tabela em dados de amostra colocados pelo designer da página. Note-se que, no mundo real, o HTML normalmente seria uma página maior lida de um arquivo externo, mantendo os dados e a apresentação separados, e os dados viriam de uma fonte externa como um RDBMS. O HTML pode estar cheio de estilos, imagens, tudo o que quiser e tudo funcionará exatamente.

>>> xhtml = '''<html><table id="people">
... <tr id="header"><th>Name</th><th>Age</th></tr>
... <tr id="row"><td id="name">Example name</td><td id="age">21</td></tr>
... </table></html>'''
>>> doc = Meld(xhtml)
>>> templateRow = doc.row.clone()  # Take a copy of the template row, then
>>> del doc.row                    # delete it to make way for the real rows.
>>> for name, age in [("Richie", 30), ("Dave", 39), ("John", 78)]:
...      newRow = templateRow.clone()
...      newRow.name = name
...      newRow.age = age
...      doc.people += newRow
>>> print re.sub(r'</tr>\s*', '</tr>\n', str(doc))  # Prettify the output
<html><table id="people">
<tr id="header"><th>Name</th><th>Age</th></tr>
<tr id="row"><td id="name">Richie</td><td id="age">30</td></tr>
<tr id="row"><td id="name">Dave</td><td id="age">39</td></tr>
<tr id="row"><td id="name">John</td><td id="age">78</td></tr>
</table></html>

Note que, se você fosse posteriormente manipular a tabela, usando PyMeld ou JavaScript, por exemplo, você precisaria renomear cada row, name e age elemento para ter um nome exclusivo - você pode fazer isso atribuindo ao id atributo, mas eu saltei isso para simplificar o exemplo.

Como mostra o exemplo, o += operador adiciona conteúdo a um elemento - adicionando <tr> elementos para um <table> nesse caso.

Atalho: o % operador

Usando o object.id = value a sintaxe para cada operação pode ficar tediosa, então há atalhos que você pode tomar usando o operador %. Isso funciona exatamente como o built-in % operador para cordas. O exemplo acima poderia ter sido escrito assim:

>>> for name, age in [("Richie", 30), ("Dave", 39), ("John", 78)]:
...      doc.people += templateRow % (name, age)

O operador %, dado um único valor ou uma seqüência, atribui valores aos elementos com `id`s na ordem em que aparecem, assim como o operador % para strings. Observe que não há necessidade de ligar clone() quando você está usando %, como ele retorna automaticamente um clone modificado (novamente, assim como % faz para strings). Você também pode usar um dicionário:

>>> print templateRow % {'name': 'Frances', 'age': 39}
<tr id="row"><td id="name">Frances</td><td id="age">39</td></tr>

O operador % é realmente útil quando você possui uma grande quantidade de itens de dados - por exemplo, preencher um formulário HTML com um registro de um RDBMS torna-se um one-liner.

Observe que esses exemplos são escritos para maior clareza do que desempenho e não necessariamente dimensionam muito bem - usando += criar um resultado em um loop é ineficiente, e PyMeld's % O operador é mais lento do que o incorporado em Python. Vejo toFormatString() no manual de referência para obter formas de acelerar esse tipo de código.

Conteúdo de elemento

Quando você se refere a um elemento nomeado em um documento, você obtém um objeto Meld representando esse elemento inteiro:

>>> page = Meld('<html><span id="x">Hello world</span></html>')
>>> print page.x
<span id="x">Hello world</span>

Se você quiser apenas obter o conteúdo do elemento como string, use o atributo _content:

>>> print page.x._content
Hello world

Você também pode atribuir a _content, embora isso seja diretamente equivalente a atribuir à própria etiqueta:

>>> page.x._content = "Hello again"
>>> print page
<html><span id="x">Hello again</span></html>
>>> page.x = "Goodbye"
>>> print page
<html><span id="x">Goodbye</span></html>

A única vez que você precisa atribuir a _content é quando você fez uma referência a um elemento dentro de um documento:

>>> x = page.x
>>> x._content = "I'm back"
>>> print page
<html><span id="x">I'm back</span></html>

Dizendo x = "I'm back" simplesmente re-bind x para a string "I'm back" sem afetar o documento.

Versão e licença

Esta é a versão 2.1.4 de PyMeld.py, Copyright (c) 2002-2009 Entrian Solutions. É um software de código aberto lançado sob os termos da Licença do MIT.