Python解析xmlns属性动态变化的XML问题
解决动态命名空间下XML元素查找问题
问题背景
请求NuGet的nupsec XML时,根元素xmlns属性中的日期段(如2012/06、2013/05)会动态变化,硬编码命名空间后,xml.etree.ElementTree无法定位元素,返回None。
示例XML:
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> <metadata> <id>SharpZipLib</id> <version>1.1.0</version> <authors>ICSharpCode</authors> <owners>ICSharpCode</owners> <requireLicenseAcceptance>false</requireLicenseAcceptance> <licenseUrl>https://github.com/icsharpcode/SharpZipLib/blob/master/LICENSE.txt</licenseUrl> <projectUrl>https://github.com/icsharpcode/SharpZipLib</projectUrl> <description>SharpZipLib (#ziplib, formerly NZipLib) is a compression library for Zip, GZip, BZip2, and Tar written entirely in C# for .NET. It is implemented as an assembly (installable in the GAC), and thus can easily be incorporated into other projects (in any .NET language)</description> <releaseNotes>Please see https://github.com/icsharpcode/SharpZipLib/wiki/Release-1.1 for more information.</releaseNotes> <copyright>Copyright © 2000-2018 SharpZipLib Contributors</copyright> <tags>Compression Library Zip GZip BZip2 LZW Tar</tags> <repository type="git" url="https://github.com/icsharpcode/SharpZipLib" commit="45347c34a0752f188ae742e9e295a22de6b2c2ed"/> <dependencies> <group targetFramework=".NETFramework4.5"/> <group targetFramework=".NETStandard2.0"/> </dependencies> </metadata> </package>
原问题代码:
def fetch_nuget_spec(self, versioned_package): name = versioned_package.package.name.lower() version = versioned_package.version.lower() url = f'https://api.nuget.org/v3-flatcontainer/{name}/{version}/{name}.nuspec' response = requests.get(url) metadata = ET.fromstring(response.content) ns = {'nuspec': 'http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd'} license = metadata.find('./nuspec:metadata/nuspec:license', ns) if license is None: license_url=metadata.find('./nuspec:metadata/nuspec:licenseUrl', ns) if license_url is None: return { 'license': 'Not Found' } return {'license':license_url.text} else: if len(license.text)==0: print('SHIT') return { 'license': license.text }
方案1:动态提取命名空间(推荐)
直接从XML根元素提取xmlns属性值,无需关心日期段变化,是最可靠的XML处理方式。
修改后的代码:
import xml.etree.ElementTree as ET import requests def fetch_nuget_spec(self, versioned_package): name = versioned_package.package.name.lower() version = versioned_package.version.lower() url = f'https://api.nuget.org/v3-flatcontainer/{name}/{version}/{name}.nuspec' response = requests.get(url) root = ET.fromstring(response.content) # 动态获取根元素的命名空间 ns = {'nuspec': root.attrib.get('xmlns', '')} # 优先查找<license> license_elem = root.find('./nuspec:metadata/nuspec:license', ns) if license_elem is not None: license_text = license_elem.text.strip() if license_elem.text else 'Not Found' return {'license': license_text} # 找不到则查找<licenseUrl> license_url_elem = root.find('./nuspec:metadata/nuspec:licenseUrl', ns) if license_url_elem is not None: return {'license': license_url_elem.text.strip()} return {'license': 'Not Found'}
方案2:正则表达式匹配(不推荐)
仅当XML结构简单且稳定时使用,正则处理XML容易因标签嵌套、属性变化等出现错误。
示例代码:
import re import requests def fetch_nuget_spec(self, versioned_package): name = versioned_package.package.name.lower() version = versioned_package.version.lower() url = f'https://api.nuget.org/v3-flatcontainer/{name}/{version}/{name}.nuspec' response = requests.get(url) xml_content = response.text # 匹配<license>标签内容 license_match = re.search(r'<license[^>]*>(.*?)</license>', xml_content, re.DOTALL) if license_match: license_text = license_match.group(1).strip() return {'license': license_text if license_text else 'Not Found'} # 匹配<licenseUrl>标签内容 license_url_match = re.search(r'<licenseUrl[^>]*>(.*?)</licenseUrl>', xml_content, re.DOTALL) if license_url_match: return {'license': license_url_match.group(1).strip()} return {'license': 'Not Found'}
内容的提问来源于stack exchange,提问作者nikhil
相关产品推荐
相关产品推荐

