Python解析带命名空间的UBL Invoice XML文档问题
解析UBL格式Invoice XML的正确方法
UBL格式XML的核心难点是命名空间的正确映射与使用,xml.etree.ElementTree需要显式指定命名空间才能定位到目标节点。以下是针对你需求的完整解决方案:
1. 定义UBL命名空间映射
UBL发票常用的命名空间需要提前映射,方便后续节点查找:
ns = { 'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', 'default': 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' }
2. 示例UBL InvoiceLine片段
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"> <cac:InvoiceLine> <cbc:ID>LINE-001</cbc:ID> <cbc:InvoicedQuantity unitCode="PCE">2</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">200.00</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>Wireless Mouse</cbc:Name> <cbc:Description>Ergonomic wireless optical mouse</cbc:Description> </cac:Item> <cac:TaxTotal> <cbc:TaxAmount currencyID="EUR">42.00</cbc:TaxAmount> <cac:TaxSubtotal> <cbc:Percent>21</cbc:Percent> </cac:TaxSubtotal> </cac:TaxTotal> </cac:InvoiceLine> </Invoice>
3. 修正后的解析代码
import xml.etree.ElementTree as ET # 加载XML文档 tree = ET.parse('your_invoice.xml') # 替换为你的XML文件路径 root = tree.getroot() # 提取所有InvoiceLine节点 invoice_lines = root.findall('.//cac:InvoiceLine', ns) # 遍历提取目标字段 for line in invoice_lines: # 基础字段提取 line_id = line.find('cbc:ID', ns).text invoiced_qty = line.find('cbc:InvoicedQuantity', ns).text qty_unit = line.find('cbc:InvoicedQuantity', ns).attrib.get('unitCode') line_ext_amount = line.find('cbc:LineExtensionAmount', ns).text amount_currency = line.find('cbc:LineExtensionAmount', ns).attrib.get('currencyID') # 商品信息提取 item = line.find('cac:Item', ns) item_name = item.find('cbc:Name', ns).text item_desc = item.find('cbc:Description', ns).text # 税费信息提取 tax_total = line.find('cac:TaxTotal', ns) tax_amount = tax_total.find('cbc:TaxAmount', ns).text tax_percent = tax_total.find('.//cbc:Percent', ns).text # 输出结果(可改为存入字典/列表) print(f"行ID: {line_id}") print(f"开票数量: {invoiced_qty} {qty_unit}") print(f"行扩展金额: {line_ext_amount} {amount_currency}") print(f"商品名称: {item_name}") print(f"商品描述: {item_desc}") print(f"税额: {tax_amount} {amount_currency}") print(f"税率: {tax_percent}%") print("-" * 30)
4. 关键注意事项
- 所有节点查找必须传入命名空间映射参数
ns,否则无法识别带前缀的UBL节点。 - 带属性的节点(如
InvoicedQuantity的unitCode),通过.attrib.get()提取属性值。 - 层级较深的节点(如
Percent),可使用相对路径'.//cbc:Percent'直接定位,无需逐层查找。 - 若你的XML命名空间前缀不同(比如用
ns1代替cbc),只需修改ns字典中的前缀对应关系即可。
内容的提问来源于stack exchange,提问作者Pecooou
相关产品推荐
相关产品推荐

