如何在lxml中设置属性值的命名空间前缀?
我正在尝试使用lxml创建XML模式。最开始我想做的就是这样的:
<xs:schema xmlns="http://www.goo.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.goo.com">
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:positiveInteger" name="age"/>
</xs:schema>
我这样做了——在值前面加上了xs:,但我觉得还有更好的方法。
def schema():
SCHEMA_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
XS = "{%s}" % SCHEMA_NAMESPACE
NSMAP = {None: "http://www.goo.com"}
schema = etree.Element(XS+"schema",
nsmap = NSMAP,
targetNamespace="http://www.goo.com",
elementFormDefault="qualified")
element = etree.Element(XS+"element",
attrib = {"name" : "name",
"type" : "xs:string"})
schema.append(element)
element = etree.Element(XS+"element",
attrib = {"name" : "age",
"type" : "xs:positiveInteger"})
schema.append(element)
return etree.tostring(schema, pretty_print=True)
有没有更好的写法呢?
1 个回答
2
有一点要提一下,你需要在你的命名空间映射(NSMAP)中包含 "xs": SCHEMA_NAMESPACE
这样的内容。否则,你生成的XML中,'xs'这个前缀就没有对应的命名空间。这样做可以让你在定义元素名称时使用前缀,比如 "xs:element"。
关于你主要的问题,我觉得只要你在任何地方都保持相同的前缀和命名空间的对应关系,比如使用一个全局的 NSMAP
,这样做应该是没问题的。如果你在处理XML时可能会遇到任意的命名空间前缀,那么你需要确保:
- 在你创建的每个元素中都添加带有 'xs' 前缀的
nsmap
;或者 - 使用
_Element.nsmap
属性来获取父元素的命名空间映射,反转它,然后在反转后的映射中查找合适的前缀。
后者的一个例子是:
SCHEMA_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
def add_element(schema):
nsmap = schema.nsmap
nsrmap = dict([(uri, prefix) for prefix, uri in nsmap.items()])
prefix = nsrmap[SCHEMA_NAMESPACE]
xs = lambda name: "%s:%s" % (prefix, name)
element = schema.makeelement(xs("element"), nsmap=nsmap,
attrib={'name': 'age', 'type': xs('string')})
schema.append(element)
return etree.tostring(schema, pretty_print=True)
不过对于大多数情况来说,这可能有点过于复杂了。