如何按xsi:type对Esri文件地理数据库的XML schema排序?
解决Esri地理数据库XML按标签和DataElement类型排序问题
我需要处理Esri文件地理数据库的schema片段XML,要求按标签名称和DataElement的xsi:type属性排序。现有的XML排序方案都不适用我的场景,目前已实现按标签排序,但无法完成DataElement的类型排序。
原始XML数据与初始代码
import xml.etree.ElementTree as ET from operator import attrgetter data = """<esri:Workspace xmlns:esri='http://www.esri.com/schemas/ArcGIS/10.8' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema'> <WorkspaceDefinition xsi:type='esri:WorkspaceDefinition'> <WorkspaceType>esriLocalDatabaseWorkspace</WorkspaceType> <Version/> <Domains xsi:type='esri:ArrayOfDomain'/> <Sequences xsi:type='esri:ArrayOfSequence'/> <DatasetDefinitions xsi:type='esri:ArrayOfDataElement'> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureDataset'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> </DatasetDefinitions> </WorkspaceDefinition> <WorkspaceData xsi:type='esri:WorkspaceData'/> </esri:Workspace>""" root_1 = ET.fromstring(data)
期望排序效果
WorkspaceData {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:WorkspaceData'} WorkspaceDefinition {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:WorkspaceDefinition'} DatasetDefinitions {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:ArrayOfDataElement'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureClass'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureClass'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureClass'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureClass'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureClass'} DataElement {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:DEFeatureDataset'} Domains {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:ArrayOfDomain'} Sequences {'{http://www.w3.org/2001/XMLSchema-instance}type': 'esri:ArrayOfSequence'} Version {} WorkspaceType {}
现有代码(仅实现标签排序)
root_1[:] = sorted(root_1, key=attrgetter("tag")) # WorkspaceData, WorkspaceDefinition for node in root_1.findall("*"): # DatasetDefinitions, Domains, Sequences, Version, WorkspaceType node[:] = sorted(node, key=attrgetter("tag")) print(node) for subnode in node.findall("*"): #DataElement, Domain subnode[:] = sorted(subnode, key=attrgetter("tag")) #subnode[:] = sorted(subnode, key=subnode.get['xsi:type']) # not working! print(" ", subnode.tag, subnode.attrib) for subsubnode in subnode.findall("*"): print(" ", subsubnode.tag, subsubnode.attrib) subsubnode[:] = sorted(subsubnode, key=attrgetter("tag"))
解决方案
问题出在xsi:type的命名空间处理上,XML属性中的xsi是前缀,对应的完整命名空间是http://www.w3.org/2001/XMLSchema-instance,因此不能直接用'xsi:type'作为键,必须使用完整的命名空间键'{http://www.w3.org/2001/XMLSchema-instance}type'。
修改后的完整代码:
import xml.etree.ElementTree as ET from operator import attrgetter data = """<esri:Workspace xmlns:esri='http://www.esri.com/schemas/ArcGIS/10.8' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema'> <WorkspaceDefinition xsi:type='esri:WorkspaceDefinition'> <WorkspaceType>esriLocalDatabaseWorkspace</WorkspaceType> <Version/> <Domains xsi:type='esri:ArrayOfDomain'/> <Sequences xsi:type='esri:ArrayOfSequence'/> <DatasetDefinitions xsi:type='esri:ArrayOfDataElement'> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureDataset'/> <DataElement xsi:type='esri:DEFeatureClass'/> <DataElement xsi:type='esri:DEFeatureClass'/> </DatasetDefinitions> </WorkspaceDefinition> <WorkspaceData xsi:type='esri:WorkspaceData'/> </esri:Workspace>""" root_1 = ET.fromstring(data) # 根节点按标签排序 root_1[:] = sorted(root_1, key=attrgetter("tag")) # 遍历WorkspaceDefinition下的子节点,按标签排序 for node in root_1.findall("*"): node[:] = sorted(node, key=attrgetter("tag")) # 获取节点的本地名称(去掉命名空间前缀) node_local_name = node.tag.split('}')[-1] print(f"{node_local_name} {node.attrib}") for subnode in node.findall("*"): subnode_local_name = subnode.tag.split('}')[-1] # 针对DatasetDefinitions下的DataElement,按xsi:type排序 if subnode_local_name == "DatasetDefinitions": # 按xsi:type属性排序,把DEFeatureClass放在前面 subnode[:] = sorted(subnode, key=lambda elem: elem.get('{http://www.w3.org/2001/XMLSchema-instance}type')) else: subnode[:] = sorted(subnode, key=attrgetter("tag")) print(f" {subnode_local_name} {subnode.attrib}") for subsubnode in subnode.findall("*"): subsubnode_local_name = subsubnode.tag.split('}')[-1] print(f" {subsubnode_local_name} {subsubnode.attrib}") subsubnode[:] = sorted(subsubnode, key=attrgetter("tag"))
说明
- 命名空间处理:通过
tag.split('}')[-1]获取节点的本地名称,避免命名空间前缀影响输出可读性。 - DataElement排序:针对
DatasetDefinitions节点,使用lambda表达式提取xsi:type的完整属性键进行排序,确保DEFeatureClass类型的节点排在DEFeatureDataset之前。 - 层级输出:调整打印格式,匹配期望的缩进效果,让输出结构更清晰。
内容的提问来源于stack exchange,提问作者pinkiko
相关产品推荐
相关产品推荐

