如何在lxml中设置属性值的命名空间前缀?

3 投票
1 回答
4130 浏览
提问于 2025-04-16 03:58

我正在尝试使用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)

不过对于大多数情况来说,这可能有点过于复杂了。

撰写回答