如何告诉lxml.etree.tostring(element)不要在python中编写命名空间?

时间:2011-08-09 23:20:33

标签: python namespaces lxml tostring elementtree

我有一个巨大的xml文件(1 Gig)。我想将一些元素(entrys)移动到具有相同标题和规范的另一个文件。

假设原始文件包含带有标记<to_move>的此条目:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE some SYSTEM "some.dtd">
<some>
...
<to_move date="somedate">
    <child>some text</child>
    ...
...
</to_move>
...
</some>

我使用lxml.etree.iterparse迭代文件。工作良好。当我找到带有标记<to_move>的元素时,我们假设它存储在变量element中我做

new_file.write(etree.tostring(element))

但这会导致

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE some SYSTEM "some.dtd">
<some>
...
<to_move xmlns:="some" date="somedate">  # <---- Here is the problem. I don't want the namespace.
    <child>some text</child>
    ...
...
</to_move>
...
</some>

所以问题是:如何告诉etree.tostring()不要写xmlns:="some"。这可能吗?我使用了lxml.etree的api文档,但我找不到令人满意的答案。

这是我为etree.trostring找到的:

tostring(element_or_tree, encoding=None, method="xml",
xml_declaration=None, pretty_print=False, with_tail=True,
standalone=None, doctype=None, exclusive=False, with_comments=True)
  

将元素序列化为其XML的编码字符串表示形式   树。

对我来说,tostring()的每个参数似乎都没有帮助。有任何建议或更正吗?

3 个答案:

答案 0 :(得分:5)

我经常抓住一个命名空间来为它创建一个别名:

someXML = lxml.etree.XML(someString)
if ns is None:
      ns = {"m": someXML.tag.split("}")[0][1:]}
someid = someXML.xpath('.//m:ImportantThing//m:ID', namespaces=ns)

您可以执行类似的操作来获取命名空间,以便创建一个在使用tostring后清理它的正则表达式。

或者你可以清理输入字符串。找到第一个空格,检查它是否后跟xmlns,如果是,则删除整个xmlns位直到下一个空格,如果没有删除空格。重复,直到没有空格或xmlns声明。但是不要超过第一个>

答案 1 :(得分:2)

remove namespaces with XSLT有一种方式:

import io
import lxml.etree as ET


def remove_namespaces(doc):
    # http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl
    xslt='''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="no"/>

    <xsl:template match="/|comment()|processing-instruction()">
        <xsl:copy>
          <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
          <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
    </xsl:stylesheet>
    '''

    xslt_doc = ET.parse(io.BytesIO(xslt))
    transform = ET.XSLT(xslt_doc)
    doc = transform(doc)
    return doc

doc = ET.parse('data.xml')
doc = remove_namespaces(doc)
print(ET.tostring(doc))

产量

<some>

<to_move date="somedate">
    <child>some text</child>
</to_move>

</some>

答案 2 :(得分:2)

这更像是对'unutbu'的回答,其中需要一个清理命名空间的建议而不给出示例。这可能就是你要找的......

from lxml import objectify
objectify.deannotate(root, cleanup_namespaces=True)