Как сказать lxml.etree.tostring (element) не писать пространства имен в python?

у меня есть огромный xml-файл (1 концерт). Я хочу переместить некоторые элементы (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". Возможно ли это? Я struggeled с API-документация библиотека lxml.etree, но я не мог найти удовлетворительного ответа.

это то, что я нашел для 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 ответов


Я часто хватаю пространство имен, чтобы сделать псевдоним для него следующим образом:

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. Но не проходите мимо первый >.


это больше в комментарии к ответу "unutbu", в котором было предложено очистить пространство имен без приведения примера. это может быть то, что вы ищете...

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

есть способ удалить пространства имен с помощью 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>