jjzjj

python - 降低 XML 文档中值的精度

coder 2024-06-30 原文

我有一个描述地理坐标的大型 XML 文档(准确地说是 KML);下面的代码片段应该可以让您了解它的外观。这里的问题是坐标是 double 的(小数点后 16 位),这会在进一步处理时造成很多问题(此外,小数点后一位实际上是十分之一纳米 - 我们的 GPS 不是那么精确)。

我一直在寻找将精度降低到给定值的任何方法,例如小数点后 5 位给了我们一米的精度。我尝试用 Python(使用 lxml)解析 XML,更改值并保存新文档,但在处理过程中文档的格式发生了很大变化,并以某种方式中断了进一步处理。

因此,我正在寻找一种就地降低精度的方法,以便更改原始文件中的值。我认为 AWK 应该可以解决问题,但遗憾的是我的尝试没有成功。

这里是 my XML 的例子.

<Document xmlns="http://www.opengis.net/kml/2.2">
    <Folder><name>Export_Output02</name>
        <Placemark>
            <Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
            <ExtendedData><SchemaData schemaUrl="#Export_Output02">
                <SimpleData name="species">1312</SimpleData>
                <SimpleData name="area">7848012</SimpleData>
                <SimpleData name="irrep_area">0.00000012742</SimpleData>
                <SimpleData name="groupID">2</SimpleData>
            </SchemaData></ExtendedData>
            <MultiGeometry>
                <Polygon>
                    <outerBoundaryIs>
                        <LinearRing>
                            <coordinates>-57.843052746056827,-33.032934004012787 -57.825312079170494,-33.089724736921667 -57.888494029914156,-33.073777852969904 -57.843052746056827,-33.032934004012787</coordinates>
                        </LinearRing>
                    </outerBoundaryIs>
                </Polygon>
                <Polygon>
                    <outerBoundaryIs>
                        <LinearRing>
                            <coordinates>-57.635769389832561,-33.032934004012787 -57.618028722946228,-33.089724736921667 -57.681210673689904,-33.073777852969904 -57.635769389832561,-33.032934004012787</coordinates>
                        </LinearRing>
                    </outerBoundaryIs>
                </Polygon>
            </MultiGeometry>
        </Placemark>
    </Folder>
</Document>

[编辑]

我的 Python 代码:

import glob
import argparse
from pykml import parser
from pykml.helpers import set_max_decimal_places

arg_parser = argparse.ArgumentParser(description='Script for batch reduction of precision of KML files', prog='KML precision reducer')

arg_parser.add_argument('-p', '--precision', type=int, default=5, help='Desired precision')
arg_parser.add_argument('-d', '--directory', default='./', help='Path to KML files')

args = arg_parser.parse_args()

path_to_kml = glob.glob(args.directory + '*.kml')
precision = args.precision

for kml_file in path_to_kml:
    print 'Processing ' + kml_file
    with open(kml_file) as file_read:
        doc = parser.parse(file_read)

    max_decimals={'longitude': precision, 'latitude': precision,}

    for element in doc.iter("*"):
        set_max_decimal_places(element, max_decimals)

    out_filename = kml_file.replace('.kml', '_out.kml')

    with open(out_filename, 'w') as file_write:
       doc.write(file_write, pretty_print=True, with_tail=True)

最佳答案

您可以使用 XSLT .下面的样式表使用 XSLT 2.0 .这也可以使用 XSLT 1.0,但它没有我在这里使用的 tokenize() 函数:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:gis="http://www.opengis.net/kml/2.2"
    version="2.0">

    <!-- This is an identity transform template - it copies all the nodes -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- this template has precedence over the identity template for the `coordinates` nodes -->
    <xsl:template match="gis:coordinates">
        <xsl:copy> <!-- it copies the element --> 
        <xsl:variable name="coords" select="tokenize(.,' ')"/> <!-- saves coordinate pairs in variable -->
        <xsl:for-each select="$coords"> <!-- for each coordinate pair, formats the values before and after the comma -->
            <xsl:value-of select="round(number(substring-before(.,','))*100000) div 100000"/>
            <xsl:text>,</xsl:text> <!-- puts the comma back between the coords -->
            <xsl:value-of select="round(number(substring-after(.,','))*100000) div 100000"/>
            <xsl:if test="position() != last()">
                <xsl:text> </xsl:text> <!-- puts the space back if it's not the last coord -->
            </xsl:if>
        </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

我在上面添加了一些注释来解释它是如何工作的。

如果将其应用于示例文档,它会将坐标截断为五位小数。这是一个显示转换后的 coordinates 元素的示例:

<LinearRing>
    <coordinates>-57.84305,-33.03293 -57.82531,-33.08972 -57.88849,-33.07378 -57.84305,-33.03293</coordinates>
</LinearRing>

这是一个 XSLT Fiddle 有一个工作结果。

我在上面的 XML Playground 中粘贴了您的完整 XML,它起作用了。我只是无法将 fiddle 与您的文件一起保存以将其链接到此处,因为文件太大,但您可以尝试将其粘贴到此处。转换整个文件大约需要 40 秒。

我不知道 Python 中的 XSLT 2.0 支持,但您可以使用命令行工具(例如 Saxon)运行转换,或者调用 Java 或其他支持 XSLT 2.0 的语言的程序(或者,如果您正在寻找针对这个特定问题的解决方案,可以使用在线工具来解决)。

关于python - 降低 XML 文档中值的精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24224318/

有关python - 降低 XML 文档中值的精度的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

  6. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  7. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  8. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  9. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  10. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

随机推荐