ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-11-21 16:06:04  阅读:266  来源: 互联网

标签:awk xml xslt python xml-parsing


我有一个描述地理坐标的大型XML文档(准确地说是KML).下面的代码段将使您了解其外观.这里的问题是坐标是双精度的(小数点后16位),这会在进一步处理中引起很多问题(此外,最后的小数点后实际上是十分之一纳米-我们的GPS不够精确).

我正在寻找将精度降低到给定值的任何方法,例如小数点后五位给我们一个仪表的准确性.我尝试用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>

我在上面解释了它的工作原理时添加了一些评论.

如果将其应用于示例文档,它将把坐标截断为五个十进制数字.这是显示转换后的坐标元素的示例:

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

这是XSLT Fiddle的工作结果.

我将完整的XML粘贴到上面的XML Playground中,并且可以正常工作.我只是无法将小提琴与您的文件一起保存以将其链接到此处,因为文件太大,但是您可以尝试将其粘贴到此处.转换整个文件大约需要40秒钟.

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

标签:awk,xml,xslt,python,xml-parsing
来源: https://codeday.me/bug/20191121/2053127.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有