【问题标题】:Show XML element value if number of characters exceeded given threshold如果超过给定阈值的字符数,则显示XML元素值
【发布时间】:2014-08-05 09:36:55
【问题描述】:

我有一堆大型 XML 文档,其中包含按以下方式排列的地理空间信息(KML,如果有人感兴趣的话):

<Placemark><SimpleData name="species">Unique number</SimpleData> ... coordinates</Placemark>

我想列出地标标签之间的字符总数超过给定阈值的所有物种 ID - 1,000,000。以下 AWK 脚本指示哪些行超出了限制:

for kmlfile in *.kml; do
    echo "Processing $kmlfile"
    awk -- '/<Placemark>/,/<\/Placemark>/ { if (length() > 10000) { printf("Line %d has %d characters\n", NR, length()); } }' $kmlfile
done

但我不知道如何让它显示物种 ID 而不是行号。任何想法如何使它成为 AWK、Python 或其他任何你喜欢的东西?

这是一个 sn-p 文档的样子:

<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>

还有一个完整文件的示例:link to GDrive

[编辑] 我应该补充一点,谷歌融合表对“地标”中的字符数进行了特殊限制。每个地标都描述了地图上的特定特征,并且地图上可能有许多特征。如果任何 Placemark 超过 1M 字符限制,则转换为融合表将失败。

【问题讨论】:

  • 当您的数据采用 XML 格式时,您为什么要计算字符数?任意字符是否以任何方式相关?例如,您不能使用 XML 提取和测试元素的内容吗?使用 XML 方法很容易计算某个元素中的字符数。在您实际选择多个文件的情况下,为什么不测试文件大小? (在我看来,10000 和 &lt;Placemark&gt; 之外的几个字符之间的差异非常小,并且无关紧要。)也许你应该描述你想要实现的目标。
  • 感谢@helderdarocha 再次查看我的问题。 Google 融合表不接受超过一百万个字符的“地标”。出于这个原因,我需要找到所有超过此限制的地标并对它们执行一些手动预处理。由于我有 6000 个文件,我不想一个一个地检查哪个“物种”违反了限制。如何提取“地标”?我尝试了像link 这样的示例,但我总是得到一个空列表。

标签: python xml awk xml-parsing


【解决方案1】:

我想出了一个粗略的 Python 脚本来完成这项工作。当然这不是最好的方法,所以如果你有更好的方法,我会很高兴看到它。此外,我提取 specie ID 的方式非常丑陋 - 关于 hot 使其更漂亮的建议也很受欢迎。

import glob
from collections import namedtuple
Placemark = namedtuple('Placemark', 'found no_characters specie_id end_idx')


def GetPlacemark(input_file, start):
    start_idx = input_file.find('Placemark', start)
    end_idx = input_file.find('/Placemark', start)
    if start_idx == -1 or end_idx == -1:
        return Placemark(False, -1, -1, -1)
    no_characters = end_idx - start_idx
    specie_name_idx = input_file.find('species', start_idx, end_idx)
    specie_id_start_idx = input_file.find('>', specie_name_idx)
    specie_id_end_idx = input_file.find('<', specie_name_idx)
    specie_id = int(data[specie_id_start_idx+1:specie_id_end_idx])
    return Placemark(True, no_characters, specie_id, end_idx)

path_to_kml = glob.glob('*.kml')
for kml_file in path_to_kml:
    print 'Processing ' + kml_file
    with open (kml_file, "r") as myfile:
        data=myfile.read().replace('\n', '')

    placemarks = []
    current_idx = 0

    while True:
        mark = GetPlacemark(data, current_idx)
        if mark.found:
            placemarks.append(mark)
            current_idx = mark.end_idx + 1
        else:
            break

    for placemark in placemarks:
        if placemark.no_characters > 1000000:
            print 'Specie %d has %d characters' % (placemark.specie_id, placemark.no_characters)
    print 'Done\n'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多