Извлечение данных из простого 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.