2014-12-17 2 views
3

Я пытаюсь сделать некоторые манипуляции с файлом формата XMLTV, который содержит информацию о расписании ТВ. В файле есть разделы, которые выглядят так:Есть ли утилита командной строки Linux для удаления разделов (не уверен, что это правильный термин) из XML-файла?

<programme start="20141215220000 -0500" stop="20141216060000 -0500" channel="someid.someaddress.com"> 
    <title lang="en">Local Programming</title> 
    <length units="hours">1</length> 
    <episode-num system="common">S00E00</episode-num> 
    <episode-num system="dd_progid">SH00019112.0000</episode-num> 
    <previously-shown /> 
    </programme> 

Как вы можете видеть во второй строке этого:

<title lang="en">Local Programming</title> 

То, что я хотел бы найти это своего рода утилита командной строки, которая работает в Linux, который может искать эту конкретную строку и, если она существует, удаляет все между тегами программы и включая их. Я не очень хорошо знаком с XML-файлами, поэтому я не знаю, есть ли конкретное имя для такого блока данных, но я просто хочу удалить весь этот раздел, когда заголовок называется «Local Programming».

Это могло бы работать лучше для моих целей, если бы я мог удалить блок только тогда, когда заголовок «Местное программирование», а значение канала в первой строке является определенным конкретным значением, так как мне нужно только удалить их для но не повредило бы что-либо, чтобы удалить все блоки «Local Programming» на любом канале, и искать два значения, вероятно, сделало бы это гораздо более сложной задачей. Это должна быть утилита командной строки, потому что она будет вызвана из короткого сценария оболочки.

В основном я просто пытаюсь определить лучший инструмент для работы. Я не программист (если только вы не считаете, что сценарий оболочки bash имеет несколько строк, который просто выполняет несколько операций последовательно, как программирование), поэтому, если возможно, я хотел бы использовать существующий инструмент командной строки, но я не неблагоприятное для того, чтобы вытащить что-то новое с помощью apt-get. Какие-либо предложения?

EDIT: Работал был инструмент xmlstarlet, предложенный Чарльзом Даффи, но только если я не пытался использовать параметр -var и вместо этого указывал значения напрямую. Например, это убрали все блоки с заголовком «Local Programming» из файла xmltv.xml:

xmlstarlet ed --delete "//programme[title='Local Programming']" <xmltv.xml >newfile.xml 

И если я хочу, чтобы удалить блок только тогда, когда название «Местное программирование» и значение канала в первая строка представляет собой определенное конкретное значение, то оказывается, что это работает:

xmlstarlet ed --delete "//programme[title='Local Programming'][@channel='someid.someaddress.com']" <xmltv.xml >newfile.xml 

Это именно то, что я искал, поэтому я считаю, что проблема решена. Спасибо всем, кто ответил.

+0

Это довольно просто, но ваша спецификация о том, как решить, что поражает меня как менее ясное, чем идеальное. Вы хотите удалить любой заголовок, независимо от его языка? Только на английском языке? Только внутри одной программы? Внутри любой программы? Попробуйте указать свою проблему однозначно с минимальным излишним текстом. –

+0

Charles Duffy: Я не уверен, как бы я мог сделать это менее двусмысленным, но здесь идет: я хочу удалить каждый «программный» блок, который содержит определенную строку « Local Programming" in любой XML-файл, который я указываю. Это XML-файл, а не программа, которую я пытаюсь изменить, и в этой строке нет изменений. Если строка «title» - это что-то еще, я не хочу удалять блок «program». Надеюсь, это очистит вас. – Skyviewer

+0

Итак - версия, которую я дал удаленным программам, где _any_ title - «Local Programming»; основанный на пояснении, похоже, что вы хотите удалить программы, в которых заголовок _English_ является «Local Programming». Я поправлю свой ответ соответствующим образом. –

ответ

5

Для удаления какой-либо программы, имеющей как названия Local Programming на английском языке и канал someid.someaddress.com:

xmlstarlet ed \ 
    --var chan "'someid.someaddress.com'" \ 
    --var name "'Local Programming'" \ 
    --delete '//programme[title[@lang="en"]=$name][@channel=$chan]' \ 
    <in.xml >out.xml && mv out.xml in.xml 

Если вы ориентируетесь старше XMLStarlet релиза, возможно, потребуется сделать замены самостоятельно - с помощью "Local Programming" вместо $name и "someid.someaddress.com" вместо $chan - но вышеизложенное работает против выпуска 1.5.0.

Для этого необходим инструмент XMLStarlet, который должен быть доступен для установки в репозитории поставщика распространения.

Обратите внимание, что вы не указали объявления пространства имен вашего документа - если в родителе указано xmlns='...', может потребоваться некоторая корректировка.

+0

Вы также можете посмотреть утилиту xsltproc. – Mike

+0

Это идеально подходит для этой цели, спасибо за предложения! Я думал, что, вероятно, была утилита командной строки, подходящая для этой задачи, и я никогда не слышал о xmlstarlet before (или xsltproc), поэтому я обязательно проверю их обоих. Я не могу получить доступ к системе, в которой я хочу запустить это до позднего вечера, но как только смогу, я попробую. – Skyviewer

+0

Кстати, 'xmlstarlet sel' (другая подкоманда) может генерировать XSLT, подходящий для использования с xsltproc, поэтому вы можете использовать xmlstarlet на своей машине разработки для создания сценариев, которые затем можно запустить с помощью xsltproc (если это уже установлено на ваших целевых машинах). –

2

В дополнение к правильной обработке XML, как показано в другом ответе, всегда можно прибегнуть к старомодному способу: обработкой XML как обычного текста. В Perl:

cat fancy.xml | 
perl -ne 'BEGIN{$/=undef;} print grep { /^<programme/ ? !m{<title\s+lang="en">Local\s+Programming</title>} : 1 } split qr{(<programme.*?</programme>)}s' 

Это читает весь входной XML (путем сброса входной разделитель записей), сокращает его в плоский список программных блоков и все, что происходит между ними (в split()), а затем отфильтровывает программу блоки, в которых есть искомая строка, присутствующая в них (grep()).

+0

Я хочу поблагодарить вас за это, потому что если бы инструмент xmlstarlet не работал, я бы попробовал это. Но, как я уже говорил выше, я не программист, и то, что я узнал о perl, состоит в том, что, хотя он может выполнять огромное количество задач, код почти полностью неподходящий для большинства людей (и я один из них) , Я вижу определенное преимущество использования perl, поскольку он доступен практически для каждой платформы, но, учитывая выбор между использованием команды, я могу понять и использовать язык сценариев, который так же понятен мне, как греческие иероглифы, я Я предпочту первое. – Skyviewer

+0

Я привел это только в качестве примера или идеи для случая, когда утилиты XML недоступны (или вы ошеломлены «quathks» XPath). Раньше я делал что-то подобное в редакторе VIM, используя встроенный скрипт, и выбрал Perl для примера более или менее произвольно. Если можно настроить '' '' '' 'IFS' sed', это можно сделать даже с 'sed'. – Dummy00001

Смежные вопросы