【问题标题】:How to create <!DOCTYPE> with Python's cElementTree如何使用 Python 的 cElementTree 创建 <!DOCTYPE>
【发布时间】:2012-02-10 16:47:53
【问题描述】:

我已尝试使用此问题的答案,但无法使其工作:How to create "virtual root" with Python's ElementTree?

这是我的代码:

import xml.etree.cElementTree as ElementTree
from StringIO import StringIO
s = '<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE tmx SYSTEM \"tmx14a.dtd\" ><tmx version=\"1.4a\" />'
tree = ElementTree.parse(StringIO(s)).getroot()
header = ElementTree.SubElement(tree,'header',{'adminlang': 'EN',})
body = ElementTree.SubElement(tree,'body')
ElementTree.ElementTree(tree).write('myfile.tmx','UTF-8')

当我打开生成的“myfile.tmx”文件时,它包含以下内容:

<?xml version='1.0' encoding='UTF-8'?>
<tmx version="1.4a"><header adminlang="EN" /><body /></tmx>

我错过了什么?或者,有没有更好的工具?

【问题讨论】:

    标签: python xml elementtree


    【解决方案1】:

    您可以将write 函数上的xml_declaration 参数设置为False,因此输出不会有带编码的xml 声明,然后只需手动附加您需要的标头即可。实际上如果你设置你的编码为'utf-8'(小写),xml声明也不会被添加。

    import xml.etree.cElementTree as ElementTree
    
    tree = ElementTree.Element('tmx', {'version': '1.4a'})
    ElementTree.SubElement(tree, 'header', {'adminlang': 'EN'})
    ElementTree.SubElement(tree, 'body')
    
    with open('myfile.tmx', 'wb') as f:
        f.write('<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE tmx SYSTEM "tmx14a.dtd">'.encode('utf8'))
        ElementTree.ElementTree(tree).write(f, 'utf-8')
    

    结果文件(手动添加换行符以提高可读性):

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE tmx SYSTEM "tmx14a.dtd">
    <tmx version="1.4a">
        <header adminlang="EN" />
        <body />
    </tmx>
    

    【讨论】:

    • 您能解释一下您是如何在 xml 中添加新行的吗?
    • @Learner:为了便于阅读,我手动添加了它。如果您想使用 ElementTree 中的新行来获取 XML - 搜索如何漂亮地打印 XML。
    • 这在 macOS 上的 python 3.6.4 中给了我一个错误TypeError: write() argument must be str, not bytes。我认为这是因为您首先以字符串形式编写,然后在同一个 open() 命令中以二进制形式编写。
    • @ElliottB 谢谢,我更新了代码。应该适用于 python 2 和 3。
    • 此解决方案不起作用,除非您手动(如前所述)输入 ElementTree,这肯定不是您想要做的。我在下面对这个问题提出了一个简单而愚蠢的解决方案。
    【解决方案2】:

    您可以使用lxml 及其tostring 函数:

    from lxml import etree
    
    s = """<?xml version="1.0" encoding="UTF-8"?>
    <tmx version="1.4a"/>""" 
    
    tree = etree.fromstring(s)
    header = etree.SubElement(tree,'header',{'adminlang': 'EN'})
    body = etree.SubElement(tree,'body')
    
    print etree.tostring(tree, encoding="UTF-8",
                         xml_declaration=True,
                         pretty_print=True,
                         doctype='<!DOCTYPE tmx SYSTEM "tmx14a.dtd">')
    

    =>

    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE tmx SYSTEM "tmx14a.dtd">
    <tmx version="1.4a">
      <header adminlang="EN"/>
      <body/>
    </tmx>
    

    【讨论】:

    • 我收到此错误:ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration. 使用 Python 3.6
    • etree.fromstring(s.encode("UTF-8")) 适用于我的 Python 3.6。
    【解决方案3】:

    我使用不同的解决方案来添加 DOCTYPE,非常简单,非常愚蠢。

    import xml.etree.ElementTree as ET
    
    with open(path_file, "w", encoding='UTF-8') as xf:
        doc_type = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dlg:window ' \
                   'PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">'
        tostring = ET.tostring(root).decode('utf-8')
        file = f"{doc_type}{tostring}"
        xf.write(file)
    

    【讨论】:

      【解决方案4】:

      我无法使用 vanilla ElementTree 找到解决此问题的方法,并且 demalexx 提出的解决方案创建了无效的 XML,该 XML 被我的应用程序 (DITA) 拒绝。 我建议的是一种涉及其他模块的解决方法,它对我来说非常有效。

      import re
      # found no way for cleanly specify a <!DOCTYPE ...> stanza in ElementTree so
      # so we substitute the current <?xml ... ?> stanza with a full <?xml... + <!DOCTYPE...
      new_header = '<?xml version="1.0" encoding="UTF-8" ?>\n' \
                       '<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">\n'
      
      target_xml = re.sub(u"\<\?xml .+?>", new_header, source_xml)
      with open(filename, 'w') as catalog_file:
          catalog_file.write(target_xml.encode('utf8'))
      

      【讨论】:

      • 能否详细说明“非有效 XML”问题?
      • @posfan12,我猜主要问题是行首没有 DTD,这在 demalexx 的回答中很容易解决。
      猜你喜欢
      • 2015-08-14
      • 1970-01-01
      • 2019-07-12
      • 1970-01-01
      • 2017-11-06
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多