XML::LibXML::Reader 需要对架构错误发出警告而不是退出
XML::LibXML::Reader need warn on schema errors instead of exit
基本上,我需要使用 perl 模块 XML::libXML::Reader 中的架构选项,以便在解析文件时验证大型 (>1GB) XML 文件。
以前,我使用 xmllint 命令根据给定模式 (xsd) 文件验证 XML 文件。但是现在我有一些大的 XML 文件要验证并且 运行 内存不足 (8GB) 试图执行验证。
我在 XML::libXML::Reader perl 模块页面上看到有一个架构选项。但是,当我使用它时(参见下面的代码),当找到 XML 文件的第一个无效元素时,代码退出。
use strict;
use warnings;
use XML::LibXML::Reader;
my $SchemaFile='schema.xsd';
my $FileToAnalyse='/tmp/file.xml';
my $reader = XML::LibXML::Reader->new(location => $FileToAnalyse,Schema=>$SchemaFile) or
die "cannot read file '$FileToAnalyse': $!\n";
while($reader->read) {
Process the file line by line here, even if not valid against schema (reduces memory usage for large files)
}
我需要收集无效条目并继续而不是退出。这可能吗?
好的,不完全是我最初提出的问题,但如果有人感兴趣,我已经找到了解决方案。我只是为 xmllint 命令使用了 --stream 开关。
这允许我在具有 4GB 内存的系统上验证 XML 个大于 1GB 的文件(如果没有 --stream 开关,这是不可能的)。该方法生成一个条目列表,如果它们存在,不符合提供的 XSD 文件(这些可以写入文件或终端)。对我来说重要的一点是 xmllint 在发现第一个不符合项时不会停止,而是继续到 XML 文件的末尾打印任何不符合项。
$reader->read
无法从模式验证错误中恢复的原因(即使可以恢复)可以在 line #8815 of LibXML.xs
. Notice that REPORT_ERROR()
is called with a zero value (the value indicates whether `LibXML_report_error_ctx() will be able to recover from errors or not. A value of zero, means it will not try to recover, and it will call XML::LibXML::Error::_report_error 中看到。
我试图在 line #8815 将值更改为 1 并重新编译 XS 模块,现在它报告模式错误作为警告(而不是死掉)并继续解析。
我想用户无法使用此选项是有充分理由的,但我对 XML 解析不太熟悉,因此我可以举一个示例说明此处可能出现的问题。
编辑:
看来正确的做法是捕获read()
抛出的异常,然后再尝试调用read()
,如果下面调用read()
returns -1,解析器无法从错误中恢复,如果为 returns 0,则到达文件末尾,如果为 returns 1,则能够从异常中恢复。我做了一些测试,它似乎能够从模式验证错误中恢复,但不能从解析错误中恢复。所以你可以尝试以下方法:
use feature qw(say);
use strict;
use warnings;
use Try::Tiny qw(try catch);
use XML::LibXML::Reader;
my $SchemaFile='schema.xsd';
my $FileToAnalyse='file.xml';
my $reader = XML::LibXML::Reader->new(
location => $FileToAnalyse, Schema => $SchemaFile
) or die "cannot read file '$FileToAnalyse': $!\n";
while (1) {
my $result;
try { $result = $reader->read } catch {
say '==> ' . $_;
$result = 1; # Try to continue after exception..
};
last if $result != 1;
if ( $reader->nodeType == XML_READER_ELEMENT ) {
say "Element node: ", $reader->name;
}
}
$reader->finish();
$reader->close();
基本上,我需要使用 perl 模块 XML::libXML::Reader 中的架构选项,以便在解析文件时验证大型 (>1GB) XML 文件。
以前,我使用 xmllint 命令根据给定模式 (xsd) 文件验证 XML 文件。但是现在我有一些大的 XML 文件要验证并且 运行 内存不足 (8GB) 试图执行验证。
我在 XML::libXML::Reader perl 模块页面上看到有一个架构选项。但是,当我使用它时(参见下面的代码),当找到 XML 文件的第一个无效元素时,代码退出。
use strict;
use warnings;
use XML::LibXML::Reader;
my $SchemaFile='schema.xsd';
my $FileToAnalyse='/tmp/file.xml';
my $reader = XML::LibXML::Reader->new(location => $FileToAnalyse,Schema=>$SchemaFile) or
die "cannot read file '$FileToAnalyse': $!\n";
while($reader->read) {
Process the file line by line here, even if not valid against schema (reduces memory usage for large files)
}
我需要收集无效条目并继续而不是退出。这可能吗?
好的,不完全是我最初提出的问题,但如果有人感兴趣,我已经找到了解决方案。我只是为 xmllint 命令使用了 --stream 开关。
这允许我在具有 4GB 内存的系统上验证 XML 个大于 1GB 的文件(如果没有 --stream 开关,这是不可能的)。该方法生成一个条目列表,如果它们存在,不符合提供的 XSD 文件(这些可以写入文件或终端)。对我来说重要的一点是 xmllint 在发现第一个不符合项时不会停止,而是继续到 XML 文件的末尾打印任何不符合项。
$reader->read
无法从模式验证错误中恢复的原因(即使可以恢复)可以在 line #8815 of LibXML.xs
. Notice that REPORT_ERROR()
is called with a zero value (the value indicates whether `LibXML_report_error_ctx() will be able to recover from errors or not. A value of zero, means it will not try to recover, and it will call XML::LibXML::Error::_report_error 中看到。
我试图在 line #8815 将值更改为 1 并重新编译 XS 模块,现在它报告模式错误作为警告(而不是死掉)并继续解析。
我想用户无法使用此选项是有充分理由的,但我对 XML 解析不太熟悉,因此我可以举一个示例说明此处可能出现的问题。
编辑:
看来正确的做法是捕获read()
抛出的异常,然后再尝试调用read()
,如果下面调用read()
returns -1,解析器无法从错误中恢复,如果为 returns 0,则到达文件末尾,如果为 returns 1,则能够从异常中恢复。我做了一些测试,它似乎能够从模式验证错误中恢复,但不能从解析错误中恢复。所以你可以尝试以下方法:
use feature qw(say);
use strict;
use warnings;
use Try::Tiny qw(try catch);
use XML::LibXML::Reader;
my $SchemaFile='schema.xsd';
my $FileToAnalyse='file.xml';
my $reader = XML::LibXML::Reader->new(
location => $FileToAnalyse, Schema => $SchemaFile
) or die "cannot read file '$FileToAnalyse': $!\n";
while (1) {
my $result;
try { $result = $reader->read } catch {
say '==> ' . $_;
$result = 1; # Try to continue after exception..
};
last if $result != 1;
if ( $reader->nodeType == XML_READER_ELEMENT ) {
say "Element node: ", $reader->name;
}
}
$reader->finish();
$reader->close();