В настоящее время я пробую ElementTree, и он выглядит нормально, он избегает сущностей HTML и так далее, и так далее. Мне не хватает чего-то действительно замечательного, о чем я не слышал?
Это похоже на то, что я делаю на самом деле:
import xml.etree.ElementTree as ET
root = ET.Element('html')
head = ET.SubElement(root,'head')
script = ET.SubElement(head,'script')
script.set('type','text/javascript')
script.text = "var a = 'I love á letters'"
body = ET.SubElement(root,'body')
h1 = ET.SubElement(body,'h1')
h1.text = "And I like the fact that 3 > 1"
tree = ET.ElementTree(root)
tree.write('foo.xhtml')
# more foo.xhtml
<html><head><script type = "text/javascript">var a = 'I love &aacute;
letters'</script></head><body><h1>And I like the fact that 3 > 1</h1>
</body></html>






разве вы не хотите чего-то вроде:
html(head(script(type='text/javascript', content='var a = ...')),
body(h1('And I like the fact that 3 < 1'), p('just some paragraph'))
Кажется, я где-то видел что-то подобное. Это было бы замечательно.
Обновлено: На самом деле, сегодня я пошел и написал библиотеку, чтобы сделать только то: магия
Вы можете использовать это так:
from magictree import html, head, script, body, h1, p
root = html(
head(
script('''var a = 'I love &aacute; letters''',
type='text/javascript')),
body(
h1('And I like the fact that 3 > 1')))
# root is a plain Element object, like those created with ET.Element...
# so you can write it out using ElementTree :)
tree = ET.ElementTree(root)
tree.write('foo.xhtml')
Магия magictree заключается в том, как работает импорт: фабрики Element создаются по мере необходимости. Есть посмотри на источник, это на основе ответа на другой вопрос StackOverflow.
можно ли добавлять атрибуты к элементам? Я имею в виду атрибуты html / xml, такие как <h1 class = "something">
да: любые аргументы ключевого слова в конечном итоге становятся атрибутами, как и любые переданные словари :)
Другой способ - использовать конструктор E Фабрика из lxml (также доступен в Elementtree)
>>> from lxml import etree
>>> from lxml.builder import E
>>> def CLASS(*args): # class is a reserved word in Python
... return {"class":' '.join(args)}
>>> html = page = (
... E.html( # create an Element called "html"
... E.head(
... E.title("This is a sample document")
... ),
... E.body(
... E.h1("Hello!", CLASS("title")),
... E.p("This is a paragraph with ", E.b("bold"), " text in it!"),
... E.p("This is another paragraph, with a", "\n ",
... E.a("link", href = "http://www.python.org"), "."),
... E.p("Here are some reserved characters: <spam&egg>."),
... etree.XML("<p>And finally an embedded XHTML fragment.</p>"),
... )
... )
... )
>>> print(etree.tostring(page, pretty_print=True))
<html>
<head>
<title>This is a sample document</title>
</head>
<body>
<h1 class = "title">Hello!</h1>
<p>This is a paragraph with <b>bold</b> text in it!</p>
<p>This is another paragraph, with a
<a href = "http://www.python.org">link</a>.</p>
<p>Here are some reservered characters: <spam&egg>.</p>
<p>And finally an embedded XHTML fragment.</p>
</body>
</html>
В моем случае это не работает !, нет опции pretty_print
Я предполагаю, что вы фактически создаете дерево XML DOM, потому что вы хотите проверить, что то, что входит в этот файл, является допустимым XML, поскольку в противном случае вы просто записали бы статическую строку в файл. Если проверка вашего вывода действительно является вашей целью, я бы предложил
from xml.dom.minidom import parseString
doc = parseString("""<html>
<head>
<script type = "text/javascript">
var a = 'I love &aacute; letters'
</script>
</head>
<body>
<h1>And I like the fact that 3 > 1</h1>
</body>
</html>""")
with open("foo.xhtml", "w") as f:
f.write( doc.toxml() )
Это позволяет вам просто написать XML, который вы хотите вывести, проверить его правильность (поскольку parseString вызовет исключение, если он недействителен), и ваш код будет выглядеть намного лучше.
Предположительно, вы не просто пишете каждый раз один и тот же статический XML и хотите подменить его. В этом случае у меня были бы строки вроде
var a = '%(message)s'
а затем используйте оператор% для замены, например
</html>""" % {"message": "I love &aacute; letters"})
Идея состоит в том, чтобы код выводил действительный XML, даже если я даю ему неверный XML, как это делает ET.
Попробуйте http://uche.ogbuji.net/tech/4suite/amara. Он довольно полный и имеет простой набор инструментов для доступа. Нормальная поддержка Unicode и т. д.
#
#Output the XML entry
#
def genFileOLD(out,label,term,idval):
filename=entryTime() + ".html"
writer=MarkupWriter(out, indent=u"yes")
writer.startDocument()
#Test element and attribute writing
ans=namespace=u'http://www.w3.org/2005/Atom'
xns=namespace=u'http://www.w3.org/1999/xhtml'
writer.startElement(u'entry',
ans,
extraNss = {u'x':u'http://www.w3.org/1999/xhtml' ,
u'dc':u'http://purl.org/dc/elements/1.1'})
#u'a':u'http://www.w3.org/2005/Atom',
#writer.attribute(u'xml:lang',unicode("en-UK"))
writer.simpleElement(u'title',ans,content=unicode(label))
#writer.simpleElement(u'a:subtitle',ans,content=u' ')
id=unicode("http://www.dpawson.co.uk/nodesets/"+afn.split(".")[0])
writer.simpleElement(u'id',ans,content=id)
writer.simpleElement(u'updated',ans,content=unicode(dtime()))
writer.startElement(u'author',ans)
writer.simpleElement(u'name',ans,content=u'Dave ')
writer.simpleElement(u'uri',ans,
content=u'http://www.dpawson.co.uk/nodesets/'+afn+".xml")
writer.endElement(u'author')
writer.startElement(u'category', ans)
if (prompt):
label=unicode(raw_input("Enter label "))
writer.attribute(u'label',unicode(label))
if (prompt):
term = unicode(raw_input("Enter term to use "))
writer.attribute(u'term', unicode(term))
writer.endElement(u'category')
writer.simpleElement(u'rights',ans,content=u'\u00A9 Dave 2005-2008')
writer.startElement(u'link',ans)
writer.attribute(u'href',
unicode("http://www.dpawson.co.uk/nodesets/entries/"+afn+".html"))
writer.attribute(u'rel',unicode("alternate"))
writer.endElement(u'link')
writer.startElement(u'published', ans)
dt=dtime()
dtu=unicode(dt)
writer.text(dtu)
writer.endElement(u'published')
writer.simpleElement(u'summary',ans,content=unicode(label))
writer.startElement(u'content',ans)
writer.attribute(u'type',unicode("xhtml"))
writer.startElement(u'div',xns)
writer.simpleElement(u'h3',xns,content=unicode(label))
writer.endElement(u'div')
writer.endElement(u'content')
writer.endElement(u'entry')
Это только я, или это единственный ответ с учетом пространства имен?
В итоге я использовал saxutils.escape (str) для создания действительных строк XML, а затем проверил их с помощью подхода Эли, чтобы убедиться, что я не пропустил ни одного тега
from xml.sax import saxutils
from xml.dom.minidom import parseString
from xml.parsers.expat import ExpatError
xml = '''<?xml version = "1.0" encoding = "%s"?>\n
<contents title = "%s" crawl_date = "%s" in_text_date = "%s"
url = "%s">\n<main_post>%s</main_post>\n</contents>''' %
(self.encoding, saxutils.escape(title), saxutils.escape(time),
saxutils.escape(date), saxutils.escape(url), saxutils.escape(contents))
try:
minidoc = parseString(xml)
catch ExpatError:
print "Invalid xml"
Имейте в виду, что saxutils.escape не подходит для кодирования значений атрибутов XML; вы действительно хотите quoteattr: docs.python.org/2/library/…
Всегда есть SimpleXMLWriter, часть набора инструментов ElementTree. Интерфейс предельно прост.
Вот пример:
from elementtree.SimpleXMLWriter import XMLWriter
import sys
w = XMLWriter(sys.stdout)
html = w.start("html")
w.start("head")
w.element("title", "my document")
w.element("meta", name = "generator", value = "my application 1.0")
w.end()
w.start("body")
w.element("h1", "this is a heading")
w.element("p", "this is a paragraph")
w.start("p")
w.data("this is ")
w.element("b", "bold")
w.data(" and ")
w.element("i", "italic")
w.data(".")
w.end("p")
w.close(html)
Это дает мне ошибку: File "C:\Python33\lib\site-packages\elementtree\SimpleXMLWriter.py", line 119, in <module> def escape_cdata(s, encoding=None, replace=string.replace): AttributeError: 'module' object has no attribute 'replace'
https://github.com/galvez/xmlwitch:
import xmlwitch
xml = xmlwitch.Builder(version='1.0', encoding='utf-8')
with xml.feed(xmlns='http://www.w3.org/2005/Atom'):
xml.title('Example Feed')
xml.updated('2003-12-13T18:30:02Z')
with xml.author:
xml.name('John Doe')
xml.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6')
with xml.entry:
xml.title('Atom-Powered Robots Run Amok')
xml.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a')
xml.updated('2003-12-13T18:30:02Z')
xml.summary('Some text.')
print(xml)
Для тех, кто сталкивается с этим сейчас, на самом деле есть способ сделать это, скрытый в стандартной библиотеке Python в xml.sax.utils.XMLGenerator. Вот пример этого в действии:
>>> from xml.sax.saxutils import XMLGenerator
>>> import StringIO
>>> w = XMLGenerator(out, 'utf-8')
>>> w.startDocument()
>>> w.startElement("test", {'bar': 'baz'})
>>> w.characters("Foo")
>>> w.endElement("test")
>>> w.endDocument()
>>> print out.getvalue()
<?xml version = "1.0" encoding = "utf-8"?>
<test bar = "baz">Foo</test>
Некоторые из языков веб-шаблонов (которые, конечно, генерируют HTML / XML) могут быть загружены в виде модулей без соответствующей веб-инфраструктуры. Если вам нужно пофантазировать, я бы посоветовал посмотреть туда. Мне особенно повезло с Генши.