lxml 无需 Schema URL 解析 xsd 文件

2 投票
4 回答
4949 浏览
提问于 2025-04-16 21:41

我正在使用lxml库来解析一个xsd文件,想找个简单的方法去掉每个元素名称前面的URL命名空间。下面是这个xsd文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="rootelement">
    <xs:complexType>
      <xs:choice maxOccurs="unbounded">
        <xs:element minOccurs="1" maxOccurs="1" name="element1">
          <xs:complexType>
            <xs:all>
              <xs:element name="subelement1" type="xs:string" />
              <xs:element name="subelement2" type="xs:integer" />
              <xs:element name="subelement3" type="xs:dateTime" />
            </xs:all>
            <xs:attribute name="id" type="xs:integer" use="required" />
          </xs:complexType>
        </xs:element>
       </xs:choice>
      <xs:attribute fixed="2.0" name="version" type="xs:decimal" use="required" />
    </xs:complexType>
  </xs:element>
</xs:schema>

然后我用这段代码:

from lxml import etree

parser = etree.XMLParser()
data = etree.parse(open("testschema.xsd"),parser)
root = data.getroot()
rootelement = root.getchildren()[0]
rootelementattribute = rootelement.getchildren()[0].getchildren()[1]
print "root element tags"
print rootelement[0].tag
print rootelementattribute.tag
elements = rootelement.getchildren()[0].getchildren()[0].getchildren()
elements_attribute = elements[0].getchildren()[0].getchildren()[1]
print "element tags"
print elements[0].tag
print elements_attribute.tag
subelements = elements[0].getchildren()[0].getchildren()[0].getchildren()
print "subelements"
print subelements

得到了以下输出:

root element tags
{http://www.w3.org/2001/XMLSchema}complexType
{http://www.w3.org/2001/XMLSchema}attribute
element tags
{http://www.w3.org/2001/XMLSchema}element
{http://www.w3.org/2001/XMLSchema}attribute
subelements
[<Element {http://www.w3.org/2001/XMLSchema}element at 0x7f2998fb16e0>, <Element {http://www.w3.org/2001/XMLSchema}element at 0x7f2998fb1780>, <Element {http://www.w3.org/2001/XMLSchema}element at 0x7f2998fb17d0>]

我不想在提取标签数据时看到"{http://www.w3.org/2001/XMLSchema}"这个部分(我不能修改xsd文件)。我需要这些xsd标签的信息,是因为我用它来验证一系列平面文件中的列名。在“元素”层面上,我提取了多个元素和子元素,并且我用字典来验证这些列。此外,如果有任何建议可以改进上面的代码,比如减少“getchildren”调用的次数,或者让代码更有条理,那就太好了。

4 个回答

0

最简单的方法就是用字符串切片来去掉命名空间前缀:

>>> print rootelement[0].tag[34:]
complexType
1

我想知道为什么 etree.XMLParser(ns_clean=True) 不好使。对我来说,它一直都没用,似乎是因为它从根节点的命名空间映射中获取了内容,然后把它替换成了空字符串。

print rootelement[0].tag.replace('{%s}' %root.nsmap['xs'], '')
3

我会使用:

print elem.tag.split('}')[-1]

不过你也可以用 xpath 函数 local-name()

print elem.xpath('local-name()')

关于减少 getchildren() 的调用:直接不使用它就行了。getchildren() 是一种过时的方法,用来获取直接子元素的列表(如果你真的想要这个,应该直接用 list(elem))。

你可以直接遍历元素,或者用索引访问它。例如:rootelement[0] 会给你 rootelement 的第一个子元素(这样比用 rootelement.getchildren()[0] 更有效率,因为后者会先像 list(rootelement) 一样创建一个新列表)。

撰写回答