如何在python中从xml中删除ns?

时间:2017-08-22 12:08:36

标签: python xml python-3.x

我有一个像这样的xml:

<?xml version="1.0" encoding="UTF-8"?>
<ns0:epp xmlns:ns0="urn:ietf:params:xml:ns:epp-1.0" 
 xmlns:ns1="http://epp.nic.ir/ns/contact-1.0">
   <ns0:command>
      <ns0:check>
         <ns1:check>
            <ns1:id>ex61-irnic</ns1:id>
            <ns1:id>ex999-irnic</ns1:id>
            <ns1:authInfo>
               <ns1:pw>1487441516170712</ns1:pw>
            </ns1:authInfo>
         </ns1:check>
      </ns0:check>
      <ns0:clTRID>TEST-12345</ns0:clTRID>
   </ns0:command>
</ns0:epp>

我想用python 3将其更改为:

<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
   <command>
      <check>
         <check>
            <id>ex61-irnic</id>
            <id>ex999-irnic</id>
            <authInfo>
               <pw>1487441516170712</pw>
            </authInfo>
         </check>
      </check>
      <clTRID>TEST-12345</clTRID>
   </command>
</epp>

我试图从lxml模块中删除带有objectify.deannotate的ns。 但它不起作用。 你能帮助我实现我的目标吗?

2 个答案:

答案 0 :(得分:3)

这是Remove namespace and prefix from xml in python using lxml的组合,它显示了如何修改元素的命名空间,lxml: add namespace to input file显示了如何重置顶级命名空间映射。

代码有点hacky(我特别怀疑它是否是使用_setroot方法的犹太教),但似乎有效:

from lxml import etree

inputfile = 'data.xml'
target_ns = 'urn:ietf:params:xml:ns:epp-1.0'
nsmap = {None: target_ns}

tree = etree.parse(inputfile)
root = tree.getroot()

# here we set the namespace of all elements to target_ns
for elem in root.getiterator():
    tag = etree.QName(elem.tag)
    elem.tag = '{%s}%s' % (target_ns, tag.localname)

# create a new root element and set the namespace map, then
# copy over all the child elements    
new_root = etree.Element(root.tag, nsmap=nsmap)
new_root[:] = root[:]

# create a new elementtree with new_root so that we can use the
# .write method.
tree = etree.ElementTree()
tree._setroot(new_root)

tree.write('done.xml',
           pretty_print=True, xml_declaration=True, encoding='UTF-8')

根据您的样本输入,这将在done.xml中生成:

<?xml version='1.0' encoding='UTF-8'?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"><command>
      <check>
         <check>
            <id>ex61-irnic</id>
            <id>ex999-irnic</id>
            <authInfo>
               <pw>1487441516170712</pw>
            </authInfo>
         </check>
      </check>
      <clTRID>TEST-12345</clTRID>
   </command>
</epp>

答案 1 :(得分:3)

考虑XSLT,这是专门用于转换XML文件的专用语言,例如删除命名空间。 Python的第三方模块lxml可以运行XSLT 1.0脚本。并且因为XSLT脚本 XML文件,所以您可以像任何XML一样从文件或字符串进行解析。不需要循环或条件if逻辑。此外,您可以在其他语言(PHP,Java,C#等)中使用此XSLT脚本

XSLT (另存为.xsl文件,将在Python中引用)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!-- IDENTITY TRANSFROM: COPY DOC AS IS -->
  <xsl:template match="@*|node()">
    <xsl:copy>    
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- REMOVE NAMESPACE PREFIXES, ADD DOC NAMESPACE -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="urn:ietf:params:xml:ns:epp-1.0">    
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

<强>的Python

import lxml.etree as et

# LOAD XML AND XSL
doc = et.parse('Input.xml')
xsl = et.parse('XSLT_Script.xsl')

# CONFIGURE AND RUN TRANSFORMER
transform = et.XSLT(xsl)    
result = transform(doc)

# OUTPUT RESULT TREE TO FILE
with open('Output.xml', 'wb') as f:
    f.write(result)

<强>输出

<?xml version="1.0"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <check>
      <check>
        <id>ex61-irnic</id>
        <id>ex999-irnic</id>
        <authInfo>
          <pw>1487441516170712</pw>
        </authInfo>
      </check>
    </check>
    <clTRID>TEST-12345</clTRID>
  </command>
</epp>