当前位置:  开发笔记 > 编程语言 > 正文

如何使用ElementTree输出CDATA

如何解决《如何使用ElementTree输出CDATA》经验,为你挑选了6个好方法。

我发现cElementTree快了大约30倍xml.dom.minidom,我正在重写我的XML编码/解码代码.但是,我需要输出包含CDATA部分的XML,并且似乎没有办法使用ElementTree.

可以吗?



1> elifiner..:

经过一番工作,我自己找到了答案.查看ElementTree.py源代码,我发现XML注释和预处理指令有特殊处理.他们所做的是为特殊元素类型创建一个工厂函数,该函数使用特殊(非字符串)标记值来区分它与常规元素.

def Comment(text=None):
    element = Element(Comment)
    element.text = text
    return element

然后在_write实际输出XML的ElementTree函数中,有一个特殊的案例处理注释:

if tag is Comment:
    file.write("" % _escape_cdata(node.text, encoding))

为了支持CDATA部分,我创建了一个名为的工厂函数CDATA,扩展了ElementTree类并更改了_write处理CDATA元素的函数.

如果你想用CDATA部分解析XML然后再用CDATA部分输出它,这仍然无济于事,但它至少允许你以编程方式创建带有CDATA部分的XML,这是我需要做的.

该实现似乎适用于ElementTree和cElementTree.

import elementtree.ElementTree as etree
#~ import cElementTree as etree

def CDATA(text=None):
    element = etree.Element(CDATA)
    element.text = text
    return element

class ElementTreeCDATA(etree.ElementTree):
    def _write(self, file, node, encoding, namespaces):
        if node.tag is CDATA:
            text = node.text.encode(encoding)
            file.write("\n\n" % text)
        else:
            etree.ElementTree._write(self, file, node, encoding, namespaces)

if __name__ == "__main__":
    import sys

    text = """
    
    
    This is just some sample text.
    
    """

    e = etree.Element("data")
    cdata = CDATA(text)
    e.append(cdata)
    et = ElementTreeCDATA(e)
    et.write(sys.stdout, "utf-8")


Thsio reciep不适用于Python 2.7或3.2(和3.3) - 请查看@ amaury的答案.因此,新的ElementTree没有可以重写的"_write"方法.

2> iny..:

lxml支持像ElementTree这样的CDATA和API.



3> 小智..:

以下是适用于python 3.2的gooli解决方案的变体:

import xml.etree.ElementTree as etree

def CDATA(text=None):
    element = etree.Element('![CDATA[')
    element.text = text
    return element

etree._original_serialize_xml = etree._serialize_xml
def _serialize_xml(write, elem, qnames, namespaces):
    if elem.tag == '![CDATA[':
        write("\n<%s%s]]>\n" % (
                elem.tag, elem.text))
        return
    return etree._original_serialize_xml(
        write, elem, qnames, namespaces)
etree._serialize_xml = etree._serialize['xml'] = _serialize_xml


if __name__ == "__main__":
    import sys

    text = """
    
    
    This is just some sample text.
    
    """

    e = etree.Element("data")
    cdata = CDATA(text)
    e.append(cdata)
    et = etree.ElementTree(e)
    et.write(sys.stdout.buffer.raw, "utf-8")


for python 2.7将编码arg添加到序列化签名.改变`DEF _serialize_xml(写,ELEM,的QName,命名空间):`到`DEF _serialize_xml(写,ELEM,编码,的QName,命名空间):`变化`写入,ELEM,的QName,命名空间)`到`写,ELEM,编码,的QName,命名空间)``变化et.write(sys.stdout.buffer.raw, "UTF-8")``到et.write(sys.stdout的, "UTF-8")`

4> Kamil..:

我不知道先前版本的拟议代码是否运行良好以及ElementTree模块是否已更新但我遇到了使用此技巧的问题:

import xml.etree.ElementTree as ElementTree

def CDATA(text=None):
    element = ElementTree.Element('![CDATA[')
    element.text = text
    return element

ElementTree._original_serialize_xml = ElementTree._serialize_xml
def _serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs):
    if elem.tag == '![CDATA[':
        write("\n<{}{}]]>\n".format(elem.tag, elem.text))
        if elem.tail:
            write(_escape_cdata(elem.tail))
    else:
        return ElementTree._original_serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs)

ElementTree._serialize_xml = ElementTree._serialize['xml'] = _serialize_xml

if __name__ == "__main__":
    import sys

text = """


This is just some sample text.

"""

e = ElementTree.Element("data")
cdata = CDATA(text)
root.append(cdata)

这种方法的问题在于,在传递此异常之后,序列化程序再次将其视为普通标记.我得到的东西是这样的:

etree._original_serialize_xml = etree._serialize_xml
def _serialize_xml(write, elem, qnames, namespaces):
    if elem.tag == '![CDATA[':
        write("\n<%s%s]]>\n" % (
                elem.tag, elem.text))
        return
    return etree._original_serialize_xml(
        write, elem, qnames, namespaces)
etree._serialize_xml = etree._serialize['xml'] = _serialize_xml

当然,我们知道这只会导致很多错误.为什么会这样呢?

答案就在这个小家伙身上:



this was the code I wanted to put inside of CDATA

如果我们已经困住了我们的CDATA并成功通过了它,我们不想再通过原始的序列化函数来检查代码.因此,在"if"块中,只有当CDATA不存在时,我们才必须返回原始序列化函数.在返回原始函数之前,我们错过了"else".

而且在我的版本ElementTree模块中,serialize函数拼命地要求"short_empty_element"参数.所以我推荐的最新版本看起来像这样(也有"尾巴"):

return etree._original_serialize_xml(write, elem, qnames, namespaces)

我得到的输出是:

from xml.etree import ElementTree
from xml import etree

#in order to test it you have to create testing.xml file in the folder with the script
xmlParsedWithET = ElementTree.parse("testing.xml")
root = xmlParsedWithET.getroot()

def CDATA(text=None):
    element = ElementTree.Element('![CDATA[')
    element.text = text
    return element

ElementTree._original_serialize_xml = ElementTree._serialize_xml

def _serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs):

    if elem.tag == '![CDATA[':
        write("\n<{}{}]]>\n".format(elem.tag, elem.text))
        if elem.tail:
            write(_escape_cdata(elem.tail))
    else:
        return ElementTree._original_serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs)

ElementTree._serialize_xml = ElementTree._serialize['xml'] = _serialize_xml


text = """


This is just some sample text.

"""
e = ElementTree.Element("data")
cdata = CDATA(text)
root.append(cdata)

#tests
print(root)
print(root.getchildren()[0])
print(root.getchildren()[0].text + "\n\nyay!")

祝你有同样的结果!



5> Dan Lenski..:

这是不可能的AFAIK ...这是一个遗憾.基本上,ElementTree模块假定读者是100%XML兼容的,因此如果他们输出一个CDATA或其他生成等效文本的格式,则无关紧要.

有关详细信息,请参阅Python邮件列表中的此主题.基本上,他们建议使用某种基于DOM的XML库.


我不会称之为"遗憾".对于XML信息集(内容),""和"&"之间没有区别......大多数XML解析器甚至不会让您知道原始文档中的内容.

6> 小智..:

实际上这段代码有一个错误,因为你没有]]>在你作为CDATA插入的数据中出现

按是否有一种方式来逃避XML中的CDATA结束令牌?

在这种情况下你应该把它分成两个CDATA,在]]>两者之间分开.

基本上data = data.replace("]]>", "]]]]>")
(不一定正确,请验证)

推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有