【问题标题】:Is Python bad at XML? [closed]Python 不擅长 XML 吗? [关闭]
【发布时间】:2010-10-23 19:13:27
【问题描述】:

编辑

在这个问题中使用“bad at XML”这个短语一直是争论的焦点,所以我想首先提供一个非常明确的定义来说明我在这种情况下这个术语的含义:如果支持对于标准 XML API 来说很差,并且迫使人们使用特定于语言的 API,其中命名空间似乎是事后才想到的,那么我倾向于将该语言描述为不像其他主流语言那样适合使用 XML没有这些问题。 “Bad at XML”只是这些条件的简写,我认为这是描述它的一种公平方式。正如我将要描述的,我对 Python 的初步体验引起了人们对它是否满足这些条件的担忧。但是,因为总的来说我对 Python 的体验非常积极,所以我似乎遗漏了一些东西,从而激发了这个问题。

我正在尝试使用 Python 进行一些非常简单的 XML 处理。我最初希望能够重用我对标准 W3C DOM API 的了解,并高兴地发现 xml.domxml.dom.minidom 模块在支持这些 API 方面做得很好。然而不幸的是,序列化被证明是有问题的,原因如下:

我在这里查看了其他类似 W3C 的库的列表:

http://wiki.python.org/moin/PythonXml#W3CDOM-likelibraries

我发现很多其他的库,比如 4Suite 和 libxml2dom 也没有维护。

另一方面,itools 乍一看似乎得到了维护,但似乎没有可用的 Ubuntu/Debian 软件包,因此很难部署和维护。

此时,尝试在我的 Python 应用程序中使用 W3C DOM API 似乎是死路一条,我开始研究 ElementTree API。但我认为 eTree API 支持命名空间的方式非常丑陋,每次创建特定命名空间中的元素时都需要使用字符串连接:

http://lxml.de/tutorial.html#namespaces

所以,我的问题是,我是否忽略了某些东西,或者在 Python 中对 XML(尤其是 W3C DOM)的支持实际上很糟糕?

编辑

下面列出了更精确的问题,这些问题的答案对我很有帮助:

  • Python 中是否有对 W3C DOM 的合理支持?
  • 如果不是xml.dom,你是否使用例如etree 而不是 W3C DOM?
  • 如果是这样,哪个库最好,您如何克服 API 中的命名空间问题?
  • 如果您改用 W3C DOM,您是否知道实现序列化并支持命名空间的库?

【问题讨论】:

  • 不错的价值判断。这就是一个很好的问题。形成意见并要求人们证明你的意见是错误的。除了投反对票,你希望从这样的“加载”价值判断中得到什么?放弃意见。放弃价值判断。放下消极情绪。将其改写为(1)定义您的问题并(2)寻求解决方案。否则,您将一无所获。
  • @echo-flow:“这不是价值判断”。然而。它一种价值判断。放弃意见。放弃价值判断。放下消极情绪。将其改写为(1)定义您的问题并(2)寻求解决方案。请。 “Python 中是否有对 W3C DOM 的合理支持?”如果这是您的问题,请从标题中删除价值判断并将其作为您的标题。
  • @echo-flow:我会将这个问题改写为“Python 中如何支持 XML?”在问题中使用“坏”这个词并不是一个很好的开始方式,因为这意味着你认为它很糟糕。不要那样做。
  • "标题并不意味着价值判断。"当它明显而明显的价值判断时,你怎么能这么说。 “Bad at XML”是价值判断的最好例子。没有比价值判断更简洁或清晰的例子了。这就是它的全部内容。它一种价值判断。和。这不是你的问题。请使其与您的问题保持一致。
  • 这里是我对“bad at XML”这个短语的完整解释:如果对标准 API 的支持很差,并且强制使用特定于语言的 API,其中命名空间似乎是事后考虑,我倾向于将该语言描述为不像其他没有这些问题的主流语言那样适合使用 XML。短语“不擅长 XML”只是对此的简写,我相信我在问题中已经充分证明了它的合理性,可以将其作为一个合理的问题提出。这个问题的目的是为了更好地理解这些问题。

标签: python xml dom


【解决方案1】:

我会说 python 可以很好地处理 XML。可用的不同库的数量说明了这一点 - 您有很多选择。如果您想使用库中缺少的功能,请随时贡献一些补丁!

我个人使用 DOM 和 lxml.etree(etree 真的快)。但是,我对命名空间的事情感到痛苦。我写了一个快速帮助函数来处理它:

DEFAULT_NS = "http://www.domain.org/path/to/xml"

def add_xml_namespace(path, namespace=DEFAULT_NS):
    """Adds namespaces to an XPath-ish expression path for etree

    Test simple expression:
    >>> add_xml_namespace('image/namingData/fileBaseName')
    '{http://www.domain.org/path/to/xml}image/{http://www.domain.org/path/to/xml}namingData/{http://www.domain.org/path/to/xml}fileBaseName'

    More complicated expression
    >>> add_xml_namespace('.//image/*') 
    './/{http://www.domain.org/path/to/xml}image/*'

    >>> add_xml_namespace('.//image/text()')
    './/{http://www.domain.org/path/to/xml}image/text()'
    """
    pattern = re.compile(r'^[A-Za-z0-9-]+$')
    tags = path.split('/')
    for i in xrange(len(tags)):
        if pattern.match(tags[i]):
            tags[i] = "{%s}%s" % (namespace, tags[i])
    return '/'.join(tags)

我是这样使用的:

from lxml import etree
from utilities import add_xml_namespace as ns

tree = etree.parse('file.xml')
node = tree.get_root().find(ns('root/group/subgroup'))
# etc. 

如果不提前知道命名空间,可以从根节点提取:

tree = etree.parse('file.xml')
root = tree.getroot().tag
namespace = root[1:root.index('}')]
ns = lambda path: add_xml_namespace(path, namespace)
...

补充说明:这里有一点工作,但是在处理XML 时工作是必要的。这不是 python 问题,而是 XML 问题。

【讨论】:

  • “如果你想要,提交补丁”是最尴尬的开源单行。 (当然,这是一个 Python 问题——如果 Python API 缺少函数并让您完成工作,这不是 XML 的错,而是 API 的错。)
  • 对于最终用户应用程序,这听起来很糟糕,但对于为程序员编写的库,这有什么问题?我不得不使用许多专有库(尤其是在动态性较低的语言中),其中的情况基本上是“如果您需要一个我们认为不包含的琐碎功能,#@!$ off”。害怕写一点代码的人并不是一开始就下载 XML 库的人……
  • @Ken:当库不再维护或处于模棱两可的状态时,情况就完全不同了,就像许多这些 python XML 库的情况一样。维护库比简单地提交补丁要多得多。
  • @echo-flow:我不明白lxml 有什么问题。我对此非常满意,我目前的项目完全围绕 XML!您缺少哪些功能? (序列化就是etree.tostring(the_node, formatting_and_encoding_options)
  • @echo-flow:尽管有问题的文档大量使用了命名空间(IIRC,我在测试时没有遇到不在某个命名空间中的单个标签),但这只是一个小烦恼。在大多数情况下,这意味着在评估 XPath 查询之前调用一次.format(),并在读取调试输出时忽略{...}。也许我很幸运,因为我将 XML 读入了自定义的、更轻量级的数据结构进行处理,并将其转换回 etree 以进行输出(保留命名空间,但这很简单)——所以只有那些部分需要处理命名空间。
【解决方案2】:

Python 非常擅长处理 XML,我认为 lxml 是我用过的最好的 xml 库,它功能强大且 DOM 非常简单。命名空间处理需要一些时间来适应,但我认为这是 lxml 保持简单的另一种好方法。

编辑

重新阅读问题后,不清楚作者是指python对象的序列化,还是只是DOM树。我在下面的回答部分假定了前者。

XML 序列化是一个完全不同的问题。个人觉得不是很重要。大多数 XML 序列化程序产生的输出非常特定于语言或运行时,这违背了拥有这种开放格式的目的。我意识到有一些通用的 XML 序列化模式,但是 Python 提供了 2 种解决方案,它们在 95% 的情况下都表现出色,Pickling 和 JSON。

如果您的应用程序不必与非 python 系统共享对象,Pickling 是您能找到的最快、最强大的序列化解决方案。 JSON 的解析和生成速度明显更快,并且比 XML 更易于使用。 JSON 有很多限制,但解决这些限制通常比处理 XML 的麻烦更容易。

还有很多其他的序列化格式,根据应用程序,我会在 XML 之前推荐它们(例如:Google Protocol Buffers,或 YAML。)

另外,不要忘记 SAX。事件驱动解析器只对读取 XML 有用,但我发现它仍然是解决某些问题的最佳方案。

【讨论】:

    【解决方案3】:

    但我认为 eTree API 支持命名空间的方式非常丑陋,每次创建特定命名空间中的元素时都需要使用字符串连接

    这是在 .NET 的 System.Linq.Xml DOM 中创建具有命名空间的元素的方法:

    XNamespace ns = "my-namespace";
    XElement elm = new XElement(ns + "foo");
    

    这是在 lxml 的命名空间中创建元素的方法:

    ns = "{my-namespace}"
    elm = etree.Element(ns + "foo")
    

    我在这里没有看到可怕的丑陋。事实上,.NET API 的开发人员已经向后弯腰,创建了支持运算符重载的基类,以使他们的 API 能够像 lxml 那样直观地处理命名空间。

    这比 W3C DOM 要求您使用不同的方法来创建带和不带命名空间的元素更难看。

    【讨论】:

    • 比创建更成问题的是查询。要使用 W3C DOM 获取元素的命名空间,您只需访问其 namespaceURI 属性;要获取标签名称,它是 localName。如果您查看@Seth 的示例,您可以看到使用 etree 访问 namespaceURI 需要以下调用“root[1:root.index('}')]”。我认为这不是那么干净。但是,如果有更好的方法来做到这一点,那就太好了。
    • 我同意你的看法; Element 没有 localName 属性有点愚蠢。另一方面,如果您通过遍历 DOM 对象并查看元素名称来查询 XML,而不是使用 XPath,那么您可能还会犯其他错误。
    猜你喜欢
    • 2011-07-20
    • 2012-08-18
    • 1970-01-01
    • 2011-04-04
    • 2013-10-19
    • 1970-01-01
    • 2011-03-26
    • 2013-06-15
    • 1970-01-01
    相关资源
    最近更新 更多