在ElementTree 1.2中抑制命名空间前缀
在Python 2.7(使用etree 1.3)中,我可以通过以下方式去掉元素上的XML前缀:
Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as etree
>>> etree.VERSION
'1.3.0'
>>> something = etree.Element('{http://some.namespace}token')
>>> etree.tostring(something)
'<ns0:token xmlns:ns0="http://some.namespace" />'
>>> etree.register_namespace('', 'http://some.namespace')
>>> etree.tostring(something)
'<token xmlns="http://some.namespace" />'
在1.3版本中增加了一个叫register_namespace
的函数。我想以一种兼容Python 2.6的etree 1.2.6的方式来去掉前缀。以下是我尝试过的:
Python 2.6.7 (r267:88850, Jul 31 2011, 19:30:54)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import xml.etree.ElementTree as etree
>>> etree.VERSION
'1.2.6'
>>> something = etree.Element('{http://some.namespace}token')
>>> etree.tostring(something)
'<ns0:token xmlns:ns0="http://some.namespace" />'
>>> etree._namespace_map['http://some.namespace'] = ''
>>> etree.tostring(something)
'<:token xmlns:="http://some.namespace" />'
但这并不是我想要的。前缀还是存在,只不过是空的。有没有办法完全去掉它们呢?
4 个回答
1
这虽然是个小技巧,但在我使用Jython 2.5.2的时候效果很好。
ns=re.match('^\{([^\}]+)\}', mydoc.getroot().tag ).group(1)
etree._namespace_map[ns]='STRIPME'
etree.tostring( mydoc.getroot() ).replace( 'STRIPME:', '' )
6
我在文件的开头创建了一个方法,然后在需要用到标签字符串的地方直接使用它。我把这个方法命名为'ns_tag',你也可以随便起个名字。
def ns_tag(tag):
return str( ElementTree.QName('http://some.namespace/api/4/', tag) )
举个例子:
root = ElementTree.fromstring(xml)
success = root.find(ns_tag('success'))
if success.text == 'true':
for node in root.find(ns_tag('items')):
id = node.find(ns_tag('id')).text
...
18
在查看了 Python 2.6 中 ElementTree 的源代码 后,我发现 :
是在 fixtag
函数里写死的。为了绕过这个问题,我做了以下操作:
from xml.etree import ElementTree as etree
if etree.VERSION[0:3] == '1.2':
#in etree < 1.3, this is a workaround for supressing prefixes
def fixtag(tag, namespaces):
import string
# given a decorated tag (of the form {uri}tag), return prefixed
# tag and namespace declaration, if any
if isinstance(tag, etree.QName):
tag = tag.text
namespace_uri, tag = string.split(tag[1:], "}", 1)
prefix = namespaces.get(namespace_uri)
if namespace_uri not in namespaces:
prefix = etree._namespace_map.get(namespace_uri)
if namespace_uri not in etree._namespace_map:
prefix = "ns%d" % len(namespaces)
namespaces[namespace_uri] = prefix
if prefix == "xml":
xmlns = None
else:
if prefix is not None:
nsprefix = ':' + prefix
else:
nsprefix = ''
xmlns = ("xmlns%s" % nsprefix, namespace_uri)
else:
xmlns = None
if prefix is not None:
prefix += ":"
else:
prefix = ''
return "%s%s" % (prefix, tag), xmlns
etree.fixtag = fixtag
etree._namespace_map['http://some.namespace'] = None
else:
#For etree > 1.3, use register_namespace function
etree.register_namespace('', 'http://some.namespace')
如果这个帖子将来过时了,代码会在 这里 进行维护。