0

我正在解析一些外部方提供给我的 XML,他们肯定不会改变它们;这些讨厌的 XML 包含 CDATA 部分中的 HTML,并且 XML::Parser 阻塞了它们。

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

编辑:

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

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

感谢@ikegami 提供工作测试用例,感谢@mirod 提供这种行为的非常可能且不明显的原因——编码不匹配。

下面发布的真实原因作为答案。

4

3 回答 3

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 时停止

于 2012-08-09T18:02:21.940 回答
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
于 2012-08-09T17:59:12.707 回答
0

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

疯狂的!

我能够用这个片段修复我的文件:

perl -CSDA -pe 'tr/\x00-\x08\x0B\x0C\x0E-\x19//d' bad.xml > good.xml
于 2012-08-10T15:00:44.873 回答