LINUX.ORG.RU

parse xml, я так думаю.


0

0

Файлы .fb2 по-сути xml, хочется вытащить из них информацию: автор, название, краткое описание книги, чтобы создать каталог имеющихся книг.

мелкий пример файла, 2.5Кб :
http://lib.aldebaran.ru/author/garrison_garri/garrison_garri_absolyutnoe_oruz...

<FictionBook xmlns:l="http://www.w3.org/1999/xlink"; xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"><description>; <title-info> <genre>sf_social</genre> <author> <first-name>Гарри</first-name> <last-name>Гаррисон</last-name> </author> <book-title>Абсолютное оружие</book-title>


почитал perldoc XML::Parse непонял ничего

Вопрос: как вытащить из xml файла нужный мне ключ (<genre>, <author> и тд)

★★★★★

>use XML::Simple;

>my $fb2=XML::Simple->new;

>my $fb2_parsed=$fb2->XMLin( path_to_fb2_file )

dal'she razbirat' $fb2_parsed

//router

anonymous
()
Ответ на: комментарий от anonymous

sub authors { my @authors; $_= $fb2_parsed->{"description"}{"title-info"}{"author"};

# либо это массив хэшей, либо один хэш. В любом случае, обработать надо # приведём хэш к массиву хэшей if ( ref($_) eq "HASH" ) { $_=[$_]; };

foreach ( @$_ ) { push(@authors, { "first-name" => $_->{"first-name"}, "middle-name" => $_->{"middle-name"}, "last-name" => $_->{"last-name"} } ); }; return \@authors; }

anonymous
()
Ответ на: комментарий от anonymous

sub authors {
my @authors;
$_= $fb2_parsed->{"description"}{"title-info"}{"author"};

# либо это массив хэшей, либо один хэш. В любом случае, обработать надо
# приведём хэш к массиву хэшей
if ( ref($_) eq "HASH" ) {
$_=[$_];
};

foreach ( @$_ ) {
push(@authors,
{
"first-name" => $_->{"first-name"},
"middle-name" => $_->{"middle-name"},
"last-name" => $_->{"last-name"}
}
);
};
return \@authors;
}

//router

anonymous
()
Ответ на: комментарий от anonymous

Вообще, это писал буквально сегодня и наспех, поэтому за образец лучше не считать :D . Наверное, лучше сначала для XMLin установить параметры ForceArray и ForceContent, тогда будет гораздо удобнее обрабатывать результат

router ★★★★★
()
Ответ на: комментарий от router

Спасибо, до конца еще не осознал, но свет в конце туннеля забрезжил, буду разбираться.

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

Вроде так правильнее будет:



use XML::Simple;
my $fb2=XML::Simple->new;
my $fb2_parsed=$fb2->XMLin( path_to_fb2_file, ForceArray => 1, NoAttr => 1 ) 



А разбор соответственно



# возвращает жанр, как он описан с документе, без преобраозваний
sub genre {
    return $info->{"description"}[0]{"title-info"}[0]{"genre"};
}

# возвращает информацию об авторах
sub authors {
    my @authors;
    $_= $info->{"description"}[0]{"title-info"}[0]{"author"};

    foreach ( @$_ ) {
        push(@authors,
            {
                "first-name"    => $_->{"first-name"}[0],
                "middle-name"   => $_->{"middle-name"}[0],
                "last-name" => $_->{"last-name"}[0]
            }
        );
    };
    return \@authors;
}



Ессно, всё это лучше запаковать в класс :)

router ★★★★★
()
Ответ на: комментарий от router

[offtopic] При парсинге xml удобно использовать Data::Dumper, чтобы понять, что же получилось :D

use Data::Dumper

print Dumper( результат_парсинга ), "\n";

[offtopic]

ЗЫ. Пока думаю, как можно преобразовать жанр по файлу http://fictionbook.org/index.php/XML-файл_для_преобразования_кодов_жанров_всех_ версий_в_двухуровневое_описание_жанра

router ★★★★★
()
Ответ на: комментарий от router

И до кучи 

#возвращает заголовок документа
sub title {
    return $info->{"description"}[0]{"title-info"}[0]{"book-title"}[0];
}

router ★★★★★
()

Для пакетной обработки есть консольная тулза xmlstarlet. Типа как аналог grep/sed/awk, но под xml заточены.

AngryElf ★★★★★
()
Ответ на: комментарий от AngryElf

Вроде как самое то для разового скрипта.
Но не работает, хотя и должно бы.

$ xmlstarlet el garrison.fb2
FictionBook
FictionBook/description
FictionBook/description/title-info
FictionBook/description/title-info/genre
FictionBook/description/title-info/author
FictionBook/description/title-info/author/first-name
FictionBook/description/title-info/author/last-name
FictionBook/description/title-info/book-title
[SKIP]

$ xmlstarlet sel -t -c "/FictionBook/description/title-info/genre" garrison.fb2
$ [пусто]

В тоже время
$ xmlstarlet el aaaa.xml
ipe
ipe/info
ipe/page
ipe/page/layer
ipe/page/view
ipe/page/path
ipe/page/path
ipe/page/path
ipe/page/path
ipe/page/path
ipe/page/text

$ xmlstarlet sel -t -c "/ipe/page/path[5]" aaaa.xml
<path stroke="black" pen="normal">
88.955 0 0 88.955 252 390 e
</path>

$ xmlstarlet sel -t -v "/ipe/page/path[5]" aaaa.xml
88.955 0 0 88.955 252 390 e

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

Объясните, кто знает, удалил в след. строке все "лишнее" и xmlstarlet заработал
Из <FictionBook xmlns:l="http://www.w3.org/1999/xlink"; xmlns="http://www.gribuser.ru/xml/fictionbook/2.0">; сделал <FictionBook>

Что бы это значило? В XML ни в зуб ногой :-(

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

$ cat king_stiven_volki_kali.fb2 | sed 's/FictionBook [^>]*/FictionBook/' | xmlstarlet sel -t -v "/FictionBook/description/title-info/annotation" 2>/dev/null

Странствие Роланда Дискейна и его друзей продолжается... И теперь на пути их лежит маленький городок Калья Брин Стерджис, жители которого раз в поколение платят страшную дань посланникам тьмы — Волкам Кальи!



Так работает.

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

Просто xmlstarlet пытается отрезолвить схему FictionBooks, но не находит ее.

Так работает:

 xmlstarlet sel -t -v  "//node()[name()='author']" king_temnaya_bashnya_5_volki_kyelliy.fb2
 Стивен Кинг
~/al/wrk$ xmlstarlet sel -t -v  "//node()[name()='genre']" king_temnaya_bashnya_5_volki_kyelliy.fb2
romance_sf
~/al/wrk$ xmlstarlet sel -t -v  "//node()[name()='book-title']" king_temnaya_bashnya_5_volki_kyelliy.fb2
Волки Кэллы
~/al/wrk$ xmlstarlet sel -t -v  "//node()[name()='annotation']" king_temnaya_bashnya_5_volki_kyelliy.fb2
«Волки Кэллы» – пятая книга долгого повествования, навеянного поэмой Роберта Браунинга «Чайлд Роланд к Темной Башне пришел».

Проще, однако, xsl написать для такого дела.

svr69 ★★
()
Ответ на: комментарий от sdio

не удалось закинуть сюда исходник xslt. Так что:

lynx -dump http://ocaml.spb.ru/fb-info.xsl > fb-info.xsl

xsltproc fb-info.xsl king_temnaya_bashnya_5_volki_kyelliy.fb2

Author: СтивенКинг
Genre: romance_sf
Title: Волки Кэллы
Annotation: «Волки Кэллы» – пятая книга долгого повествования, навеянного поэмой Роберта Браунинга «Чайлд Роланд к Темной Башне пришел».

svr69 ★★
()
Ответ на: комментарий от sdio

да, с xslt тебе дело советуют.

Я тоже недавно столкнулся с обработкой xml. Самый классный способ -- это написать xslt преобразование, которое генерирует набор пар key=value. (из командной строки -- xsltproc). Обычно занимает в пределах миллисекунды, если использовать libxml

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

libxml мало :) Это только парсер. libxslt еще нужен.

svr69 ★★
()
Ответ на: комментарий от svr69

Последний вопрос. В fb2 встречаются binary вставки (картинка-обложка jpeg). как ее выдернуть (сохранить в файл)?

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

Вот это с помощью XSL только через задницу. Т.е., есть расширения для записи во внешний файл (если я правильно понял), но надо проверять, умеет ли эти расширения конкретный процессор.
 http://ocaml.spb.ru/fb-info.xsl - поправил для работы с расширение exsl:document, с которым xsltproc работает.

Теперь так:

$ lynx -dump http://ocaml.spb.ru/fb-info.xsl > fb-info.xsl

$ xsltproc fb-info.xsl king_temnaya_bashnya_5_volki_kyelliy.fb2

Author: СтивенКинг
Genre: romance_sf
Title: Волки Кэллы
Annotation: «Волки Кэллы» – пятая книга долгого повествования, навеянного поэмой Роберта Браунинга «Чайлд Роланд к Темной Башне пришел».

$ ls -latr
<...>
king_wolves_of_calla_cover_small.jpg-b64

$ cat king_wolves_of_calla_cover_small.jpg-b64 | perl -MMIME::Base64 -e '$dec = decode_base64(<>); binmode *STDOUT; print $dec;' > t.jpg

Т.е., xsl выдергивает имя файла, добавляет к нему суффикс -b64, и пишет в этот файл бинарь из fb2.
Поскольку бинарники там кодируются Base64, то остается только раскодировать их.

В принципе, все эти игры с множественным выводом и перекодировкой удобнее делать уже на чистом XPath или даже SAХ,
но если знакомства с этими технологиями нет, то и ну их :) 

svr69 ★★
()
Ответ на: комментарий от svr69

Спасибо.
Вряд ли я стану погружаться во все это глубже вышеизложенного, по крайне мере, не ради разового написания скрипта.

sdio ★★★★★
() автор топика
Ответ на: комментарий от sdio

В принципе, есть такой волшебный процессор под названием Saxon, так вот в его последних версиях есть и полная поддержка XSLT 2.0, и даже расширения для работы с base64, но это джава (не знаю, насколько это удобно).

svr69 ★★
()
Ответ на: комментарий от svr69

у него скорость только неадекватная (для моих целей). xsltproc и перловый XML::LibXSLT работают миллисекунды, а саксон ближе к секунде.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

Это секунда на запуск JVM. Saxon - один из самых быстрых процессоров.

svr69 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.