perl LibXML:针对dtd验证doc,返回boolean

时间:2014-06-16 16:16:05

标签: xml perl libxml2

我正在尝试使用LibXML编写一个perl脚本,该脚本根据dtd验证文档,并返回一个关于doc是否有效的布尔值。我希望能够在xml文件的文件夹上运行脚本,报告哪些是有效的,哪些不是,并记录那些无效的错误。

我所拥有的脚本确实会验证文档,但它会在第一个无效的文档中停止。

use strict;
use warnings;
no warnings 'uninitialized';
use XML::LibXML;
use IO::Handle;

# script to test dtd validity against test xml instance
my $instance = 'C:\jason\code\perl\dev\well-formed-test\family-instance1.xml';
$instance =~ s#\\#/#g;

print "about to test $instance \nagainst dtd\n\n";
my $parser = XML::LibXML->new();
$parser->validation(1);
print "here we go...\n";
print "test : ", &isValid( $instance );
print "after sub.\n";



sub isValid {
   my $file = shift;
   return $parser->parse_file($instance);
}

我在下面的脚本上尝试了很多变体,没有使用那个sub,将parse命令放在eval块中等等。

我根据this tutorial.使用filehandle-> fd_open时出现问题。我也不清楚parse_file函数根据cpan docs.

返回什么

返回布尔值以确定doc是否有效的最佳方法是什么?

这是xml doc:

<?xml version="1.0"?>
<!DOCTYPE family SYSTEM "family.dtd">
<family>
    <member gender="female">
    <firstName>Sally</firstName>
    <lastName>Smith</lastName>
</member>
<member gender="male">
    <firstName>Bernie</firstName>
    <lastName>Smith</lastName>
</member>
<member gender="female">
    <firstName>Anna</firstName>
    <lastName>Smith-Jones</lastName>

</member>
</family>

和dtd:

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT family (member+)>
<!ELEMENT member (firstName, lastName)>
<!ATTLIST member gender (male|female) 'male'>

<!ELEMENT firstName (#PCDATA)>
<!ELEMENT lastName (#PCDATA)>

脚本按预期运行(如果文件有效,它会在'sub'之后到达该行),但是当我添加导致失败的标记时

<sometag/>

脚本打印出错误,但不会到达最后一行。 谢谢!

3 个答案:

答案 0 :(得分:2)

The documentation说:

All of the functions listed below will throw an exception if the document is invalid.
To prevent this causing your program exiting, wrap the call in an eval{} block

parse_file是其中一项功能。

使用eval,您可以预期S@S!来检查结果。

答案 1 :(得分:1)

您可以使用File :: Find处理多个文件。

use strict;
use warnings;
use File::Find;
use XML::Parser; 

my $parser = XML::Parser->new();
find({
        wanted => \&wanted,
        no_chdir => 1,
        follow_fast => 1,
    },
    $ARGV[0],
);


sub wanted {
    return unless -f and m/\.xml$/i;
    eval {
        $parser->parsefile($File::Find::name);
    }; if( $@ ){
        printf STDERR "Not a valid XML document: %s\n", $File::Find::name;
    } else {
        printf STDERR "A valid XML document: %s\n", $File::Find::name;
    }
}

答案 2 :(得分:1)

除非设置了validation解析器选项,否则

XML::LibXML将不会针对DTD验证已解析的文档:

my $parser = XML::LibXML->new(
    validation => 1,
);

如果解析了无效文档,这将抛出异常。将呼叫包裹在parse_file块中的eval以捕获异常。

my $doc = eval { $parser->parse_file($filename) };
if ( ! $doc ) {
    print("Can't parse $filename: $@");
}

或者,您可以在不进行验证的情况下解析文档,然后使用is_valid方法进行验证:

my $doc = $parser->parse_file('filename.xml');
if ( ! $doc->is_valid ) {
    # Document does not validate...
}

在这种情况下,如果发现其他错误(文件未找到,文档格式不正确),parse_file可能仍会抛出异常。这取决于您的用例,首选行为。