Извлечение данных из простого XML файла
У меня есть XML файл с содержимым:
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
Мне нужен способ извлечь то, что находится в тегах <job..>
</job>
, programmin в этом случае. Это нужно сделать в командной строке linux, используя grep/sed/awk.
Ответы
Ответ 1
Вы действительно должны использовать только те инструменты? Они не предназначены для обработки XML, и хотя он может получить что-то, что работает нормально большую часть времени, он будет терпеть неудачу по крайним случаям, таким как кодирование, разрывы строк и т.д.
Я рекомендую xml_grep:
xml_grep 'job' jobs.xml --text_only
Что дает результат:
programming
В ubuntu/debian xml_grep находится в пакете xml-twig-tools.
Ответ 2
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
Ответ 3
Пожалуйста, не используйте синтаксический анализ на основе строк и регулярных выражений в XML. Это плохая идея. Вы можете иметь семантически идентичный XML с различным форматированием, а регулярное выражение и анализ на основе строк просто не могут справиться с ним.
Такие вещи, как унарные теги и перенос переменных строк - эти фрагменты "говорят" одно и то же:
<root>
<sometag val1="fish" val2="carrot" val3="narf"></sometag>
</root>
<root>
<sometag
val1="fish"
val2="carrot"
val3="narf"></sometag>
</root>
<root
><sometag
val1="fish"
val2="carrot"
val3="narf"
></sometag></root>
<root><sometag val1="fish" val2="carrot" val3="narf"/></root>
Надеюсь, это объясняет, почему создание парсера с регулярным выражением/линией затруднено? К счастью, вам не нужно. Многие языки сценариев имеют как минимум один, а иногда и более синтаксический анализ.
Как уже упоминался предыдущий плакат - xml_grep
. Это фактически инструмент, основанный на XML::Twig
perl-библиотеке. Однако то, что он делает, это использовать выражения "xpath", чтобы найти что-то и различать структуру документа, атрибуты и "контент".
например:.
xml_grep 'job' jobs.xml --text_only
Однако в интересах получения более качественных ответов здесь приведено несколько примеров "сворачивать ваши собственные" на основе ваших исходных данных:
Первый способ:
Используйте twig handlers
, который захватывает элементы определенного типа и действует на них. Преимущество этого метода заключается в том, что он анализирует XML "как вы идете" и позволяет вам изменять его в полете, если вам нужно. Это особенно полезно для отбрасывания "обработанного" XML, когда вы работаете с большими файлами, используя purge
или flush
:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new(
twig_handlers => {
'job' => sub { print $_ ->text }
}
)->parse( <> );
который будет использовать <>
для ввода ввода (подключен или задан с помощью командной строки ./myscript somefile.xml
) и обрабатывать его - каждый элемент job
, он будет извлекать и печатать любой связанный текст. (Возможно, вы захотите print $_ -> text,"\n"
вставить строку перевода).
Поскольку он соответствует элементам "задание", он также будет соответствовать вложенным элементам задания:
<job>programming
<job>anotherjob</job>
</job>
Сопоставим дважды, но дважды напечатайте часть вывода. Однако, если вы предпочитаете, вы можете использовать /job
. Использование - это позволяет вам, например. распечатать и удалить элемент или скопировать и вставить одно изменение структуры XML.
Альтернативно - сначала проанализируйте и "напечатайте" на основе структуры:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> root -> text;
Поскольку job
- ваш корневой элемент, все, что нам нужно, это распечатать его текст.
Но мы можем быть немного более проницательными и искать job
или /job
и печатать это специально вместо этого:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> findnodes('/job',0)->text;
Вы можете использовать опцию XML::Twig
pretty_print
для переформатирования вашего XML:
XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
Существует множество вариантов выходного формата, но для более простого XML (например, вашего) большинство будет выглядеть довольно похоже.
Ответ 4
Использование xmlstarlet:
echo '<job xmlns="http://www.sample.com/">programming</job>' | \
xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
Ответ 5
просто используйте awk, не нужно использовать другие внешние инструменты. Ниже работает, если ваши нужные теги отображаются в многострочном формате.
$ cat file
test
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">
programming</job>
$ awk -vRS="</job>" '{gsub(/.*<job.*>/,"");print}' file
programming
programming
Ответ 6
Предполагая ту же строку, ввод из stdin:
sed -ne '/<\/job>/ { s/<[^>]*>\(.*\)<\/job>/\1/; p }'
примечания: -n
автоматически останавливает вывод; -e
означает, что однострочный (aot a script) /<\/job>
действует как grep; s
разделяет атрибуты opentag + и endtag; ;
- новое утверждение; p
отпечатки; {}
делает grep применимым к обоим операторам, как к одному.
Ответ 7
Использование команды sed:
Пример:
$ cat file.xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
$ cat file.xml | sed -ne '/<heading>/s#\s*<[^>]*>\s*##gp'
Reminder
Объяснение:
cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'
n
- подавлять печать всех строк
e
- script
/<pattern_to_find>/
- находит строки, содержащие указанный шаблон, который может быть, например, <heading>
next - это замещающая часть s///p
, которая удаляет все, кроме желаемого значения, где /
заменяется на #
для лучшей читаемости:
s#\s*<[^>]*>\s*##gp
\s*
- включает белые пробелы, если они существуют (то же самое в конце)
<[^>]*>
представляет <xml_tag>
как альтернативу нежеланному регулярному выражению <.*?>
не работает для sed
g - заменяет все, например. закрытие тега xml </xml_tag>
Ответ 8
Как насчет:
cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1
Ответ 9
Немного поздно к шоу.
xmlcutty вырезает узлы из XML:
$ cat file.xml
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">designing</job>
<job xmlns="http://www.sample.com/">managing</job>
<job xmlns="http://www.sample.com/">teaching</job>
Аргумент path
указывает путь к элементу, который вы хотите вырезать. В этом случае, поскольку мы вообще не интересуемся тегами, мы переименовываем тег в \n
, поэтому получаем красивый список:
$ xmlcutty -path /job -rename '\n' file.xml
programming
designing
managing
teaching
Обратите внимание, что XML недействителен для начала (без корневого элемента). xmlcutty может работать и с немного сломанным XML.