2010-02-08 5 views
31

У меня есть XML-файл с содержимым:Извлечение данных из простого XML-файла

<?xml version="1.0" encoding="utf-8"?> 
<job xmlns="http://www.sample.com/">programming</job> 

Мне нужен способ, чтобы извлечь то, что в <job..></job> теги, programmin в этом случае. Это должно быть сделано в командной строке linux, используя grep/sed/awk.

+0

Если файл XML, содержащийся в этом: < вакансии XMLNS = "http://www.sample.com/" > Том & Джерри вы хотите результат, чтобы XML маскирование оставили в покое: Том & Джерри или вы хотите, чтобы избежать, чтобы отменить, как XML-парсер: Tom & Jerry Если это последнее, извините, я не знаю, как это сделать с текстовыми инструментами Unix. –

+0

@Paul 's/&/\ &/g', то же самое для' " 'и т. Д., Конечно, он не будет обобщать для пользовательских объектов и т. Д. – 13ren

ответ

51

ли вам на самом деле должны использовать только те инструменты? Они не предназначены для обработки XML, и, хотя это возможно, чтобы получить то, что работает нормально большую часть времени, она не будет выполнена в крайних случаях, например, кодирование, линии разрывов и т.д.

Я рекомендую xml_grep:

xml_grep 'job' jobs.xml --text_only 

Что дает выход:

programming 

на убунту/Debian, xml_grep в пакете XML-веточка-инструментов.

+0

Тесные инструкции по установке были бы хороши для xml_grep –

+0

sudo apt-get install xml-twig-tools – FredFury

0

Как насчет:

cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1 
+3

UUOC. 'grep ' ghostdog74

+0

@ghost * но но, я думаю, что это чище/приятнее/не так много отходов/моих приоритетов для отходов! * Http://partmaps.org/era/unix/award.html#cat (на самом деле, я думаю, что изменить имя файла проще, потому что ближе к началу) – 13ren

+3

Если вы используете ' Thor

11
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<" 
+0

только то, что это не удается, если теги находятся на отдельных строках. – ghostdog74

+7

Существует около десятка других способов, которые хорошо сформированный XML может привести к сбою. –

6

просто используйте 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 
+0

'' действительно, но ваш скрипт не распознает его. '

+3

Существует значительное количество различных инструментов, которые используют стандартную нотацию XPath для извлечения информации из XML - «xmlstarlet» - это всего лишь один. Другие включают 'xmllint',' xpath' и т. Д. См. Http://stackoverflow.com/questions/15461737/how-to-execute-xpath-one-liners-from-shell – tripleee

8

Пожалуйста, не используйте линии и регулярных выражений на основе синтаксического анализа на 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. На самом деле это инструмент, основанный на библиотеке perl XML::Twig. Однако то, что он делает, это использовать выражения «xpath», чтобы найти что-то и различать структуру документа, атрибуты и «контент».

E.g.:

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 (например, вашего) большинство будет выглядеть довольно похоже.

0

Немного поздно к выставке.

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> 

The path аргументов имена пути к элементу, который Вы хотите вырезать. В этом случае, так как мы не заинтересованы в тегах на всех, мы переименуем тег \n, таким образом мы получаем хороший список:

$ xmlcutty -path /job -rename '\n' file.xml 
programming 
designing 
managing 
teaching 

Примечания, что XML не был действителен для начала (без корня элемент). xmlcutty может работать со слегка сломанным XML.

2

Использование СЭД команду:

Пример:

$ 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 - Скрипт

/<pattern_to_find>/ - находит строки, которые содержат указанный шаблон, что может быть, например, <heading>

Следующий является замена части s///p, которая удаляет все, кроме требуемого значения, где / заменяется # для лучшей читаемости:

s#\s*<[^>]*>\s*##gp
\s* - включает в себя белое-пространство, если они есть (то же самое в конце)
<[^>]*> представляет <xml_tag> как не-жадное регулярное выражение альтернативной причины <.*?> не работает для sed
g - заменяет все напр. закрытие XML </xml_tag> тег