【问题标题】:XML writing tools for Python用于 Python 的 XML 编写工具
【发布时间】:2010-09-08 13:06:16
【问题描述】:

我目前正在尝试 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 &amp;aacute;
letters'</script></head><body><h1>And I like the fact that 3 &gt; 1</h1>
</body></html>

【问题讨论】:

  • 一些网络模板语言(当然会生成 HTML / XML)可以作为模块加载,而无需随附的网络框架。如果你需要变得花哨,我建议你这样看。我和genshi的运气特别好。

标签: python xml xhtml


【解决方案1】:

另一种方法是使用来自 lxml 的 E Factory 构建器(在 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: &lt;spam&amp;egg&gt;.</p>
    <p>And finally an embedded XHTML fragment.</p>
  </body>
</html>

【讨论】:

  • 我的情况下它不起作用!,没有 pretty_print 选项
【解决方案2】:

对于现在遇到这种情况的任何人,实际上有一种方法可以在 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>

【讨论】:

    【解决方案3】:

    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)
    

    【讨论】:

      【解决方案4】:

      你真的不想要这样的东西吗:

      html(head(script(type='text/javascript', content='var a = ...')),
      body(h1('And I like the fact that 3 < 1'), p('just some paragraph'))
      

      我想我在某个地方看到过类似的东西。这将是美妙的。

      编辑:实际上,我今天去写了一个库就这样做magictree

      你可以这样使用它:

      from magictree import html, head, script, body, h1, p
      root = html(
               head(
                 script('''var a = 'I love &amp;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 工厂是在需要时创建的。有一个look at the source,它是based on an answer to another StackOverflow question

      【讨论】:

      • 是否可以为元素添加属性?我的意思是 html/xml 属性,例如 &lt;h1 class="something"&gt;
      • 是的:任何关键字参数最终都是属性,以及传入的任何字典:)
      【解决方案5】:

      试试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')
      

      【讨论】:

      • 只有我一个人,还是这是唯一一个知道命名空间的答案?
      【解决方案6】:

      我假设您实际上是在创建 XML DOM 树,因为您想验证进入该文件的内容是否是有效的 XML,否则您只需将静态字符串写入文件。如果验证您的输出确实是您的目标,那么我建议

      from xml.dom.minidom import parseString
      
      doc = parseString("""<html>
          <head>
              <script type="text/javascript">
                  var a = 'I love &amp;aacute; letters'
              </script>
          </head>
          <body>
              <h1>And I like the fact that 3 &gt; 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 &amp;aacute; letters"})
      

      【讨论】:

      • 这个想法是让代码输出有效的 XML,即使我给了它无效的 XML,就像 ET 所做的那样。
      【解决方案7】:

      总是有 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 &lt;module&gt; def escape_cdata(s, encoding=None, replace=string.replace): AttributeError: 'module' object has no attribute 'replace'
      【解决方案8】:

      我最终使用 saxutils.escape(str) 生成有效的 XML 字符串,然后使用 Eli 的方法对其进行验证,以确保我没有遗漏任何标签

      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"
      

      【讨论】:

      猜你喜欢
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      相关资源
      最近更新 更多