使用 ElementTree 保存 XML 文件

Posted

技术标签:

【中文标题】使用 ElementTree 保存 XML 文件【英文标题】:Saving XML files using ElementTree 【发布时间】:2012-02-17 11:25:17 【问题描述】:

我正在尝试开发简单的 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>

代码sn-p如下:

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 是否有任何特定更改?

【问题讨论】:

如果我理解你的问题,请告诉我,你想要&lt;trk&gt; 而不是&lt;ns0:trk&gt; 等等? 正确。我想要 而不是 等等。 这不是一个真正的解决方案,但由于您似乎加载了一个字符串,您是否尝试使用一些正则表达式删除命名空间?之后,如果您在没有任何内容的情况下加载和保存应该没问题。 嗨瑞克。我会做其他一切都失败了。我想首先将 ElementTree 配置为不打印它。 【参考方案1】:

看来您必须声明您的命名空间,这意味着您需要将 xml 的第一行更改为:

<ns0:trk>

类似于:

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

一旦这样做,您将不再获得ParseError: for unbound prefix: ...,并且:

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

将删除命名空间。

【讨论】:

嗨瑞克。我展示的示例 XML 是 输出。解析良好的输入 XML 没有“ns0:”前缀。它只是标准的 GPX 代码。 如果element = ET.XML(gpxdata) 行给你一个带有ns0 的元素,那么“问题”在gpxdata 中,在这种情况下你必须选择:“修复”gpxdata 或找出标准的原因parser 会这样做并为ET.XML 构建一个新的。 原始 gpxdata 没有任何 ns0 条目。但是,Rik 的提示让我找到了解决方案。基本上,ET.register_namespace('', GPX11)ET.register_namespace('', GPX10)应该在阅读之前完成,即ET.XML【参考方案2】:

为了避免ns0 前缀,默认命名空间应该设置在之前读取XML数据。

ET.register_namespace('', "http://www.topografix.com/GPX/1/1")
ET.register_namespace('', "http://www.topografix.com/GPX/1/0")

【讨论】:

看起来不像以前了。我能够读取 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('')]) 这不是保留已解析和输出 ElementTree 字符串差异的完整方法(如果使用 ElementTree.tostring(root))。歌唱完成了。【参考方案3】:

在解析 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")

【讨论】:

这个答案是完整的。【参考方案4】:

如果您尝试打印根目录,您将看到如下内容: http://www.host.domain/path/to/your/xml/namespaceRootTag' 在 0x0000000000558DB8>

因此,为了避免 ns0 前缀,您必须在解析 XML 数据之前更改默认命名空间,如下所示:

ET.register_namespace('', "http://www.host.domain/path/to/your/xml/namespace")

【讨论】:

以上是关于使用 ElementTree 保存 XML 文件的主要内容,如果未能解决你的问题,请参考以下文章

使用Python和ElementTree解析XML

python解析xml文件之xml.etree.cElementTree和xml.etree.ElementTree区别

访问使用 ElementTree 解析的 xml 文件中的嵌套子项

如何让 Python 的 ElementTree 漂亮地打印到 XML 文件?

Python不归路_xml.etree.ElementTree模块

使用 xml.etree.ElementTree 在 python 中解析 XML