Запазване на 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
Това не е истинско решение, но тъй като изглежда, че зареждате низ, опитвали ли сте да премахнете пространството от имена с някакъв regexp? След това, ако заредите и запазите без всичко трябва да е наред.   -  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 файл и да получа namespace и едва след това да задам register_namespace. дърво = ET.parse(str(udx_path)) корен = дърво.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)). singingsingh е завършен. - person Emil; 18.04.2018

Трябва да регистрирате всичките си пространства от имена, преди да анализирате xml файл.

Например: Ако имате въведен xml като този и Възможности е коренът на вашето дърво на елементите.

<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' на 0x0000000000558DB8>

Така че, за да избегнете префикса ns0, трябва да промените пространството на имената по подразбиране, преди да анализирате XML данните, както е показано по-долу:

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