Perl XML::LibXML无法针对HTTPS上可用的DTD进行验证

Perl XML::LibXML无法针对HTTPS上可用的DTD进行验证,perl,https,dtd,xml-libxml,Perl,Https,Dtd,Xml Libxml,如何使用 当DTD通过HTTPS可用时 测试代码: #/usr/bin/perl-w 使用XML::LibXML; 严格使用; my$xml=xml::LibXML->load\uxml(IO=>\*数据); my$dtd=XML::LibXML::dtd->new(“-//NLM//dtd链接1.0//EN”https://www.ncbi.nlm.nih.gov/projects/linkout/doc/LinkOut.dtd" ); my$https\u is\u valid=$xml->

如何使用 当DTD通过HTTPS可用时

测试代码:
#/usr/bin/perl-w
使用XML::LibXML;
严格使用;
my$xml=xml::LibXML->load\uxml(IO=>\*数据);
my$dtd=XML::LibXML::dtd->new(“-//NLM//dtd链接1.0//EN”https://www.ncbi.nlm.nih.gov/projects/linkout/doc/LinkOut.dtd" );
my$https\u is\u valid=$xml->is\u valid($dtd);
打印“HTTPS dtd:”,ref$dtd,“\n有效:$HTTPS\u有效\n”;
我的$dtd_http=XML::LibXML::dtd->new(“-//NLM//dtd链接1.0//EN”http://www.ncbi.nlm.nih.gov/projects/linkout/doc/LinkOut.dtd" );
我的$http\u is\u valid=$xml->is\u valid($dtd\u http);
打印“HTTP dtd:”,ref$dtd\u HTTP,“\n有效:$HTTP\u有效\n”;
__资料__
]>
1.
XXXX
&icon.url;
PubMed
1234567890
&base.url;
/1/
上面的代码生成以下输出:

HTTPS-dtd:
有效日期:0
HTTP dtd:XML::LibXML::dtd
有效期:1
DTD无法从HTTPS URL加载,因此无法用于验证XML

我已经通过HTTPS下载了DTD,并检查了HTTP重定向-没有任何重定向

我也看了一眼 但我看不出如何将它与
XML::LibXML::Dtd->new(…)合并

我应该如何实现此验证


DTD是通过HTTP提供的,所以我可以使用它来验证,但这感觉就像是在避免问题,而不是正确地解决问题

注意,XML已经包含指向DTD的URL,因此您不需要创建
XML::LibXML::DTD
来传递给
->是否有效

我同意评论员格兰特·麦克莱恩的观点,你可能不想一直在网络上。事实上,不久前我编写了一些代码,使用
XML::LibXML::InputCallback
将所有网络请求重定向到我缓存了网络资源的本地FS

但要回答您的问题,调整代码以从网络获取并不太困难,包括HTTPS、via,它需要为SSL支持安装>=1.56和>=1.49。以下打印预期的“
有效:是”
”:

使用警告;
严格使用;
使用XML::LibXML;
使用HTTP::Tiny;
使用URI;
my$parser=XML::LibXML->new;
my$cb=XML::LibXML::InputCallback->new;
my$http=http::Tiny->new;
我的%cache;
$cb->register_回调([
sub{1},#match(URI)返回Bool
sub{#open(URI),返回句柄
my$uri=uri->new($\u0]);
我的$file;
#警告“处理”\n;#调试
如果(!$uri->scheme){$file=$\u0]}
elsif($uri->scheme eq'file'){$file=$uri->path}
elsif($uri->scheme=~/\Ahttps?\z/i){
if(!defined$cache{$uri}){
my$resp=$http->get($uri);
死“$uri:$resp->{status}$resp->{reason}\n”
除非$resp->{success};
$cache{$uri}=$resp->{content};
}
$file=\$cache{$uri};
}
else{die“不支持的URL方案:“.$uri->scheme}

打开我的$fh,'我可以复制。但是请注意,您可以简化示例:问题是
Dtd->new(…)
似乎无法与HTTPS一起工作。验证失败是其结果,并且不会添加更多信息。您可以自己下载Dtd(例如使用LWP)并使用
->解析字符串($download\Dtd)
而不是
->new($url)
似乎是libxml2中的一个核心问题。请参阅:,或者(忽略Gentoo,这是关于libxml2库的。)理想情况下,您的验证代码无论如何都不应该每次都下载DTD。有一种东西叫做DTD,它为请求DTD的应用程序提供了一种标准方法,将URL映射到本地文件。例如,在Debian系统上,该工具由
xml核心
包提供,并通过/etc/xml中的文件进行配置。是的,acco根据需要,在发出网络请求之前将检查系统目录。因此,如果目录具有映射,则将直接检索文件,并且不会发生网络请求。我认为这符合我的需要。我不想依赖服务器上的其他东西(XML目录),因此这是最好的解决方案。
use warnings;
use strict;
use XML::LibXML;
use HTTP::Tiny;
use URI;

my $parser = XML::LibXML->new;
my $cb = XML::LibXML::InputCallback->new;
my $http = HTTP::Tiny->new;
my %cache;
$cb->register_callbacks([
    sub { 1 }, # match (URI), returns Bool
    sub { # open (URI), returns Handle
        my $uri = URI->new($_[0]);
        my $file;
        #warn "Handling <<$uri>>\n"; #Debug
        if (!$uri->scheme) { $file = $_[0] }
        elsif ($uri->scheme eq 'file') { $file = $uri->path }
        elsif ($uri->scheme=~/\Ahttps?\z/i) {
            if (!defined $cache{$uri}) {
                my $resp = $http->get($uri);
                die "$uri: $resp->{status} $resp->{reason}\n"
                    unless $resp->{success};
                $cache{$uri} = $resp->{content};
            }
            $file = \$cache{$uri};
        }
        else { die "unsupported URL scheme: ".$uri->scheme }
        open my $fh, '<', $file or die "$file: $!";
        return $fh;
    },
    sub { # read (Handle,Length), returns Data
        my ($fh,$len) = @_;
        read($fh, my $buf, $len);
        return $buf;
    },
    sub { close shift } # close (Handle)
]);
$parser->input_callbacks($cb);

my $doc = $parser->load_xml( IO => \*DATA );
print "Is valid: ", $doc->is_valid ? "yes" : "no", "\n";

__DATA__
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE LinkSet PUBLIC "-//NLM//DTD LinkOut 1.0//EN" "https://www.ncbi.nlm.nih.gov/projects/linkout/doc/LinkOut.dtd" [
<!ENTITY base.url "https://some.domain.com">
<!ENTITY icon.url "https://some.domain.com/logo.png">
]>
<LinkSet>
  <Link>
    <LinkId>1</LinkId>
    <ProviderId>XXXX</ProviderId>
    <IconUrl>&icon.url;</IconUrl>
    <ObjectSelector>
      <Database>PubMed</Database>
      <ObjectList>
        <ObjId>1234567890</ObjId>
      </ObjectList>
    </ObjectSelector>
    <ObjectUrl>
      <Base>&base.url;</Base>
      <Rule>/1/</Rule>
    </ObjectUrl>
  </Link>
</LinkSet>