使用XML :: Parser时如何忽略CDATA内容?

时间:2012-08-09 17:34:29

标签: xml perl

我正在解析外部方提供给我的一些XML,他们绝对不会改变它们;这些讨厌的XML包含CDATA部分内的HTML和XML :: Parser扼流圈。

除了完全剥离CDATA之外,还有什么方法可以解决这个问题吗?

修改

原始错误是"格式不正确(令牌无效)"。

对不起,我没有立即发布测试用例。经过一些研究后,我出于某种原因确信CDATA内部应该是有效的XML,所以我发布了这个问题。

感谢@ikegami工作测试用例和@mirod非常可能且不明显的原因 - 编码不匹配。

下面发布了真正的理由作为答案。

3 个答案:

答案 0 :(得分:4)

XML :: Parser不应该阻塞正确的CDATA部分。基本上任何东西都在CDATA内,除了]]>只要它的字符数据,这意味着没有随机二进制,这似乎不是你的情况,并且编码中没有数据与文档声明(显式或隐式)的不兼容。这可能是问题所在。

如果您的问题是文档中没有编码声明,我不会感到惊讶,因此解析器假定它是UTF-8,但HTML数据是latin-1或windows-1252 ,当读取为UTF-8时,会生成无效的字符。

根据您的数据,您可以强制编码为latin1,如果XML数据本身不是特定的UTF-8,请使用XML :: Parser选项ProtocolEncoding => 'ISO-8859-1',或者您可能需要转换CDATA部分中文本的编码,预解析。

请注意,使用不同的解析器可能没有用,因为设计XML解析器应该在遇到格式不正确的XML时停止

答案 1 :(得分:3)

XML :: Parser非常好地处理CDATA块。也许您需要更新XML :: Parser或基础expat库,或者您的问题可能在其他地方。很难说,因为你没有证明你的问题。

use strict;
use warnings;
use feature qw( say );

use Data::Dumper qw( Dumper );
use XML::Parser  qw( );

sub f {
   local $Data::Dumper::Indent = 0;
   local $Data::Dumper::Terse  = 1;
   local $Data::Dumper::Useqq  = 1;
   return Dumper($_[0]);
}

my $parser = XML::Parser->new(
   Handlers => {
      Start => sub { say "Start of $_[1]"; },
      End   => sub { say "End of $_[1]"; },
      Char  => sub { say "Char: " . f($_[1]); },
   },
);

$parser->parse(<<'__EOI__');
<root>
<![CDATA[
   <html>
   <foo>test > test</foo><br>
   </html>
]]>
</root>
__EOI__

Start of root
Char: "\n"
Char: "\n"
Char: "   <html>"
Char: "\n"
Char: "   <foo>test > test</foo><br>"
Char: "\n"
Char: "   </html>"
Char: "\n"
Char: "\n"
End of root

答案 2 :(得分:0)

好吧,在最小化我的XML后,我能够跟踪这些错误的原因:它是一个垂直标签特殊符号。

疯狂!

我能够使用此代码段修复我的文件:

perl -CSDA -pe 'tr/\x00-\x08\x0B\x0C\x0E-\x19//d' bad.xml > good.xml