使用 lxml 添加具有与根元素不同命名空间的 xml 子元素

Add xml subelement with different namespaces than root element using lxml

这是 xml 我正在尝试构建的简化版本:

<BizData xmlns="urn:iso:std:iso:20022:tech:xsd:head.003.001.01" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:n1="urn:iso:std:iso:20022:tech:xsd:head.001.001.02" 
  xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.003.001.01 head.003.001.02_DTCC.xsd">
  <Hdr>
   <AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.02"             
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         
    xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.001.001.02 head.001.001.02.xsd"> 
   </AppHdr>
  </Hdr>
 </BizData>

Python代码

from lxml import etree as etree

if __name__ == '__main__':
attr_qname = etree.QName('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')
nsmap = {None: 'urn:iso:std:iso:20022:tech:xsd:head.003.001.01',
         'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
         'n1': 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02'
        }
root = etree.Element('BizData',
                     {attr_qname: 'urn:iso:std:iso:20022:tech:xsd:head.003.001.01 head.003.001.02_DTCC.xsd'},
                     nsmap)

hdr = etree.Element('hdr')
attr_qname = etree.QName('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')
nsmap = {None: 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02',
         'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
         }

app_hdr = etree.Element('AppHdr',
                {attr_qname: 'urn:iso:std:iso:20022:tech:xsd:head.001.001.02 head.001.001.02.xsd'},
                nsmap)
hdr.append(app_hdr)
root.append(hdr)

在附加到根之前打印 hdr 时,我得到了正确的输出:

<Hdr>
 <AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.02"             
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         
  xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.001.001.02 head.001.001.02.xsd"> 
 </AppHdr>
</Hdr> 

但是在将命名空间 xmlnsxmlns:xsi 附加到根之后消失了:

<BizData xmlns:n1="urn:iso:std:iso:20022:tech:xsd:head.001.001.02" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
 xmlns="urn:iso:std:iso:20022:tech:xsd:head.003.001.01" 
 xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.003.001.01 head.003.001.02_DTCC.xsd">
 <hdr>
  <AppHdr xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.001.001.02 head.001.001.02.xsd"/>
 </hdr>
</BizData>

我尝试使用 set 函数设置 xmlns:xsi 但这会导致错误 ..not a valid attribute...

有人有想法吗?

肮脏的解决方法

  1. 创建信封 (BizData)、Header (Hdr) 和有效载荷 (Pyld) 作为单独的 etree.Element
  2. 将它们转为字符串
  3. 组合字符串
  4. 写入xml文件

这会忽略任何类型的验证,但不会混淆命名空间。不理想,但可以。