Сохранение файлов XML с помощью ElementTree

Я пытаюсь разработать простой код Python (3.2) для чтения файлов XML, внесения некоторых исправлений и сохранения их обратно. Однако на этапе хранения ElementTree добавляет эту номенклатуру пространства имен. Например:

<ns0:trk>
  <ns0:name>ACTIVE LOG</ns0:name>
<ns0:trkseg>
<ns0:trkpt lat="38.5" lon="-120.2">
  <ns0:ele>6.385864</ns0:ele>
  <ns0:time>2011-12-10T17:46:30Z</ns0:time>
</ns0:trkpt>
<ns0:trkpt lat="40.7" lon="-120.95">
  <ns0:ele>5.905273</ns0:ele>
  <ns0:time>2011-12-10T17:46:51Z</ns0:time>
</ns0:trkpt>
<ns0:trkpt lat="43.252" lon="-126.453">
  <ns0:ele>7.347168</ns0:ele>
  <ns0:time>2011-12-10T17:52:28Z</ns0:time>
</ns0:trkpt>
</ns0:trkseg>
</ns0:trk>

Фрагмент кода ниже:

def parse_gpx_data(gpxdata, tzname=None, npoints=None, filter_window=None,
                   output_file_name=None):
        ET = load_xml_library();

    def find_trksegs_or_route(etree, ns):
        trksegs=etree.findall('.//'+ns+'trkseg')
        if trksegs:
            return trksegs, "trkpt"
        else: # try to display route if track is missing
            rte=etree.findall('.//'+ns+'rte')
            return rte, "rtept"

    # try GPX10 namespace first
    try:
        element = ET.XML(gpxdata)
    except ET.ParseError as v:
        row, column = v.position
        print ("error on row %d, column %d:%d" % row, column, v)

    print ("%s" % ET.tostring(element))
    trksegs,pttag=find_trksegs_or_route(element, GPX10)
    NS=GPX10
    if not trksegs: # try GPX11 namespace otherwise
        trksegs,pttag=find_trksegs_or_route(element, GPX11)
        NS=GPX11
    if not trksegs: # try without any namespace
        trksegs,pttag=find_trksegs_or_route(element, "")
        NS=""

    # Store the results if requested
    if output_file_name:
        ET.register_namespace('', GPX11)
        ET.register_namespace('', GPX10)
        ET.ElementTree(element).write(output_file_name, xml_declaration=True)

    return;

Я пробовал использовать register_namespace, но безрезультатно. Есть ли какие-то особые изменения для этой версии ElementTree 1.3?


person ilya1725    schedule 24.01.2012    source источник
comment
Скажите, если я понял ваш вопрос, вы хотели бы иметь <trk> вместо <ns0:trk> и так далее?   -  person Rik Poggi    schedule 24.01.2012
comment
Правильный. Я хотел бы иметь ‹trk› вместо ‹ns0:trk› и так далее.   -  person ilya1725    schedule 24.01.2012
comment
Это не настоящее решение, но поскольку кажется, что вы загружаете строку, пытались ли вы удалить пространство имен с помощью какого-либо регулярного выражения? После этого, если вы загружаете и сохраняете без, все должно быть в порядке.   -  person Rik Poggi    schedule 24.01.2012
comment
Привет Рик. Я сделаю это, все остальное не получится. Я хотел бы настроить ElementTree, чтобы не печатать его в первую очередь.   -  person ilya1725    schedule 25.01.2012


Ответы (4)


Чтобы избежать префикса ns0, пространство имен по умолчанию должно быть установлено перед чтением XML-данных.

ET.register_namespace('', "http://www.topografix.com/GPX/1/1")
ET.register_namespace('', "http://www.topografix.com/GPX/1/0")
person ilya1725    schedule 25.01.2012
comment
Вроде не раньше. Я могу прочитать файл XML и получить пространство имен, и только после этого установить register_namespace. tree = ET.parse(str(udx_path)) root = tree.getroot() ns = { # извлечь пространство имен корневого элемента 'udx': root.tag[1:root.tag.index('}')] } ET .register_namespace('', root.tag[1:root.tag.index('}')]) - person likern; 03.05.2017
comment
Это не полный способ сохранить разницу в анализируемой и выходной строке ElementTree (при использовании ElementTree.tostring(root)). Сингсингх завершен. - person Emil; 18.04.2018

Вам необходимо зарегистрировать все свои пространства имен, прежде чем анализировать файл xml.

Например: Если у вас есть входной XML-файл, подобный этому, и Capabilities является корнем вашего дерева элементов.

<Capabilities xmlns="http://www.opengis.net/wmts/1.0"
    xmlns:ows="http://www.opengis.net/ows/1.1"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:gml="http://www.opengis.net/gml"
    xsi:schemaLocation="http://www.opengis.net/wmts/1.0 http://schemas.opengis.net/wmts/1.0/wmtsGetCapabilities_response.xsd"
    version="1.0.0">

Затем вам нужно зарегистрировать все пространства имен, т.е. атрибуты, присутствующие с xmlns, следующим образом:

ET.register_namespace('', "http://www.opengis.net/wmts/1.0")
ET.register_namespace('ows', "http://www.opengis.net/ows/1.1")
ET.register_namespace('xlink', "http://www.w3.org/1999/xlink")
ET.register_namespace('xsi', "http://www.w3.org/2001/XMLSchema-instance")
ET.register_namespace('gml', "http://www.opengis.net/gml")
person singingsingh    schedule 15.07.2016
comment
Этот ответ является полным. - person gofvonx; 09.10.2019

Кажется, вам нужно объявить свое пространство имен, а это означает, что вам нужно изменить первую строку вашего xml с:

<ns0:trk>

на что-то вроде:

<ns0:trk xmlns:ns0="uri:">

После этого вы больше не будете получать ParseError: for unbound prefix: ..., а также:

elem.tag = elem.tag[(len('{uri:}'):]

удалит пространство имен.

person Rik Poggi    schedule 24.01.2012
comment
Привет Рик. Пример XML, который я показал, является выводом. Входной XML, который хорошо анализируется, не имеет префикса «ns0:». Это просто стандартный код GPX. - person ilya1725; 25.01.2012
comment
Если строка element = ET.XML(gpxdata) дает вам элемент с ns0, то проблема в gpxdata, и в этом случае у вас есть варианты: исправить gpxdata или выяснить, почему стандартный парсер так делает, и построить новый для ET.XML. - person Rik Poggi; 25.01.2012
comment
Исходные данные gpxdata не содержат записей ns0. Однако твой намек, Рик, как бы подвел меня к разгадке. По сути, ET.register_namespace('', GPX11) ET.register_namespace('', GPX10) нужно делать перед чтением, то есть ET.XML. - person ilya1725; 25.01.2012

Если вы попытаетесь распечатать корень, вы увидите что-то вроде этого: http://www.host.domain/path/to/your/xml/namespace}RootTag' at 0x0000000000558DB8>

Таким образом, чтобы избежать префикса ns0, вы должны изменить пространство имен по умолчанию перед синтаксическим анализом данных XML, как показано ниже:

ET.register_namespace('', "http://www.host.domain/path/to/your/xml/namespace")
person Naiim Khaskhoussi    schedule 22.11.2019