python-降低XML文档中值的精度
作者:互联网
我有一个描述地理坐标的大型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