3

我现在在 sax 中有不同的模块,如 Author.pm、BillingPeriod.pm、Offer.pm、PaymentMethod.pm 等,每当我点击结束元素标签时,我想创建模块的对象,它相当于元素值。

我怎样才能做到这一点?

例如,如果我通过 XML 文件和 sax 解析器命中的结束元素进行解析,那么它应该创建 Offer.pm 的对象,类似地,如果 sax 解析器命中的结束元素标记那么它应该创建 Author.pm 的对象

代码

XML:books.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2009 sp1 (http://www.altova.com)-->
<bks:books xsi:schemaLocation="urn:books Untitled1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bks="urn:books">
        <book id="String">
                <author>String</author>
                  <authorFirstName>String</authorFirstName>
                  <authorLastName>String</authorLastName>
                <title>String</title>
                   <titleNo>3</titleNo>
                <genre>String</genre>
                <offer>String</offer>
                <pub_date>1967-08-13</pub_date>
                <review>String</review>
                  <reviewsratings></reviewratings>
        </book>
</bks:books>

萨克斯:perlsaxparsing.pl

#!usr/bin/perl -w

use XML::SAX::ParserFactory;
use MySaxHandler;
my $handler = MySaxHandler->new();
my $parser = XML::SAX::ParserFactory->parser(Handler => $handler);
$parser->parse_uri("books.xml")

例如在下面的示例中,假设 sax 正在击中Offer end element tag,所以正在创建对象Offer.pm

我想创建模块对象,例如,Offer.pm在这种情况下,当 sax 命中 Offer 元素标记的结束元素时。

  package Offer;
    use strict;

    # This class depicts the product_offer details
    sub new {
        my $class = shift;
        my $self  = {
            _objectId        => shift,
            _price           => shift

        };
        bless $self, $class;
        return $self;
    }

    # Returns the ObjectID
    sub getObjectId {
        my ($self) = @_;
        return $self->{_objectId};
    }


    # Returns the Price
    sub getprice {
        my ($self) = @_;
        return $self->{_price};
    }

    # Check for undefined values and build a insert mapping table
    sub doPreInsetCheck() {
        my ($self) = @_;
        my %refTable;
        if ( defined $self->getObjectId == 1 ) {
            $refTable{'object_id'} = $self->getObjectId;
        }
        if ( defined $self->getprice == 1 ) {
            $refTable{'fk2_price'} = $self->getprice;
        }
        return %refTable;
    }

    # Returns the SQL Statement
    sub getSQLScript {
        my $tableName = 'product_offer';
        my ($self)    = @_;
        my $sqlOutput = "Insert into " . $tableName . "(";
        my %refTable  = $self->doPreInsetCheck();
        my @colNames  = keys %refTable;
        my $ctr;
        foreach ( $ctr = 0 ; $ctr < ( $#colNames + 1 ) ; $ctr++ ) {
            $sqlOutput .= $colNames[$ctr];
            if ( $ctr < $#colNames ) {
                $sqlOutput .= ",";
            }
        }
        $sqlOutput .= ") values (";
        my @colVals = values %refTable;
        foreach ( $ctr = 0 ; $ctr < ( $#colVals + 1 ) ; $ctr++ ) {
            $sqlOutput .= $colVals[$ctr];
            if ( $ctr < $#colVals ) {
                $sqlOutput .= ",";
            }
        }
        $sqlOutput .= ");";
        return $sqlOutput;
    }
    1;

SAX 解析器处理程序模块:MySaxHander.pm

sub end_element {
    my($self,$data) = @_;
    print "\t Ending element:".$data->{Name}."\n";
    my $obj = new Price("1","2","NL","ENUM","DESCRIPTION","2008-01-01  10:00:00","2009-01-01 10:00:00","2008-01-01 10:00:00","USER");
print $obj->getSQLScript."\n";
$in_books--;
}

问题:使用 SAX 解析 XML 文件时,如何创建与元素值等效的模块对象?

4

2 回答 2

2

一般来说,您在 SAX 中必须做的是:

  1. 在处理 start_element 时创建一个工作区,以保存您最终需要填充对象的嵌套标签中的值。
  2. 在 end_element 上,实例化对象

或者,您可以在 start_element 上实例化(空)对象,然后处理嵌套的 characters() 和 start_element() 事件来填充它。在所有情况下,您都需要跟踪当前的处理状态,以便在遇到每种元素类型时知道如何处理它。您还需要一个全局上下文堆栈来跟踪您在层次结构中的逻辑位置并指向当前对象/工作区。

这是处理这些问题的介绍的指针。

于 2009-11-18T17:54:50.500 回答
1

我已经厌倦了一遍又一遍地看到相同的 XML,所以我决定给你一条鱼。为了您自己的利益,您需要更加努力地解释您的问题。我的意思是,即使您发布的 XML 也包含错误。

下面的代码有一些非常规的方面。它们在那里,因此在将此代码作为您自己的代码传递给您的老板/客户之前,您必须弄清楚发生了什么。

#!/usr/bin/perl

package My::Book;
use strict; use warnings;

use base 'Class::Accessor::Faster';

 __PACKAGE__->follow_best_practice;

__PACKAGE__->mk_accessors(qw(
    id author authorFirstName authorLastName title titleNo
    genre offer pub_date review reviewsratings
));

package My::Handler;
use strict; use warnings;

{{

my ($current_element, $element_data);

sub new { bless $_[1] => $_[0] }

sub start_element {
    my ($self, $data) = shift;
    my ($el) = @_;

    if ( (my $local_name = $el->{LocalName}) eq 'book' ) {
        my $book = My::Book->new({
            id => $el->{Attributes}{'{}id'}{Value}
        });
        push @$self, $book;
    }
    elsif ( $local_name ne 'books' ) {
        $current_element = $el->{LocalName};
    }
    return;
}

sub characters {
    my ($self, $data) = @_;
    if ( defined $current_element ) {
        $element_data .= $data->{Data};
    }
    return;
}

sub end_element {
    my ($self, $el) = @_;

    unless ( (my $local_name = $el->{LocalName}) =~ /\Abooks?\z/ ) {
        my $accessor = "set_$local_name";
        $self->[-1]->$accessor($element_data);
    }
    $current_element = undef;
    $element_data = '';
    return;
}


}}

package main;
use strict; use warnings;

use XML::SAX;

my @books;

my $parser = XML::SAX::ParserFactory->parser(
    { Handler => My::Handler->new(\@books) },
);

$parser->parse_file(\*DATA);

for my $book ( @books ) {
    printf("%s by %s was published on %s\n",
        $book->get_title, $book->get_author, $book->get_pub_date
    );
}


__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2009 sp1 (http://www.altova.com)-->
<bks:books xsi:schemaLocation="urn:books Untitled1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bks="urn:books">

<book id="String">
<author>String</author>
<authorFirstName>String</authorFirstName>
<authorLastName>String</authorLastName>
<title>String</title>
<titleNo>3</titleNo>
<genre>String</genre>
<offer>String</offer>
<pub_date>1967-08-13</pub_date>
<review>String</review>
<reviewsratings></reviewsratings>
</book>
</bks:books>

输出:

C:\Temp> 回
String by String 发表于 1967-08-13
于 2009-11-19T00:29:56.310 回答