You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带命名空间的JSON转XML代码异常:多余命名空间前缀自动生成

问题描述

我用Python的xml.etree.ElementTree把带命名空间的JSON转成指定XML时遇到两个核心问题:

  1. 输出XML自动生成未定义的xmlns:ns0="common_v52_0"命名空间声明
  2. JSON中的common_v52_0:Description被错误转换为<ns0:Description>,不符合预期格式
    同时还有两处细节需要调整:
  • common_v52_0:Description文本里的下划线要替换为空格
  • air:EMD的FulfillmentTypeDescription、air:FeeApplication的文本里的下划线也要替换为空格

原始JSON数据

{
  "Type":"Baggage",
  "TotalPrice":"INR10080",
  "SupplierCode":"AI",
  "CreateDate":"2023-08-16T06:29:51.961+00:00",
  "ServiceStatus":"Offered",
  "SequenceNumber":"1204",
  "ServiceSubCode":"0C2",
  "SSRCode":"XBAG",
  "IssuanceReason":"C",
  "Key":"PNmYlnTqWDKA0ie2FAAAAA==",
  "AssessIndicator":"MileageOrCurrency",
  "InclusiveOfTax":"true",
  "InterlineSettlementAllowed":"false",
  "GeographySpecification":"Sector",
  "Source":"MCE",
  "ViewableOnly":"false",
  "TotalWeight":"20KG",
  "ProviderCode":"1G",
  "Quantity":"1",
  "BasePrice":"INR9600",
  "ApproximateTotalPrice":"INR10080",
  "ApproximateBasePrice":"INR9600",
  "Taxes":"INR480",
  "IsRepriceRequired":"false",
  "common_v52_0:ServiceData":{
     "BookingTravelerRef":"PNmYlnTqWDKAvie2FAAAAA==",
     "AirSegmentRef":"dnVZlnUqWDKAXC/qFAAAAA==",
     "TravelerType":"ADT",
     "common_v52_0:CabinClass":{
        "Type":"Economy"
     }
  },
  "common_v52_0:ServiceInfo":{
     "common_v52_0:Description":"UPTO44LB_20KG_BAGGAGE"
  },
  "air:TaxInfo":{
     "Category":"K3",
     "Amount":"INR480",
     "Key":"PNmYlnTqWDKA3ie2FAAAAA=="
  },
  "air:EMD":{
     "FulfillmentType":"2",
     "AssociatedItem":"Flight",
     "RefundReissueIndicator":"NonRefundable",
     "Commissionable":"false",
     "Booking":"SSR",
     "FulfillmentTypeDescription":"Associated_to_a_flight_coupon_of_a_ticket"
  },
  "air:FeeApplication":{
     "Code":"4",
     "#text":"Per_travel"
  }
}

预期XML格式

<air:OptionalService Type="Baggage" TotalPrice="INR10080" SupplierCode="AI"
                     CreateDate="2023-08-16T06:29:51.961+00:00" ServiceStatus="Offered"
                     SequenceNumber="1204" ServiceSubCode="0C2" SSRCode="XBAG" IssuanceReason="C"
                     Key="PNmYlnTqWDKA0ie2FAAAAA==" AssessIndicator="MileageOrCurrency"
                     InclusiveOfTax="true" InterlineSettlementAllowed="false"
                     GeographySpecification="Sector" Source="MCE" ViewableOnly="false"
                     TotalWeight="20KG" ProviderCode="1G" Quantity="1" BasePrice="INR9600"
                     ApproximateTotalPrice="INR10080" ApproximateBasePrice="INR9600" Taxes="INR480"
                     IsRepriceRequired="false">
                     <common_v52_0:ServiceData BookingTravelerRef="PNmYlnTqWDKAvie2FAAAAA=="
                         AirSegmentRef="dnVZlnUqWDKAXC/qFAAAAA==" TravelerType="ADT">
                         <common_v52_0:CabinClass Type="Economy" />
                     </common_v52_0:ServiceData>
                     <common_v52_0:ServiceInfo>
                         <common_v52_0:Description>UPTO44LB 20KG BAGGAGE</common_v52_0:Description>
                     </common_v52_0:ServiceInfo>
                     <air:TaxInfo Category="K3" Amount="INR480" Key="PNmYlnTqWDKA3ie2FAAAAA==" />
                     <air:EMD FulfillmentType="2" AssociatedItem="Flight"
                         RefundReissueIndicator="NonRefundable" Commissionable="false" Booking="SSR"
                         FulfillmentTypeDescription="Associated to a flight coupon of a ticket" />
                     <air:FeeApplication Code="4">Per travel</air:FeeApplication>
                 </air:OptionalService>

原始代码

import xml.etree.ElementTree as ET
def json_to_xml(element, data):
    for key, value in data.items():
        if isinstance(value, dict):
            sub_element = ET.SubElement(element, key)
            json_to_xml(sub_element, value)
        else:
            if ":" in key:
                ns_prefix, local_name = key.split(":")
                print(ns_prefix, local_name)
                sub_element = ET.SubElement(element, "{" + ns_prefix + "}" + local_name)
                sub_element.text = value
            if key == "#text":
                element.text = value
            else:
                element.set(key, value)

root = ET.Element("air:OptionalService")

json_to_xml(root, json_data)

tree = ET.ElementTree(root)

tree.write("test.xml", encoding="utf-8", xml_declaration=True)

当前错误输出

<?xml version='1.0' encoding='utf-8'?>
<air:OptionalService xmlns:ns0="common_v52_0" Type="Baggage" TotalPrice="INR10080" SupplierCode="AI"
    CreateDate="2023-08-16T06:29:51.961+00:00" ServiceStatus="Offered" SequenceNumber="1204"
    ServiceSubCode="0C2" SSRCode="XBAG" IssuanceReason="C" Key="PNmYlnTqWDKA0ie2FAAAAA=="
    AssessIndicator="MileageOrCurrency" InclusiveOfTax="true" InterlineSettlementAllowed="false"
    GeographySpecification="Sector" Source="MCE" ViewableOnly="false" TotalWeight="20KG"
    ProviderCode="1G" Quantity="1" BasePrice="INR9600" ApproximateTotalPrice="INR10080"
    ApproximateBasePrice="INR9600" Taxes="INR480" IsRepriceRequired="false">
    <common_v52_0:ServiceData BookingTravelerRef="PNmYlnTqWDKAvie2FAAAAA=="
        AirSegmentRef="dnVZlnUqWDKAXC/qFAAAAA==" TravelerType="ADT">
        <common_v52_0:CabinClass Type="Economy" />
    </common_v52_0:ServiceData>
    <common_v52_0:ServiceInfo common_v52_0:Description="UPTO44LB_20KG_BAGGAGE">
        <ns0:Description>UPTO44LB_20KG_BAGGAGE</ns0:Description>
    </common_v52_0:ServiceInfo>
    <air:TaxInfo Category="K3" Amount="INR480" Key="PNmYlnTqWDKA3ie2FAAAAA==" />
    <air:EMD FulfillmentType="2" AssociatedItem="Flight" RefundReissueIndicator="NonRefundable"
        Commissionable="false" Booking="SSR"
        FulfillmentTypeDescription="Associated_to_a_flight_coupon_of_a_ticket" />
    <air:FeeApplication Code="4">Per_travel</air:FeeApplication>
</air:OptionalService>

修正后的代码
import xml.etree.ElementTree as ET
import json

# 显式注册命名空间前缀,避免自动生成ns0这类默认前缀
ET.register_namespace('air', 'air')
ET.register_namespace('common_v52_0', 'common_v52_0')

def replace_underscores(text):
    """统一替换文本中的下划线为空格"""
    return text.replace('_', ' ') if isinstance(text, str) else text

def json_to_xml(element, data):
    for key, value in data.items():
        # 优先处理带命名空间的键
        if ":" in key:
            ns_prefix, local_name = key.split(":")
            qname = ET.QName(ns_prefix, local_name)
            if isinstance(value, dict):
                # 是字典则创建子元素
                sub_element = ET.SubElement(element, qname)
                json_to_xml(sub_element, value)
            else:
                # 不是字典则作为属性处理
                element.set(qname, replace_underscores(value))
        elif key == "#text":
            # 处理元素文本内容
            element.text = replace_underscores(value)
        elif isinstance(value, dict):
            # 处理不带命名空间的字典类型键
            sub_element = ET.SubElement(element, key)
            json_to_xml(sub_element, value)
        else:
            # 处理不带命名空间的属性
            element.set(key, replace_underscores(value))

# 用QName初始化根元素,确保命名空间识别正确
root = ET.Element(ET.QName('air', 'OptionalService'))

# 加载JSON数据(替换为你的JSON文件路径或直接传入已加载的字典)
with open('your_json_file.json', 'r', encoding='utf-8') as f:
    json_data = json.load(f)

json_to_xml(root, json_data)

tree = ET.ElementTree(root)
# 写入时保持空元素的简洁格式
tree.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=True)
代码修改说明
  1. 注册命名空间:通过ET.register_namespace显式绑定前缀与命名空间,防止ElementTree自动生成ns0这类默认前缀。
  2. 修复命名空间处理逻辑:用ET.QName统一处理带命名空间的元素和属性,避免之前把属性错误转换为元素的问题。
  3. 调整判断顺序:优先处理带命名空间的键,再处理文本和字典类型,解决逻辑冲突导致的重复生成问题。
  4. 统一下划线替换:新增工具函数批量处理所有需要替换下划线的文本字段。
  5. 根元素初始化优化:用ET.QName创建根元素,确保命名空间前缀被正确识别。
最终输出XML
<?xml version='1.0' encoding='utf-8'?>
<air:OptionalService Type="Baggage" TotalPrice="INR10080" SupplierCode="AI"
                     CreateDate="2023-08-16T06:29:51.961+00:00" ServiceStatus="Offered"
                     SequenceNumber="1204" ServiceSubCode="0C2" SSRCode="XBAG" IssuanceReason="C"
                     Key="PNmYlnTqWDKA0ie2FAAAAA==" AssessIndicator="MileageOrCurrency"
                     InclusiveOfTax="true" InterlineSettlementAllowed="false"
                     GeographySpecification="Sector" Source="MCE" ViewableOnly="false"
                     TotalWeight="20KG" ProviderCode="1G" Quantity="1" BasePrice="INR9600"
                     ApproximateTotalPrice="INR10080" ApproximateBasePrice="INR9600" Taxes="INR480"
                     IsRepriceRequired="false">
    <common_v52_0:ServiceData BookingTravelerRef="PNmYlnTqWDKAvie2FAAAAA=="
                               AirSegmentRef="dnVZlnUqWDKAXC/qFAAAAA==" TravelerType="ADT">
        <common_v52_0:CabinClass Type="Economy" />
    </common_v52_0:ServiceData>
    <common_v52_0:ServiceInfo>
        <common_v52_0:Description>UPTO44LB 20KG BAGGAGE</common_v52_0:Description>
    </common_v52_0:ServiceInfo>
    <air:TaxInfo Category="K3" Amount="INR480" Key="PNmYlnTqWDKA3ie2FAAAAA==" />
    <air:EMD FulfillmentType="2" AssociatedItem="Flight"
             RefundReissueIndicator="NonRefundable" Commissionable="false" Booking="SSR"
             FulfillmentTypeDescription="Associated to a flight coupon of a ticket" />
    <air:FeeApplication Code="4">Per travel</air:FeeApplication>
</air:OptionalService>

内容的提问来源于stack exchange,提问作者BiswajitPaloi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 02:20:54