如何使用Perl

时间:2015-07-01 21:40:33

标签: html xml perl

有没有办法可以使用Perl将简单的XML文档转换为HTML,从而为我提供标签名称和标签值的表格?

XML文件output.xml就像这样

<?xml version="1.0"?>

<doc>
    <GI-eSTB-MIB-NPH>
        <eSTBGeneralErrorCode.0>INTEGER: 0</eSTBGeneralErrorCode.0>
        <eSTBGeneralConnectedState.0>INTEGER: true(1)</eSTBGeneralConnectedState.0>
        <eSTBGeneralPlatformID.0>INTEGER: 2076</eSTBGeneralPlatformID.0>
        <eSTBGeneralFamilyID.0>INTEGER: 25</eSTBGeneralFamilyID.0>
        <eSTBGeneralModelID.0>INTEGER: 60436</eSTBGeneralModelID.0>
        <eSTBMoCAMACAddress.0>STRING: 0:0:0:0:0:0</eSTBMoCAMACAddress.0>
        <eSTBMoCANumberOfNodes.0>INTEGER: 0</eSTBMoCANumberOfNodes.0>
    </GI-eSTB-MIB-NPH>
</doc>

我正在尝试创建看起来像这样的HTML

1. eSTBGeneralPlatformID.0 - INTEGER: 2076
2. eSTBGeneralFamilyID.0 - INTEGER: 25
3. 

我试图使用网络上的代码,但我真的很难理解如何为HTML标记生成所需的格式。

我正在尝试的是这个

#!/usr/bin/perl

use strict;
use warnings;

use XML::Parser;
use XML::LibXML;

#Add TagNumberConversion.pl here

my $parser = XML::Parser->new();
$parser->setHandlers(
    Start => \&start,
    End   => \&end,
    Char  => \&char,
    Proc  => \&proc,
);

my $header = &getXHTMLHeader();
print $header;

$parser->parsefile( '20150630104826.xml' );

my $currentTag = "";

sub start() {

    my ( $parser, $name, %attr ) = @_;
    $currentTag = $name;

    if ( $currentTag eq 'doc' ) {
        print "<head><title>"
            . "Output of snmpwalk for cpeIP4"
            . "</title></head>";
        print "<body><h2>" . "Output of snmpwalk for cpeIP4" . "</h2>";
        print '<table summary="'
            . "Output of snmpwalk for cpeIP4"
            . '"><tr><th>Tag Name</th><th>Tag Value</th></tr>';
    }
    elsif ( $currentTag eq 'GI-eSTB-MIB-NPH' ) {
        print "<tr>";
    }
    elsif ( $currentTag =~ /^eSTB/ ) {
        print "<tr>";
    }
    else {
        print "<td>";
    }
}

sub end() {

    my ( $parser, $name, %attr ) = @_;
    $currentTag = $name;

    if ( $currentTag eq 'doc' ) {
        print "</table></body></html>";
    }
    elsif ( $currentTag eq 'GI-eSTB-MIB-NPH' ) {
        print "</tr>";
    }
    elsif ( $currentTag =~ /^eSTB/ ) {
        print "</tr>";
    }
    else {
        print "</td>";
    }
}

sub char() {
    my ( $parser, $data ) = @_;

    print $data;
}

sub proc() {
    my ( $parser, $target, $data ) = @_;

    if ( lc( $target ) eq 'perl' ) {
        $data = eval( $data );
        print $data;
    }
}

sub getXHTMLHeader() {

    my $header = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';

    return $header;
}

这是正在进行的代码,但我意识到这对我的要求来说太过分了。

所以我想弄清楚是否有任何使用Perl的快速方法。

如果确实有任何快捷方法,请给我一些指示。

2 个答案:

答案 0 :(得分:1)

快速而肮脏的方法是使用正则表达式。然而,它存在丢失一些数据并被边缘情况烧毁的风险。但既然你要求它......

#!/usr/bin/env perl

use strict;

open my $fh, 'filename.xml'
    or die "unable to open filename.xml : $!";
my $count = 1;
print "<head><title>'Output of snmpwalk for cpeIP4'</title></head>\n";
print "<body><h2>'Output of snmpwalk for cpeIP4'</h2>\n";
print "<table summary='Output of snmpwalk for cpeIP4'><tr><th>Tag Name</th><th>Tag Value</th></tr>\n";
while (my $line = <$fh>) {
    next unless $line =~ m|<eSTB|;
    # Store into into $tag and $value
    # the result of matching whitespace, followed by '<'
    # followed by anything (store into $tag)
    # followed by '>'
    # followed by anything (store into $value)
    # followed by '<'
    my ($tag, $value) = $line =~ m|\s+<(.+?)>(.+?)<|;
    print "<tr><td>" . $count++ . ". $tag</td><td>$value</td></tr>\n";
}
print "</table></body></html>\n";

产生以下内容:

<head><title>'Output of snmpwalk for cpeIP4'</title></head>
<body><h2>'Output of snmpwalk for cpeIP4'</h2>
<table summary='Output of snmpwalk for cpeIP4'><tr><th>Tag Name</th><th>Tag Value</th></tr>
<tr><td>1. eSTBGeneralErrorCode.0</td><td>INTEGER: 0</td></tr>
<tr><td>2. eSTBGeneralConnectedState.0</td><td>INTEGER: true(1)</td></tr>
<tr><td>3. eSTBGeneralPlatformID.0</td><td>INTEGER: 2076</td></tr>
<tr><td>4. eSTBGeneralFamilyID.0</td><td>INTEGER: 25</td></tr>
<tr><td>5. eSTBGeneralModelID.0</td><td>INTEGER: 60436</td></tr>
<tr><td>6. eSTBMoCAMACAddress.0</td><td>STRING: 0:0:0:0:0:0</td></tr>
<tr><td>7. eSTBMoCANumberOfNodes.0</td><td>INTEGER: 0</td></tr>
</table></body></html>

答案 1 :(得分:1)

首先,我认为您正在使用错误的工具。我总觉得XML::LibXML比XML :: Parser更容易使用。您加载XML :: LibXML,但您从未使用过它。

其次,如果您将此视为两个阶段 - 一个用于提取数据,另一个用于输出新数据,我认为您会发现您的直播更容易。

这是第一个阶段,它将您需要的数据存储在一个数组中。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use XML::LibXML;
use Data::Dumper;

my $file = shift || die "Must give XML file\n";

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file($file);

my @tags;

# Find the nodes using an XPath expression
foreach ($doc->findnodes('//GI-eSTB-MIB-NPH/*')) {
  push @tags, { name => $_->nodeName, content => $_->textContent };
}

# Just here to show the intermediate data structure
say Dumper \@tags;

然后,您需要使用@tags来生成输出。十五年来,我们知道在您的Perl代码中包含硬编码HTML是一个糟糕的主意,所以我强烈建议您查看Template Toolkit之类的模板系统。

我创建了一个xml.tt文件,如下所示:

<html>
<head>
<title>Output of snmpwalk for cpeIP4</title>
</head>
<body><h2>Output of snmpwalk for cpeIP4</h2>
<table summary='Output of snmpwalk for cpeIP4'>
<tr>
<th>Tag Name</th><th>Tag Value</th><
/tr>
[% FOREACH tag IN tags -%]
<tr><td>[% loop.count %]. [% tag.name %]</td><td>[% tag.content %]</td></tr>
[% END -%]
</table>
</body>
</html>

然后我的程序的后半部分看起来像这样:

use Template;

my $tt = Template->new;
$tt->process('xml.tt', { tags => \@tags });

我希望你同意所有看起来都比你的方法简单得多。