Распарсить файл (похож xml)
Доброе время суток, коллеги.
Нужна ваша помощь, очень сильно.
До вечера надо распарсить файл. Содержание файла (отрывок):
<config>
<list name="User">
<listitem>
<variable name="Name">Administrator</variable>
<variable name="Domain">domain.ru</variable>
<variable name="Account_enabled">1</variable>
<variable name="Auth_type">1</variable>
<variable name="Password"></variable>
<variable name="PIN"></variable>
<variable name="Rights">0</variable>
<variable name="ForwardMode">0</variable>
<variable name="HomeServer"></variable>
<variable name="MailboxLocation"></variable>
<variable name="Qstorage">0</variable>
<variable name="Qmessage">0</variable>
<variable name="Fullname"></variable>
<variable name="Description"></variable>
</listitem>
<listitem>
<variable name="Name">admin</variable>
<variable name="Domain">domain.ru</variable>
<variable name="Account_enabled">0</variable>
<variable name="Auth_type">0</variable>
<variable name="Password">DE3:859040a78d562c970a16da52057897dfcc7feee</variable>
<variable name="PIN"></variable>
<variable name="Rights">0</variable>
<variable name="ForwardMode">0</variable>
<variable name="HomeServer"></variable>
<variable name="MailboxLocation"></variable>
<variable name="Qstorage">0</variable>
<variable name="Qmessage">0</variable>
<variable name="Fullname"></variable>
<variable name="Description"></variable>
</listitem>
</list>
</config>Что нужно получить на выходе:
1;Administrator@domain.ru 0;admin@domain.ru
Как формируется:
Значения берутся из этих трех полей:
<variable name="Name">Administrator</variable> <variable name="Domain">domain.ru</variable> <variable name="Account_enabled">1</variable>
Т.е. "1" берется из поля "<variable name="Account_enabled">1</variable>", после него вставляется точка с запятой (;), потом из поля "<variable name="Name">Administrator</variable>" выдирается "Administrator", добавляется "@", a потом "domain.ru" из поля "<variable name="Domain">domain.ru</variable>".
Как их повыдирать по отдельности я знаю, но как соединить в одно целое... Для меня вопрос. Может есть оптимальное решение? Или может есть xml парсер, который можно из bash-скриптов изспользовать?
Заранее благодарен.
- 4205 просмотров
Страница для печати


1. Ставишь тулзу xsltproc
2. Пишешь файлик, например transform.xsl, с таким содержмнием:
3. Скармливаешь все это тулзе:
4. ...
5. PROFIT! :)
Нужна ваша помощь, очень сильно.
надо распарсить файл. Содержание файла (отрывок): benchmark_run result='OK' binary_size='535942'
По этому отрывку не вполне понятно какую структуру имеет файл и что нужно из него извлечь. Покажите более крупный кусок и какой результат вы хотите получить. Пока что непонятно следующее:
1) Верно ли, что каждая строка имеет следующий вид:
benchmark_run result=некая_строка binary_size=некое_число
2) Может быть каждая строка имеет вид
benchmark_run некоторая_переменная=некоторое_значение ...
т.е. имена переменных заранее не известны?
3) Ну и опять же какой именно нужен результат?
Например, следующий скрипт что-то делает, но может быть это не то что надо:
while read line ; do eval $(echo $line | cut -d' ' -f2-) echo $result echo $binary_size doneнужно парсинг benchmark_run result='OK' binary_size='535942'
надо распарсить файл. Содержание файла (отрывок)
лучше поздно, чем никогда Ж:-)
шел программиног плохо предназначены для работы с xml. Изза этого в юниксах xml и не любят.
самое правильное конечно на каком нибуть скриптовом языком воспользоватся спец библиотекой для этого.
Но что бы просто продемонстрировать подход, набросал очень quick и очень dirty решение. Считается что;
(это можно в одну строку)
sed преобразует все xml теги в строки вида NAME=Administrator, DOMAIN=domain.ru и так далее
В цикле построчно берутся строки и преобразуются в переменные.
Как только встречается переменная ACCOUNT_ENABLED, считается что NAME и DOMAIN
уже раньше было и выводится нужная строка. После чего переменная-триггер
ACCOUNT_ENABLED убирается.
Афигеть!!! А я мутил... :-( А оказывается всё просто так :-)
Респект тебе огромный.
В очередной раз убеждаюсь, что ты спец. :-)
#!/usr/bin/php <? if (!@$argv[1]) exit ('You must provide file to process!' . "Like:\n" . basename($argv[0]) . " file_to_process\n"); preg_match_all('#<variable name="(?:Name|Domain|Account_enabled)">(.*?)</variable>#i', file_get_contents($argv[1]), $m, PREG_SET_ORDER); for ($i = 0; $i < count($m); $i+=3){ echo $m[$i+2][1] . ';' . $m[$i][1] . '@' . $m[$i+1][1] . "\n"; } ?>Если уж парсить через php то не регуляркой а через DOMDocument
http://mymans.org/category/php/domdocument
http://ru2.php.net/simplexml не подойдет чтоли? Или DOMxml, libxml и другие в его составе ( http://ru2.php.net/manual/en/refs.xml.php )?
Естественно что так "правильнее" работать с XML, я же предложил самый "быстрый" способ слету, вот и все.
Сомневаюсь, что для CLI версии PHP такое прокатит... Тут ведь РНР не веб-сервером вызывается, а значит DOMDocument не прокатит (он же браузерный вроде как...)
--
Аффтар (из инеткафе пишу, региться не стал, т.к., по идее, машины (не знаю все или нет, но одна, которая мне всю флешку заразила, - 100%) инифицированы вирусом Virus.Win32.Sality.z (в терминалогии каспера),а его версия d перехватывала клаву и отправляла все по мылу куда-то :( .
С каких про DOMDocument стал браузерный? Вы скорее всего батенька путаете с DOM в javascript а это не одно и тоже
$a = '< a><b><c id="tit" name="titname">Page Title</c></b></a>';
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadXML('$a');
$mytag = $dom->getElementById('tit');
echo $mytag->get_attribute('name');
echo $mytag->nodeValue;
echo $mytag->nodeName;
и еще много удобного
во это самый кошерный способ.
аналогичные либы есть в любом скриптовом языке
не сомневайся Ж:-)
можно и через cli
МЕГА РЕСПЕКТ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Все прошло на ура :))) Спасибо, огромное!!!! :)))))))))))
Можешь рассказать как этот скрипт работает? Я просто не знаю PHP :( Точнее учил когда-то, но уже не вспомню :(
Просто хочу на bash переписать его, чтобы всегда был под рукой :)
Соображения есть, но есть и сомнения ;)
Да могу конечно рассказать, но не посимвольно же разбирать его в самом деле?
Если есть вопросы - с удовольствием отвечу. Правда наверное лучше это уже все приватно - велкам в джаббер ко мне!
Ну а на Баш какой смцысл его переписывать - просто будет многословнее, вот и все...
Еще на AWK или PERL можно было бы понять конечно...
AWK? Что-то не складывается у меня в голове как такое сделать на нем... :-(
Примерчик может кто-нибудь подкинуть?
или более красиво отформатированое.
awk '{ if(sub(/.*<variable name="/,"") && sub(/<\/variable>/,"")) { p=gensub(/">.*/,"",""); v=gensub(/.*">/,"",""); h[p]=v; if(p == "Account_enabled") print v";"h["Name"]"@"h["Domain"] } }' parse.xmlосновная проблема что в регеспах не поддерживается выделение регионов в с помощью ()
Ну зачем же так сложно и вправду?
Можете как таким скриптом, так и в одну строчку прямо из Баша (не красиво):
awk 'BEGIN{RS="[[:space:]]*</?listitem>[[:space:]]*";FS="[[:space:]]*<variable name=\"|\">|</variable>\n+"} /variable/{print $9 ";" $3 "@" $6;}' config.xmlИ на счет "что в регеспах не поддерживается выделение регионов в с помощью ()":
1) С чего вы взяли???
Вы вообще МАН по нему читали?:
gensub(r, s, h [, t]) Search the target string t for matches of the regular expression r. If h is a string beginning with g or G, then replace all matches of r with s. Otherwise, h is a number indicating which match of r to replace. If t is not supplied, $0 is used instead. Within the replacement text s, the sequence \n, where n is a digit from 1 to 9, may be used to indicate just the text that matched the n’th parenthesized subexpression. The sequence \0 represents the entire matched text, as does the character &. Unlike sub() and gsub(), the modified string is returned as the result of the function, and the original target string is not changed. gsub(r, s [, t]) For each substring matching the regular expression r in the string t, substitute the string s, and return the number of substitutions. If t is not supplied, use $0. An & in the replacement text is replaced with the text that was actually matched. Use \& to get a literal &. (This must be typed as "\\&"; see GAWK: Effective AWK Programming for a fuller discussion of the rules for &’s and backslashes in the replacement text of sub(), gsub(), and gensub().)Так что поддерживаются какраз ссылки \\n и $n
2) Наверное это все же главное - тут все же надо с полями работать и стандартной логикой AWK.
Интересно, такими пафосными рождаются или это приобретается по мере приобритения навыков? Ж:-))
Восклицать "зачем так сложно" и давать довольно таки не очевидное решение - это что то Ж:-)
Это мозги надо на изнанку вывернуть что бы представить xml в виде полей. Вот у меня так не получилось. У ВАС вышло. За что вам честь и хвала.
И ман я читал. Странно да? И если я где то чего не то не углядел, это не повод патетично закатывать глаза. Можно подумать ВАШИ решения идеальны и ВЫ никогда не ошибаетесь.
Про gensub() дейсвительно проглядел. Вот так лучше
awk '/variable/{$0=gensub(/.*="([^"]*)">([^<]*).*/,"\\1 \\2","");h[$1]=$2;if($1 == "Account_enabled") print $2";"h["Name"]"@"h["Domain"]}' parse.xml() я перепутал с {}. Что бы они работали нужно указывать флажок специально. "чув звiн, та забув де вiн".
Насчет работы через поля в awk таки да надо думать в первую очередь.
Ладно, ладно, не лучший был у меня тон, согласен, прошу прощения, но Вы ответили не менее пафосно... предлагаю мир. :)
Теперь по делу
1) О неочевидности решения - с удовольствием объясню что что не понятно или вызывает вопросы. Это раз. Ну и два, это то что какраз по идеологии AWK - задается разбиение на записи и поля (records & fields), так что по идее должно быть какраз на много очевиднее, потому что вся работа делается в АWK, и как видно, у меня никакого программинга и разбора нету вовсе больше, один единственный print.
2) На счет того что XML, разумеется надо парсить не так, а с помощью его парсеров (см обсуждение этого для ПХП сдесь же), я уже говорил что полностью согласен. На сколько я знаю, AWK этого не умеет, да и в принципе предназначен не для этого.
3) Что проглядели в МАНе не беда, хорошо что хоть не спорите. Рад что было полезно все-таки замечание. Единственное, стоит все же быть менее категоричным в заявлениях... Сам конечно ошибаюсь! Не ошибается тот, кто ничего не делает.
4) О каком флажке речь? Для того чтобы ссылки вида \\n работали? И Вы на какой системе пробовали? Я использую gawk на Линуксе, и все работает по умолчанию...
мир. забыли.
1. Вопросов нет. Я говорил только о том что лично мне идея работать с xml как с полями используя теги как разделители не очевидна. Так как могут и не так идти, и лишние теги быть и все такое.
2. К этому тоже небыло претензий.
3. Зачем же мне спорить с очевидным? Ж:-) Категаричность была вызвана разражением от общего тона письма.
4. раздел Regular Expressions
r{n,m} One or two numbers inside braces denote an interval expression. If there is one number in the braces, the preceding regular expression r is repeated n times. If there are two numbers separated by a comma, r is repeated n to m times. If there is one number followed by a comma, then r is repeated at least n times. Interval expressions are only available if either --posix or --re-interval is specified on the command line.говорю ж () и {} спутал.
в общем все понятно, как по мне разобрались
Класс!!! :) Спасибо большое, теперь буду знать :)
=) Сенкс. По символам не нужно :))) Просто парочка строк не понятны.
А где я твой яббер найду? ;) тут его вроде как нету...
Стукнись в асю ко мне (334-714-695), правда я буду в сети уже наверное после 10 января 2009. :)
Упссс, был уверен что джаббер мой есть здесь в профиле, пардонки:
И стучитесь Вы ко мне лучше уж все же. И аську в топку тоже, проприетарная она...
Ок. 11 выйду на работу, стукну, дома нета нету, с мобилы порой лазаю :-(
О парни вы жжёте, я тоже так хочу скрипты на баше штопать, только вот мат. Р.В. не как не стекаются с этими :,(
что такое "мат. Р.В."?
Отправить комментарий