|
Hi Yingshuo,
LASDods.pm should be in lasroot/las/xml/perl/dods by default installation.
Joe
shen yingshuo wrote: hi all, anyone has tried to use addXml.pl from a dods data ? or anyone has used this las6 addXml.pl ? i tried and it came out with erro "Can't locate LASDods.pm" shen yingshuo |
package LAS::DODS::Object;
# Copyright (c) 2001 TMAP, NOAA
# ALL RIGHTS RESERVED
#
# Please read the full copyright notice in the file COPYRIGHT
# included with this code distribution
# $Id $
use URI::Escape;
sub new {
my ($class, $name) = @_;
my $self =
{
name => uri_unescape($name),
atts => {}
};
bless $self, $class;
}
sub getName {
$_[0]->{name};
}
sub getAttribute {
my $atts = $_[0]->{atts}->{$_[1]};
if ($atts){
return wantarray ? @{$atts} : $atts->[0];
}
}
sub getAttributes {
$_[0]->{atts};
}
sub addAttribute {
$_[0]->{atts}->{$_[1]} = $_[2];
}
package LAS::DODS;
@LAS::DODS::ISA = qw(LAS::DODS::Object);
use Parse::Lex;
use LWP::UserAgent;
use das;
use dds;
$LAS::DODS::DebugLex = 0;
@LAS::DODS::DDSTokens = (
qw(
SCAN_DATASET [Dd][Aa][Tt][Aa][Ss][Ee][Tt]\b
SCAN_INDEPENDENT [Ii][Nn][Dd][Ee][Pp][Ee][Nn][Dd][Ee][Nn][Tt]\b
SCAN_DEPENDENT [Dd][Ee][Pp][Ee][Nn][Dd][Ee][Nn][Tt]\b
SCAN_ARRAY [Aa][Rr][Rr][Aa][Yy]\b
SCAN_MAPS [Mm][Aa][Pp][Ss]\b
SCAN_LIST [Ll][Ii][Ss][Tt]\b
SCAN_GRID [Gg][Rr][Ii][Dd]\b
SCAN_SEQUENCE [Ss][Ee][Qq][Uu][Ee][Nn][Cc][Ee]\b
SCAN_STRUCTURE [Ss][Tt][Rr][Uu][Cc][Tt][Uu][Rr][Ee]\b
SCAN_ALIAS [Aa][Ll][Ii][Aa][Ss]\b
SCAN_BYTE [Bb][Yy][Tt][Ee]\b
SCAN_INT16 [Ii][Nn][Tt]16\b
SCAN_UINT16 [Uu][Ii][Nn][Tt]16\b
SCAN_INT32 [Ii][Nn][Tt]32\b
SCAN_UINT32 [Uu][Ii][Nn][Tt]32\b
SCAN_FLOAT32 [Ff][Ll][Oo][Aa][Tt]32\b
SCAN_FLOAT64 [Ff][Ll][Oo][Aa][Tt]64\b
SCAN_STRING [Ss][Tt][Rr][Ii][Nn][Gg]\b
SCAN_URL [Uu][Rr][Ll]\b
SCAN_ERROR [Ee][Rr][Rr][Oo][Rr]\b
LB {
RB }
SEMICOLON ;
),
'COMMA', ',',
qw(
COLON :
LSB \[
RSB \]
EQUALS =
SCAN_FLOAT [-+]?(([0-9]+\.?[0-9]*(E|e)[-+]?[0-9]+)|([0-9]+\.[0-9]*))
SCAN_INT [-+]?[0-9]+
SCAN_ID [a-zA-Z_%][a-zA-Z0-9_./:%+\-()]*
),
qw(SCAN_STR), [qw(" (?:[^"]+|"")* ")],
'NEVER','[^a-zA-Z0-9_/.+\-{}:;\,%]',
);
@LAS::DODS::DASTokens = (
qw(
SCAN_ATTR attributes|Attributes|ATTRIBUTES\b
SCAN_ALIAS ALIAS|Alias|alias\b
SCAN_BYTE BYTE|Byte|byte\b
SCAN_INT16 INT16|Int16|int16\b
SCAN_UINT16 UINT16|UInt16|Uint16|uint16\b
SCAN_INT32 INT32|Int32|int32\b
SCAN_UINT32 UINT32|UInt32|Uint32|uint32\b
SCAN_FLOAT32 FLOAT32|Float32|float32\b
SCAN_FLOAT64 FLOAT64|Float64|float64\b
SCAN_STRING STRING|String|string\b
SCAN_URL URL|Url|url\b
LB {
RB }
SEMICOLON ;
), 'COMMA', ',',
qw(
COLON :
LSB \[
RSB \]
EQUALS =
SCAN_FLOAT [-+]?(([0-9]+\.?[0-9]*(E|e)[-+]?[0-9]+)|([0-9]+\.[0-9]*))
SCAN_INT [-+]?[0-9]+
SCAN_ID [a-zA-Z_%][a-zA-Z0-9_./:%+\-()]*
),
qw(SCAN_STR), [qw(" (?:[^"]+|"")* ")],
'NEVER','[^a-zA-Z0-9_/.+\-{}:;\,%]',
);
$LAS::DODS::Lexer = undef;
sub ErrorHandler {
die "Parse error near: '", $_[0]->YYCurval, "'", "in:",
$_[0]->YYData->{url};
}
sub Lexer {
my $token = $LAS::DODS::Lexer->next;
if (not $LAS::DODS::Lexer->eoi) {
print "Type: ", $token->name, "\t" if $DebugLex;
print "Content:->", $token->text, "<-\n" if $DebugLex;
return ($token->name, $token->text) ;
} else {
return ('',undef);
}
}
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
my ($path) = @_;
$self->{variables} = {};
$self->{orderedVars} = [];
$self->{path} = $path;
bless $self, $class;
my $ddspath = "$path.dds";
my $daspath = "$path.das";
my $req = new HTTP::Request(GET, $ddspath);
my $ra = new LWP::UserAgent;
my $resp = $ra->request($req);
my ($ddsstr, $dasstr);
if ($resp->is_success){
$ddsstr = $resp->content;
} else {
die "Error in accessing $ddspath";
}
$req = new HTTP::Request(GET, $daspath);
$resp = $ra->request($req);
if ($resp->is_success){
$dasstr = $resp->content;
} else {
die "Error in accessing $daspath";
}
my $lexer = $LAS::DODS::Lexer = Parse::Lex->new(@DDSTokens);
$lexer->skip('[ \t\n]+');
$lexer->from($ddsstr);
my $ddsparser = new dds;
$ddsparser->YYData->{dods} = $self;
$ddsparser->YYData->{url} = $ddspath;
$ddsparser->YYParse(yylex => \&Lexer, yyerror => \&ErrorHandler);
$lexer->reset;
# Need to turn off warning messages from Lex while we add new tokens
my $lastwarn = $SIG{'__WARN__'};
$SIG{'__WARN__'} = sub {};
$lexer = $LAS::DODS::Lexer = Parse::Lex->new(@DASTokens);
$SIG{'__WARN__'} = $lastwarn;
$lexer->skip('[ \t\n]+');
$lexer->from($dasstr);
my $dasparser = new das;
$dasparser->YYData->{dods} = $self;
$dasparser->YYData->{url} = $daspath;
$dasparser->YYParse(yylex => \&Lexer, yyerror => \&ErrorHandler);
$self;
}
sub getVariables {
wantarray ? %{$_[0]->{variables}} : $_[0]->{variables};
}
sub getVariablesInOrder {
@{$_[0]->{orderedVars}};
}
sub getVariable {
$_[0]->{variables}->{$_[1]};
}
sub getURL {
$_[0]->{path};
}
# Dummy routine
sub close {
}
package LAS::DODS::Variable;
use Config;
use URI::URL;
use LWP::UserAgent;
@LAS::DODS::Variable::ISA = qw(LAS::DODS::Object);
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
$self->{dods} = $_[1];
$self->{type} = $_[2];
$self->{dims} = [];
$_[1]->{variables}->{$_[0]} = $self;
push(@{$_[1]->{orderedVars}}, $self);
bless $self, $class;
}
sub getDims {
wantarray ? @{$_[0]->{dims}} : $_[0]->{dims};
}
sub isCoord {
my ($self) = @_;
my @dims = @{$self->{dims}};
return 0 if (scalar @dims != 1);
my $dim = $dims[0];
return 1 if $dim->getName eq $self->getName;
return 0;
}
sub getSize {
my $self = shift;
my $size = 0;
foreach my $dim (@{$self->{dims}}){
$size += $dim->getSize;
}
$size;
}
sub addDim {
push(@{$_[0]->{dims}}, $_[1]);
}
sub getRank {
return scalar @{$_[0]->{dims}};
}
sub getType {
return $_[0]->{type};
}
sub getData {
my ($self, $startArray, $countArray) = @_;
die "getData only supports 1D arrays"
if scalar @{$startArray} > 1 || scalar @{$countArray} > 1;
# Bugzilla 408 -- caching caused truncated data if getData was
# called with a different $countArray size
# return (wantarray ? @{$self->{data}} : $self->{data})
# if defined($self->{data});
my @dimList = @{$self->{dims}};
my $type = $self->{type};
die "getData should only be used with 1D variables"
if $#dimList > 0;
die "getData only supports Int32,Float32,Float64"
if $type ne 'Float32' && $type ne 'Float64' &&
$type ne 'Int32';
# Construct appropriate URL
my $path = $self->{dods}->{path} . ".dods";
my $dim = $dimList[0];
my $size = int($dim->getSize);
my $index = $size - 1;
my $start = $startArray ? $startArray->[0] : 0;
my $count = $countArray ? $countArray->[0] : $index;
$count = $index if $count > $index;
$size = $count + 1;
# DODS server doesn't translate escaped '[',']',':'
# Have to hack URI::URL to not escape these
$URI::Escape::escapes{'['} = '[';
$URI::Escape::escapes{']'} = ']';
$URI::Escape::escapes{':'} = ':';
my $url = new URI::URL($path);
$url->query($self->{name} . "[$start:1:$count]");
# Get the data
my $req = new HTTP::Request(GET, $url);
my $ra = new LWP::UserAgent;
my $resp = $ra->request($req);
my $result;
if ($resp->is_success){
$result = $resp->content;
} else {
die "Error obtaining DODS data from $path";
}
# TODO -- Look for DODS error code
# Look for Data delimiter
my $dataStart = index($result, 'Data:');
die "Invalid data return for $path" if $dataStart < 0;
$result = substr($result, $dataStart+14);
# Convert to list. Assumed to be in network order.
my ($iform, $fform);
my $size2 = $size*2;
my @rval;
if ($type eq 'Float32'){
$iform = "N${size}";
$fform = "f${size}";
@rval = unpack($fform, pack('i*',unpack($iform, $result)));
} elsif ($type eq 'Float64'){
$iform = "N${size2}";
$fform = "d${size}";
my @junk = unpack($iform, $result);
if ($Config{byteorder} =~ /^1234/){
for (my $i=0; $i < $size2; $i += 2){
my $tmp = $junk[$i];
$junk[$i] = $junk[$i+1];
$junk[$i+1] = $tmp;
}
}
@rval = unpack($fform, pack('i*', @junk));
} elsif ($type eq 'Int32'){
@rval = unpack("N${size}", $result);
} else {
die "Invalid type";
}
$self->{data} = \@rval;
return (wantarray ? @{$self->{data}} : $self->{data});
}
sub printDim {
my $dim = shift;
my $rval = "";
$rval .= "[";
my $dimvar = $dim->getVar;
if ($dimvar){
$rval .= $dimvar->getName . ' = ';
}
$rval .= $dim->getSize;
$rval .= "]";
$rval;
}
sub toString {
my $self = shift;
my $rval = "";
my @dims = @{$self->{dims}};
if ($#dims > 0){
$rval .= " Grid {\n";
$rval .= " ARRAY:\n";
$rval .= " " . $self->getType . " " . $key;
foreach my $dim (@dims){
$rval .= printDim($dim);
}
$rval .= ";\n MAPS:\n";
foreach my $dim (@dims){
my $dimVar = $dim->getVar;
if ($dimVar){
$rval .= " " . $dimVar->getType . " " . $dimVar->getName ."[" .
$dim->getSize . "];\n";
}
}
$rval .= " } " . $key . ";\n";
} elsif ($#dims == 0){
$rval .= " " . $self->getType . " " . $key;
foreach my $dim (@dims){
$rval .= printDim($dim);
}
$rval .= ";\n";
}
$rval;
}
# Emulate a DODS variable. Used for dimensions without coordinate
# variables
package LAS::DODS::DummyVar;
sub new {
my ($class, $name, $size) = @_;
my $self = {
name => $name,
size => $size
};
bless $self, $class;
}
sub getData {
my $self = shift;
my $size = $self->{size};
return (1..$size);
}
sub getAttribute {
undef;
}
sub getName {
$_[0]->{name};
}
sub isCoord {
return 1;
}
package LAS::DODS::Dim;
@LAS::DODS::Dim::ISA = qw(LAS::DODS::Object);
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
$self->{dods} = $_[1];
$self->{size} = $_[2];
bless $self, $class;
}
sub getSize {
$_[0]->{size};
}
sub setSize {
$_[0]->{size} = $_[1];
}
sub getVar {
my $dods = $_[0]->{dods};
my $theVar = $dods->getVariable($_[0]->getName);
if (!$theVar){
$theVar = new LAS::DODS::DummyVar($_[0]->getName, $_[0]->getSize);
}
$theVar;
}