Извлекать элементы, содержащие теги с определенными значениями, используя jq/xq

Я пытаюсь извлечь координаты узлов с помощью <tag k="power"> теги.

Я пробовал несколько способов.

Этот возвращает только два значения (403564136 и 403564138) и ошибку: jq: error (at <stdin>:1): Cannot index array with string "@k". Вероятно, не удается обработать объект, содержащий несколько элементов, а не один элемент, в результате чего преобразование xml->json генерирует два разных типа данных - массивы и объекты. Не уверен, что лучше всего исправить:

xq '.osm.node[] | select(any(.tag; .["@k"] == "power"))' power.xml

Я мог бы решить проблему, просто выполнив поиск простого текста, но он дал 0 результатов:

xq '.osm.node[] | select( index("power") )' power.xml

или

xq '.osm.node[] | select( any(. == "power") )' power.xml

Я, наверное, что-то упускаю, но не могу понять, что делаю не так.

power.xml:

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.8.3 (3907222 thorn-02.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
    <node id="403564136" visible="true" version="4" changeset="27918722" timestamp="2015-01-04T19:50:21Z" user="k__" uid="156900" lat="58.3795467" lon="26.6902636">
        <tag k="power" v="tower"/>
    </node>
    <node id="403564138" visible="true" version="2" changeset="14825596" timestamp="2013-01-28T18:28:16Z" user="k__" uid="156900" lat="58.3798399" lon="26.6882638">
        <tag k="power" v="tower"/>
    </node>
    <node id="403564140" visible="true" version="3" changeset="21131355" timestamp="2014-03-16T08:53:37Z" user="k__" uid="156900" lat="58.3811404" lon="26.6822486">
        <tag k="power" v="tower"/>
        <tag k="source" v="Maa amet WMS 2009; survey"/>
    </node>
    <node id="403564141" visible="true" version="3" changeset="14825596" timestamp="2013-01-28T18:28:17Z" user="k__" uid="156900" lat="58.3805103" lon="26.6790130">
        <tag k="power" v="tower"/>
    </node>
    <node id="403564142" visible="true" version="2" changeset="1399220" timestamp="2009-06-01T22:33:48Z" user="green525" uid="64433" lat="58.3801485" lon="26.6771179">
        <tag k="power" v="tower"/>
        <tag k="ref" v="4"/>
        <tag k="source" v="Maa amet WMS 2009; extrapolation"/>
    </node>
    <node id="409079906" visible="true" version="3" changeset="47530271" timestamp="2017-04-07T07:39:53Z" user="juhanjuku" uid="152305" lat="58.0699088" lon="27.0763265">
        <tag k="power" v="pole"/>
    </node>
    <node id="409079908" visible="true" version="3" changeset="32801064" timestamp="2015-07-22T12:40:52Z" user="evaldmaa" uid="1706132" lat="58.0697186" lon="27.0755833">
        <tag k="power" v="tower"/>
    </node>
    <node id="579469806" visible="true" version="1" changeset="3279698" timestamp="2009-12-03T11:17:02Z" user="maaamet-import" uid="204356" lat="58.1991523" lon="26.8752022"/>
    <node id="319174533" visible="true" version="3" changeset="10614880" timestamp="2012-02-07T18:36:07Z" user="k__" uid="156900" lat="58.2019064" lon="26.8798802">
        <tag k="railway" v="level_crossing"/>
    </node>
</osm>

1 ответ

Решение

Цените попытку использовать xq в комплекте с yqдля разбора XML. Причина вашей ошибки в том, что.tagsкодируется как массив объектов в нескольких экземплярах. Вы должны иметь возможность различать их в своем фильтре во время извлечения. Также отфильтруйте объекты, у которых нет.tag собственность вообще

Один простой способ решить эту проблему - использовать явное if Заявление о сравнении

xq '
.osm.node[] | 
select(.tag != null) | 
if (.tag|type == "array") then 
  select(any(.tag[]; .["@k"] == "power")) 
else 
  select(any(.tag; .["@k"] == "power")) 
end
' power.xml

или сделайте условную ветвь как функцию

xq '
def nodeSel($p): if ($p|type == "array") then select(any($p[]; .["@k"] == "power")) else select(any($p; .["@k"] == "power")) end;
.osm.node[] | 
select(.tag != null) |
nodeSel(.tag)
' power.xml
Другие вопросы по тегам