note
fizbin
Remember when I said that it shouldn't be an HTML::TreeBuilder problem per se? Well, it's not exactly, but it turns out that HTML::Parser, which HTML::TreeBuilder uses, has an issue with characters whose utf-8 expansions include the character 0xA0. Why? Well, internal to the parser it's expanding the string into a bunch of UTF-8 bytes and then parsing as it used to before unicode came to the perl world. Unfortunately, at certain points it calls a function to skip "space characters" - and in latin1, character 0xA0 is a space. This leads to it skip part of a utf8 character, and pass along partial/truncated utf8 characters to other perl functions, which is bad.<p>
There are two ways around this. One is to patch the C source for HTML::Parser - the file you need to change is <c>hctype.h</c> and the code you need to change is:
<code>
$ diff hctype.h.orig hctype.h
42c42
< 0x01, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, /* 160 - 167 */
---
> 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, /* 160 - 167 */
</code>
The other way is to change the section that decodes incoming text into perl's representation so that you never pass anything to HTML::Parser that might contain a 0xA0 when represented in utf8; for example, in my LWP::UserAgent sample, you would do this:
<code>
if ($charset) {
$mini_parser = undef;
my $decoded = decode($charset, $unencoded_buffer, Encode::FB_QUIET);
$decoded =~ s/([\x80-\x{FFFF}])/sprintf('&#x%02X;',ord($1))/ge;
$root->parse($decoded);
}
</code>
Technically, that character range is larger than you need, but removing every possible character with an 0xA0 expansion in UTF-8, and nothing else, is an annoying task.
<p>
I'll be filing a bug report with the maintainer of HTML::Parser.
<div class="pmsig"><div class="pmsig-246930">
--<br>
<code>@/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/;
map{y/X_/\n /;print}map{pop@$_}@/for@/</code>
</div></div>
499980
499985