IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  XML  >

XML для разработчиков Perl: Часть 3. Продвинутые методы обработки и записи

Управляем преобразованием документов с помощью XSLT, SAX и SQL

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Джим Диксон, писатель, независимый писатель

29.04.2009

В данной статье методы парсинга, описанные в части 2, используются для создания древовидной структуры, которую можно преобразовать, по которой можно перемещаться и которую можно записывать. Вы узнаете, как подавать преобразованные деревья парсинга в конвейеры SAX, преобразовать их и записывать в виде текста или в базу данных SQL. В заключение вы узнаете, как организовать обратный процесс – направить содержимое базы данных в конвейер SAX.

Введение

Давайте начнем со списка животных в магазине Рози. Идут большие изменения: объединение нашего зоомагазина с магазином Лиззи. После изучения их списков животных стало понятно, что они в разных XML-форматах. Как вы видели, список Рози устроен так, как показано в листинге 1. Однако Лиззи использует абсолютно другую схему, показанную в листинге 9.

Между этими двумя схемами достаточно много различий.

  • Говоря в целом, то, что у Лиззи содержится в виде атрибутов, Рози представляет как подэлементы
  • Ассортимент товаров Лиззи состоит из подэлементов <item>; соответствующие узлы в документах Рози названы по типу животных: <dog> (собаки), <cat> (кошки) и т.д.
  • У Рози есть имена для всех животных; у Лиззи нет
  • Рози сохраняет цены, Лиззи – себестоимость
  • У Лиззи в списке указан возраст, у Рози же список содержит даты рождения
  • У Лиззи есть определенное место для всех элементов, у Рози их нет
  • Рози записывает хозяев только для собак (для других животных хозяев нет); Лиззи вообще не записывает хозяев

Наша цель - преобразовать возраст животных Лиззи и даты рождения питомцев Рози, представленные в европейском формате, в один общий формат, однако сделать это сразу же не получится. Сначала мы преобразуем возраст в даты в текущем формате, а после этого, на следующем этапе, с помощью Perl преобразуем данные в стандартный формат (4 символа для года - 2 для месяца - 2 для дня).

ППосле небольшого анализа мы согласовали спецификацию SQL-таблицы, в которой будем хранить данные в СУБД. SQL-код для создания таблицы базы данных приведен в листинге 6. Мы сошлись на том, что она лучше всего подходит представления XML-данных Лиззи, при этом столбцы отображаются на атрибуты. Мы решаем преобразовать два разных XML-файла в общую схему, соединить их, сохранив в базе данных SQL, и затем из базы данных создать XML-документ - общий файл с ассортиментом.



В начало


Начало работы

Как и в первых двух статьях данной серии нам понадобятся дополнительные модули Perl, чтобы запустить код этой статьи. Пользователи UNIX® или Linux™ могут их получить из репозитория cpan; пользователи Windows® обычно получают их, используя ppm (для ссылки см. Ресурсы). Нам нужны следующие модули:

  • DBI – интерфейс реляционной базы данных
  • XML::LibXSLT - модуль для обработки таблицы стилей


В начало


Таблицы стилей и DOM

Для преобразования списка товаров Рози в общий формат мы будем использовать таблицу стилей XSLT (rosie.xsl; см. листинг 2) Для этого нам нужно будет выполнить парсинг XML-документа (инвентарная книга в листинге 1) и таблицы стилей, а затем с помощью XSLT создать новый документ.


Листинг 1. Ассортимент в магазине Рози
   
  <pets>
  <cat><name>Madness</name>
    <dob>1 February 2004</dob><price>150</price></cat>
  <dog><name>Maggie</name>
    <dob>12 October 
2002</dob><price>75</price><owner>Rosie</owner></dog>
  <cat><name>Little</name>
    <dob>23 June 2006</dob><price>25</price></cat>
</pets>

Наша таблица стилей преобразует каждый подэлемент в элемент <item>, создавая новый атрибут, для которого значением является предыдущее имя элемента, его тегом. Она также преобразует все подэлементы нижнего уровня в атрибуты, а их содержимое - в значения атрибутов (см. листинг 2).


Листинг 2. Таблица стилей rosie.xsl
   
 <xsl:stylesheet version="1.0">
  <xsl:template match="/pets">
    <xsl:element name="stock">
      <xsl:for-each select="*">
        <xsl:element name="item">
          <xsl:attribute name="type">
            <xsl:value-of select="name()"/>
          </xsl:attribute>
          <xsl:for-each select="*">
            <xsl:attribute name="{name()}">
              <xsl:apply-templates/>
            </xsl:attribute>
          </xsl:for-each> 
          <xsl:attribute name="cost">0.00</xsl:attribute>
          <xsl:attribute name="location">Rosies</xsl:attribute>
        </xsl:element>
      </xsl:for-each>
    </xsl:element><
  </xsl:template>
</xsl:stylesheet>

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

Поскольку мы делаем это преобразование не один раз (здесь и в следующем разделе), мы разместим общий код в модуле Perl под названием RosieStock.pm (см. листинг 3).


Листинг 3. RosieStock.pm (часть)
   
  package RosieStock;
use strict;
use XML::LibXML;
use XML::LibXSLT;
use XML::LibXML::SAX::Generator;

sub new { 
    my $class = shift;
    my $parser = XML::LibXML->new;
    my $xslt   = XML::LibXSLT->new;
    my $style  = $parser->parse_file('rosie.xsl');
    my $self = { 
        PARSER      => $parser,
        STYLESHEET  => $xslt->parse_stylesheet($style),
    };
    bless $self, $class;
}
sub parseAndStyle {
    my ($self, $inFile) = @_;
    $self->{DOC}       = $self->{PARSER}->parse_file($inFile);
    $self->{STYLED}    = $self->{STYLESHEET}->transform($self->{DOC});
    return $self;
}
sub toString {
    my ($self) = shift;
    $self->{STYLESHEET}->output_string( $self->{STYLED} );
}

Преобразование выполним с помощью фрагмента кода Perl из листинга 4. Он разбирает список товаров и таблицу стилей, применяет таблицу стилей и распечатывает результаты (листинг 5), чтобы вы могли оценить сделанное.


Листинг 4. part3a.pl
   
 #!/usr/bin/perl -w
use strict;
use DBI;
use RosieStock;   

my $fixRosie = RosieStock->new;
print $fixRosie->parseAndStyle('pets.xml')->toString;

Как видите, подэлементы исходного документа теперь являются атрибутами. Фактическое содержимое ассортиментного списка, за исключением добавления атрибутов с затратами и местом, не изменилось (см. листинг 5).


Листинг 5. Преобразованный ассортимент магазина Рози (part3a.out)
   
  <?xml version="1.0"?>
<stock>
    <item type="cat" name="Madness" dob="1 February 2004" price="150" 
    cost="0.00" location="Rosies"/>
  <item type="dog" name="Maggie" dob="12 October 2002" price="75" 
    owner="Rosie" cost="0.00" location="Rosies"/>
  <item type="cat" name="Little" dob="23 June 2006" price="25" 
    cost="0.00" location="Rosies"/>
</stock>



В начало


Конвейеры SAX

Как мы видели в части 2 (см. Ресурсы), в то время как парсеры дерева и, соответственно, XSLT-преобразования можно применять лишь к тем XML-документам, которые умещаются в памяти и/или имеют определенную длину, SAX может обрабатывать XML-потоки произвольных размеров и длины. Но мы можем использовать преимущества обоих подходов: разбирать, перемещаться и преобразовать XML-документы как деревья, а затем обходить эти деревья, создавая события, которые будут подаваться в конвейеры SAX. Поскольку мы уже имеем ассортимент Рози в форме дерева, мы так и поступим прямо сейчас. Возьмем преобразованное и разобранное дерево и направим его в обработчик SAX на пути к базе данных.



В начало


Обход дерева DOM

Первый конвейер SAX, который мы создадим, состоит из двух частей: генератора, который обходит дерево DOM, создавая события SAX, и обработчика, принимающего события и записывающего их в базу данных. Генератор - это метод, добавленный к пакету RosieStock; см. листинг 6. Обработчик, который записывает строки в таблицу PETS.STOCK в ранее существовавшую базу данных, показан в листинге 7. Программа Perl, которая создает и запускает конвейер SAX, показана в листинге 8.


Листинг 6. RosieStock.pm (остальная часть)
   
  sub generate {
    my ($self, $handler) = @_;
    my $generator 
        = XML::LibXML::SAX::Generator->new(Handler=>$handler);
    $generator->generate( $self->{STYLED} );
}
1;

Новым элементом в RosieStock.pm является XML::LibXML::SAX::Generator, который будет обходить дерево DOM - преобразованный XML-документ, ранее созданный в модуле, и создавать поток событий SAX. Эти события передаются обработчику.


Листинг 7. Stock2DB.pm
   
package Stock2DB;
use XML::SAX::Base;
@ISA = ('XML::SAX::Base');
use strict;
use DBI;
use constant TYPE0 => 0;
use constant TYPE1 => 1;
use constant TYPE2 => 2;

sub new {
    my $class = shift;
    my $self  = { COUNTER => 0, HASHTYPE => TYPE0 };
    return bless {}, $class;
}

my @months = ( 'January', 'February', 'March', 'April', 'May', 'June',
               'July', 'August', 'September', 'October', 'November', 
               'December');
sub _dobFromAge($) {    # precision is not an issue!
    my $age = shift;
    my $tob = time() - $age * ((86400) * 365.25);
    my ($day, $month, $year) = (localtime($tob))[ 3, 4, 5 ];
    $year += 1900;
    return "$day $months[$month] $year";
}
# see Perl SAX 2.1 spec for details regarding $data (hash ref)

sub _getVal($$) {
    my ($hash, $name) = @_;
    return (defined $hash->{$name}) ? ''.$hash->{$name} : '';
}
# expect attribute names to appear in hash
sub _getAttrsTYPE1($) {
    my $attrs = shift;
    return (
        _getVal($attrs, 'type'),   _getVal($attrs, 'name'),  
        _getVal($attrs, 'cost'),   _getVal($attrs, 'price'), 
        _getVal($attrs, 'dob'),    _getVal($attrs, 'location'),
        _getVal($attrs, 'age'),
    ); 
}
# expect prefixed attribute names to key secondary hash
sub _getFromSecondary ($$) {
    my ($hash, $name) = @_;
    my $value;
    my $ref = $hash->{ "{}$name" };
    if (defined $ref) {
        $value = $ref->{Value};
    }
    return $value;
}
sub _getAttrsTYPE2($) {
    my $attrs = shift;
    my ($type, $name, $cost, $price, $dob, $location, $age) = (
        _getFromSecondary ($attrs, 'type'),     
        _getFromSecondary ($attrs, 'name'),     
        _getFromSecondary ($attrs, 'cost'),     
        _getFromSecondary ($attrs, 'price'),     
        _getFromSecondary ($attrs, 'dob'),     
        _getFromSecondary ($attrs, 'location'),     
        _getFromSecondary ($attrs, 'age'),     
    ); 
    return ($type, $name, $cost, $price, $dob, $location, $age);
}
sub start_element {
    my ($self, $data) = @_;
    my $elmName = $data->{Name};
    if ($elmName eq 'item') {
        my $attrs = $data->{Attributes};
        my $hashType = $self->{HASHTYPE};
        $hashType = TYPE0 if !defined($hashType);
        if ($hashType == TYPE0) {
            my @keyList = keys %$attrs;
            my $attr0 = $keyList[0];
            if ($attr0 =~ /^{}/) {
                $hashType = TYPE2;
            } else {
                $hashType = TYPE1;
            }
            $self->{HASHTYPE} = $hashType;
            $self->{COUNTER}  = 0;
        }
        my ($type, $name, $cost, $price, $dob, $location, $age);
        if ($hashType == TYPE1) {
            ($type, $name, $cost, $price, $dob, $location, $age) = 
                _getAttrsTYPE1( $attrs );
        } else {
            ($type, $name, $cost, $price, $dob, $location, $age) = 
                _getAttrsTYPE2( $attrs );
        }
        # do any necessary fixups
        if (!defined($name) or $name eq '') {
            $name = "$type-" . $self->{COUNTER}++;
        }
        if (!defined($cost) or $cost eq '' or ($cost eq '0.00') ) { 
            $cost =  0.6 * $price;
        }
        if (!defined($price) or $price eq '') {
            $price = 1.667 * $cost;
        } 
        if (!defined($dob) or $dob eq '') {
            $dob = _dobFromAge($age);
        }

        my $insert = 
            'INSERT INTO STOCK (type, name, cost, price, dob, location) '
            . "VALUES( \"$type\",  \"$name\", \"$cost\", "
            .         "\"$price\", \"$dob\",  \"$location\" )";
            
        $self->{DBH}->do ( $insert );
    }
    $self->SUPER::start_element($data);
}
sub start_document {
    my ($self, $data) = @_;
    $self->{DBH} = DBI->connect('DBI:mysql:PETS', 'genny', 'joshsgirl')
          or die "couldn't connect to PETS: " . DBI->errstr;
    $self->SUPER::start_document($data);
}
sub end_document {
    my ($self, $data) = @_;
    $self->SUPER::end_document($data);
    $self->{DBH}->disconnect;
}
1;

Обработчик - это экземпляр Stock2DB, нашего первого обработчика SAX. Он расширяет XML::SAX::Base и оставляет на усмотрение этого пакета обработку (то есть игнорирование) всех не обрабатываемых им событий.

В данном случае единственными событиями, которые нам надо обработать, являются начало и конец документа, а также начало элемента. В функции start_document мы открываем базу данных, в которую делаются записи. В end_document мы ее закрываем. В начале элемента мы смотрим на его имя. Нас интересуют исключительно элементы <item>. Находя такой элемент, мы извлекаем атрибуты из хеша, переданного как параметр, на их основании формируем оператор SQL INSERT, который затем передается DBI для выполнения.

Некоторые сложности связаны с изменениями в связывании Perl SAX. Чтобы справиться с двумя вариантами сохранения значений атрибута, код определяет тип хранения (TYPE1 или TYPE2) и затем соответствующим образом извлекает значения атрибута. Здесь атрибуты хранятся по имени в $data->{Attributes}.

Так получается главным образом из-за того, что пакет XML::LibXML::SAX::Generator устарел. Позже, когда мы будем пользоваться полностью обновленным XML::SAX::ExpatXS, мы должны будем применять второй метод для хранения атрибутов, при котором имя атрибута, например, тип, используется для создания ключа {}type, который указывает на другой хеш, содержащий дополнительную информацию об атрибуте (его значение, префикс и т.д.).

Все перечисленное реализовано в файле part3b.pl, показанном в листинге 8. Сценарий сначала создает чистую таблицу базы данных. После этого он разбирает и преобразует файл со списком товаров pets.xml. Полученное дерево DOM мы обходим. Окончанием конвейера SAX является обработчик, соответственно мы создаем его как экземпляр Stock2DB. Это позволяет нам возможность инициализировать начало конвейера - генератор, который обходит дерево DOM. Когда вызовем этот сценарий, он запишет содержимое дерева в только что созданную таблицу базы данных.


Листинг 8. part3b.pl
   
  #!/usr/bin/perl -w
use strict;
use DBI;
use RosieStock;     
use Stock2DB;

# create a clean database table 
my $dbh = DBI->connect('DBI:mysql:PETS', 'genny', 'joshsgirl')
          or die "couldn't connect to PETS: " . DBI->errstr;

$dbh->do('USE PETS');
$dbh->do('DROP TABLE IF EXISTS PETS.STOCK');
my $create = 'CREATE TABLE STOCK (           '
    . 'id       INT NOT NULL AUTO_INCREMENT, '
    . 'type     VARCHAR(64)     NOT NULL,    '
    . 'name     VARCHAR(64),  '
    . 'cost     DECIMAL(4,2), '
    . 'price    DECIMAL(4,2)    NOT NULL,    '
    . 'dob      VARCHAR(32),  ' # should be DATE, YYYY-MM-DD
    . 'location VARCHAR(64),  ' 
    . 'PRIMARY KEY (id) )     ';

$dbh->do($create)   
    or die "can't create table PETS.STOCK: " . $dbh->errstr;
$dbh->disconnect;

my $fixRosie = RosieStock->new;
$fixRosie->parseAndStyle('pets.xml');
my $dbWriter = Stock2DB->new;
$fixRosie->generate( $dbWriter );

ИИтак, что у нас есть к этому моменту? База данных, содержащая только элементы из исходного списка товаров Рози, преобразованная в стандартный формат.

Если вы внимательно посмотрите на код в листинге 7, то увидите, что Stock2DB также отыскивает недостающие или нулевые значения себестоимости, приблизительно рассчитывает их значения из цен и аналогичным образом вычисляет недостающие цены на основании себестоимостей, используя фиксированную наценку.



В начало


Запись XML в базу данных

Нашим следующим шагом будет загрузка в базу данных списка товаров Лиззи, как показано в листинге 9.


Листинг 9. Ассортимент товара в зоомагазине Лиззи
   
 <stock>
<item type="iguana" cost="124.42" location="stockroom" age="1"/>
<item type="pig" cost="15" location="floor" age="0.5"/>
<item type="parrot" cost="700" location="cage" age="6"/>
<item type="pig" cost="117.50" location="floor" age="3.2"/>
</stock>

Имея алгоритмы из Stock2DB.pm (см. листинг 7), для загрузки в базу данных списка товаров Лиззи нам остается только инициализировать экземпляр Stock2DB, который будет записывать все, что ему передается, в базу данных, и после этого запустить парсер (см. листинг 10).


Листинг 10. part3c.pl
   
#!/usr/bin/perl -w
#use strict;
use XML::SAX::ParserFactory;
use Stock2DB;
$XML::SAX::ParserPackage = "XML::SAX::ExpatXS";

my $parser = XML::SAX::ParserFactory->parser(Handler => Stock2DB->new);
eval { $parser->parse_file('pets2.xml') };
die "can't parse Lizzie's stock file: $@"   if $@;

Теперь оба наших файла с ассортиментом товара загружены в базу данных. Если вы отправите запрос в базу данных, то получите результаты, показанные в листинге 11. Обратите внимание на то, что у всех животных уже есть имена, недостающие себестоимости и цены подсчитаны, возраст преобразован в приблизительные даты рождения, и у всех животных есть свое место.


Листинг 11. Объединенная база данных
   
mysql > select * from PETS.STOCK;
+----+--------+----------+--------+--------+------------------+-----------+
| id | type   | name     | cost   | price  | dob              | location  |
+----+--------+----------+--------+--------+------------------+-----------+
|  1 | cat    | Madness  |  90.00 | 150.00 | 1 February 2004  | Rosies    |
|  2 | dog    | Maggie   |  45.00 |  75.00 | 12 October 2002  | Rosies    |
|  3 | cat    | Little   |  15.00 |  25.00 | 23 June 2006     | Rosies    |
|  4 | iguana | iguana-0 | 124.42 | 207.40 | 16 November 2005 | stockroom |
|  5 | pig    | pig-1    |  15.00 |  25.00 | 18 May 2006      | floor     |
|  6 | parrot | parrot-2 | 700.00 | 999.99 | 16 November 2000 | cage      |
|  7 | pig    | pig-3    | 117.50 | 195.87 | 5 September 2003 | floor     |
+----+--------+----------+--------+--------+------------------+-----------+
7 rows in set (0.00 sec)
mysql>



В начало


Управление базой данных конвейера SAX

Нашей конечной целью является вывести только что созданную базу данных обратно в XML- формат. Формат, в котором находятся даты, не очень подходит для баз данных SQL, однако предоставьте их преобразование предпочтительной MySQL форме YYYY-MM-DD, используя Date::Calc для считывающего устройства.

Используем XML::Generator::DBI для управления конвейером SAX. Обратите внимание на то, что мы должны дать имя корневому элементу и подэлементам в XML- документе, поскольку они неизбежно теряются при сохранении в SQL-таблицу. Также по умолчанию XML::Generator::DBI выводит значения столбцов как подэлементы. Мы хотим, чтобы в XML-документе они были атрибутами, поэтому установим опцию AsAttributes равной 1. В листинге 12 показана программа, а в листинге 13 полученные выходные данные в XML-формате.


Листинг 12. part3d.pl
   
  #!/usr/bin/perl -w
use strict;
use DBI;
use XML::Generator::DBI;
use XML::SAX::Writer;

my $dbh = DBI->connect('DBI:mysql:PETS', 'genny', 'joshsgirl')
          or die "couldn't connect to PETS: " . DBI->errstr;
my $select = qq ( SELECT * FROM STOCK );
my $writer = XML::SAX::Writer->new(Output => 'inventory.xml');
my $generator = XML::Generator::DBI->new(
                            dbh          => $dbh,
                            Handler      => $writer, 
                            
                );
$generator->execute($select, undef,
                           AsAttributes => 1,
                           QueryElement => undef,
                           RootElement  => 'stock',
                           RowElement   => 'item',
);
$dbh->disconnect;

Формат данных в листинге 13 несколько изменен для удобства чтения. Генератор изменил порядок атрибутов. Если бы он был важен (в случае с нашим приложением это не так), это можно было бы исправить на дальнейших этапах обработки.


Листинг 13. Выходные данные part3d: inventory.xml
   
<stock>
  <item cost="90.00" dob="1 February 2004" location="Rosies" 
    name="Madness" price="150.00" id="1" type="cat"/>
  <item cost="45.00" dob="12 October 2002" location="Rosies" 
    name="Maggie" price="75.00" id="2" type="dog"/>
  <item cost="15.00" dob="23 June 2006" location="Rosies" 
    name="Little" price="25.00" id="3" type="cat"/>
  <item cost="124.42" dob="16 November 2005" location="stockroom" 
    name="iguana-0" price="207.40" id="4" type="iguana"/>
  <item cost="15.00" dob="18 May 2006" location="floor" 
    name="pig-1" price="25.00" id="5" type="pig"/>
  <item cost="700.00" dob="16 November 2000" location="cage" 
    name="parrot-2" price="999.99" id="6" type="parrot"/>
  <item cost="117.50" dob="5 September 2003" location="floor" 
    name="pig-3" price="195.87" id="7" type="pig"/>
</stock>

В то время как настройка XML::Generator::DBI была достаточно несложной, выполнение Perl-сценария в листинге 12 привело к появлению раздражающих предупреждающих сообщений. Я избавился от них при помощи нескольких исправлений в модуле; в следующей версии этот недостаток должен быть исправлен (мы работали с версией 1.0). А пока вы можете получить заплатку от автора в виде diff-файла.



В начало


Заключение

Данная серия статей началась с описания того, как можно всего за один шаг преобразовывать большинство XML-документов (используя XML::Simple) в легко управляемые структуры данных Perl и обратно.

-

В части 2 представлены более мощные средства для парсинга XML: парсеры дерева типа DOM и парсеры, основанные на событиях SAX. Вы узнали о XML::SAX::Base и о том, как его можно использовать для создания источников, обработчиков и приемников событий SAX.

И, наконец, в части 3 все эти составляющие объединяются вместе, плюс реляционные базы данных. Мы создали дерево парсинга, преобразовали его, затем обошли преобразованное дерево, создавая события SAX, которые направили в базу данных. Затем мы с помощью конвейера SAX разобрали второй XML-документ, преобразовали его и добавили в ту же базу данных, объединив тем самым оба списка товаров. На последнем этапе из базы данных, содержащей объединенные документы, мы создали поток событий SAX, который мы далее преобразовали другим конвейером для формирования итогового объединенного документа.



Ресурсы

Научиться

Получить продукты и технологии
  • Спецификация Document Object Model: узнайте подробнее об этом не зависящем от языка и платформы интерфейсе, который позволяет программам и сценариям быстро получать доступ и обновлять содержимое, структуру и стиль документов. (EN)

  • Perl SAX 2.1 binding: в этом документе описана версия SAX, которая используется модулями Perl.(EN)

  • Perl: получите самую новую версию и испытайте ее в действии.(EN)

  • Огромная Perl-библиотека CPAN:в Comprehensive Perl Archive Network можно найти ссылки на все модули, отмеченные в данной статье(EN)

  • PPM, Perl Package Manager для Windows: получите средства, которые позволят вам устанавливать, перемещать, обновлять и другими способами управлять использованием простых модулей Perl CPAN (таких как Tk и DBI) в ActivePerl. (EN)

  • XML::Simple Гранта Маклина: попробуйте модуль XML::Simple - простой API поверх встроенного модуля XML-парсинга.(EN)

  • Спецификация XML: полное описание расширяемого языка разметки (Extensible Markup Language - XML).(EN)

  • Введение в XML (Дуг Тидвел (Doug Tidwell), developerWorks, август 2002 г.) (EN): в качестве более плавного введения в XML ознакомьтесь с этим пособием, где описано, как появился XML, какое значение он имеет для будущего электронной торговли, а также представлены различные программные интерфейсы и стандарты XML и два примера того, как компании решают проблемы при помощи XML.(EN)

  • XPath 1.0: получите спецификацию языка для навигации по дереву DOM.(EN)

  • Спецификация XSLT 1.0: узнайте о преобразовании одного XML-документа в другой.(EN)

  • Пробуем писать древовидный XML с Perl: работа с древовидными моделями документов (Паранд Даругар, developerWorks, июль 2000 г.) (EN): хорошее введение в древовидный парсинг XML в Perl.(EN)

  • Ознакомительное программное обеспечение от IBM: используйте в своем следующем проекте ознакомительное программное обеспечение, которое можно загрузить прямо с developerWorks.(EN)


Обсудить


Об авторе

Джим Диксон (Jim Dixon) - независимый разработчик, недавно вернувшийся в Сан Франциско, где он консультирует начинающие компании, занимающиеся Web 2.0, по вопросам Perl и Ruby. До этого он семь лет работал ведущим техническим специалистом работающего в Великобритании и США Интернет-провайдера, а также много разрабатывал программное обеспечение на Java/J2EE.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



 


 


 


Поделиться этой статьей:

забобрить забобрить memori сохранить в memori




В начало


UNIX – это зарегистрированная торговая марка Open Group в Соединенных Штатах и других странах. Linux – это торговая марка Linus Torvalds в Соединенных Штатах и других странах. Microsoft, Windows и торговый знак Windows являются торговыми марками Microsoft Corporation в Соединенных Штатах и других странах. Названия других компаний, продуктов и служб могут быть торговыми марками или знаками обслуживания других организаций. Другая компания, продукт или название услуги могут быть торговыми марками или знаками обслуживания, принадлежащими иным физическим или юридическим лицам.

IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.
    IBM в России Конфиденциальность Контакты