使XML :: Simple读取外部DTD

时间:2015-12-30 16:58:54

标签: xml perl dtd

鉴于以下两个文件:

doc.xml

<!DOCTYPE TEST [

    <!ENTITY % get_em SYSTEM "entities.ent" >
    %get_em;

]>

<TEST>
        <COMPANY_ID>&COMPANY_ID;</COMPANY_ID>
</TEST>

entities.ent

<!ENTITY COMPANY_ID "84500">
<!ENTITY SPN_FIRM_ID "5900">
<!ENTITY SPN_CUSTD_REL_ID "40001">
<!ENTITY CUSTD_FIRM_NBR "229">
<!ENTITY CUSTD_FIRM_ID "5901">
<!ENTITY MASTERACCOUNT "TAL">

我可以成功使用xmllint

xmllint --loaddtd --noent --dropdtd doc.xml
<?xml version="1.0"?>
<TEST>
        <COMPANY_ID>84500</COMPANY_ID>
</TEST>

我怎么能在Perl和XML :: Simple中使用这个想法?

$ perl -MData::Dumper -MXML::Simple -e 'print Dumper XMLin q{doc.xml}'
doc.xml:4: parser error : PEReference: %get_em; not found
    %get_em;
            ^
doc.xml:9: parser error : Entity 'COMPANY_ID' not defined
        <COMPANY_ID>&COMPANY_ID;</COMPANY_ID>
                                ^

经过一些评论后,我已尝试使用XML::LibXML::Simple它确实看起来好一点,但实体仍未得到解决

$ perl -MData::Dumper -MXML::LibXML::Simple -e 'print Dumper XMLin q{doc.xml}'
./doc.xml:9: parser error : Entity 'COMPANY_ID' not defined
        <COMPANY_ID>&COMPANY_ID;</COMPANY_ID>
                                ^

嗯,上面的PEReference突出......什么是PE? 但更重要的是,如何通过XML :: Simple读取外部DTD的Perl?

我累了XML::Simple::DTDReader但我觉得这个模块非常严格,特别是它指出specifically 没有XML::Simple支持无数的选项

如果我在doc.xml本身中包含ENTITY声明,它就可以工作..所以显然XML::Simple 知道如何处理DOCTYPE只有我想要使用SYSTEM的外部DTD,以及我坚持让它工作的地方。

2 个答案:

答案 0 :(得分:1)

XML :: LibXML默认会扩展实体,因此您可以使用

$ perl -e'
    use Data::Dumper qw( Dumper );
    use XML::LibXML  qw( );
    use XML::Simple  qw( XMLin );

    my $xml = XML::LibXML->new()->parse_file("doc.xml")->toString();
    my $doc = XMLin($xml);
    print(Dumper($doc));
'
$VAR1 = {
          'COMPANY_ID' => '84500'
        };

这也可以通过覆盖XML :: Simple-compatibility设置来实现XML :: LibXML :: Simple。

$ perl -e'
    use Data::Dumper        qw( Dumper );
    use XML::LibXML::Simple qw( XMLin );

    my $doc = XMLin("doc.xml",
        ParserOpts => {
            load_ext_dtd    => 1,
            ext_ent_handler => undef,
        },
    );
    print(Dumper($doc));
'
$VAR1 = {
          'COMPANY_ID' => '84500'
        };

答案 1 :(得分:0)

我仍然在寻找是否可以在Perl本身内完成,但一种简单的方法是将我发现的xmllintXMLin的文件句柄相结合!

$ perl -MData::Dumper -MXML::Simple -e 'open my $fh, "xmllint --loaddtd --noent --dropdtd doc.xml |"; print Dumper XMLin $fh'
$VAR1 = {
          'COMPANY_ID' => '84500'
        };