use CSS;
my $css = CSS->new();
$css->read_string('div#foo p.bar { background-image : url(/foo/bar.gif) }');
# $css->read_string('table { border: 1px solid #FF0000 }');
# etc...
my %bg_selectors;
# for some reason, CSS doesn't supply accessor methods...
foreach my $rule ( @{ $css->{'styles'} } ) {
foreach my $prop ( @{ $rule->{'properties'} } ) {
if ( $prop->{'property'} =~ /^background(?:-image)?$/ ) {
foreach my $selector ( @{ $rule->{'selectors'} } ) {
$bg_selectors{$selector->{'name'}} =
$prop->{'simple_value'};
}
}
}
}
####
sub selector_to_xpath {
my $selector = shift;
my $xpath = '';
foreach my $token ( split(/\s/, $selector) ) {
if ( $token =~ /(\w+)? (?: \#(\w+) | \.(\w+) )?/x ) {
$xpath .= '//';
my ( $tag, $id, $class ) = ( $1, $2, $3 );
if ( $tag ) {
$xpath .= $tag;
}
if ( $id ) {
$xpath .= "*" unless $tag;
$xpath .= "[\@id='$id']";
}
if ( $class ) {
$xpath .= "*" unless $tag;
$xpath .= "[\@class='$class']";
}
}
}
return $xpath;
}
####
use strict;
use warnings;
use CSS;
use XML::XPath;
use Data::Dumper;
sub selector_to_xpath {
my $selector = shift;
my $xpath = '';
# doesn't deal with much of the CSS spec ...
foreach my $token ( split(/\s/, $selector) ) {
if ( $token =~ /(\w+)? (?: \#(\w+) | \.(\w+) )?/x ) {
$xpath .= '//';
my ( $tag, $id, $class ) = ( $1, $2, $3 );
if ( $tag ) {
$xpath .= $tag;
}
if ( $id ) {
$xpath .= "*" unless $tag;
$xpath .= "[\@id='$id']";
}
if ( $class ) {
$xpath .= "*" unless $tag;
$xpath .= "[\@class='$class']";
}
}
}
return $xpath;
}
my $css = CSS->new();
# this rule matches an element in our doc
$css->read_string('div#foo p.bar { background-image : url(/foo/bar.gif) }');
# this doesn't match an element in our doc
$css->read_string('div#foo p.qux { background-image : url(/foo/qux.gif) }');
# nor does this
$css->read_string('div#baz p.bar { background-image : url(/foo/baz.gif) }');
# but this does
$css->read_string('div { background-image : url(/foo/div.gif) }');
# gather up all rules talking about backgrounds
my %bg_rules;
foreach my $rule ( @{ $css->{'styles'} } ) {
foreach my $prop ( @{ $rule->{'properties'} } ) {
if ( $prop->{'property'} =~ /^background(?:-image)?$/ ) {
foreach my $selector ( @{ $rule->{'selectors'} } ) {
$bg_rules{$selector->{'name'}} =
$prop->{'simple_value'};
}
}
}
}
# slurp up the XML and parse for XPath-ery
my $xml;
{
local $/;
$xml = XML::XPath->new(ioref => *DATA);
}
# go through our list of CSS rules seeing which ones apply
my @used_images;
while ( my ( $sel, $propvalue ) = each %bg_rules ) {
my $xpath = selector_to_xpath($sel);
push(@used_images, $propvalue) if $xml->exists($xpath);
}
# let's see what we got ...
warn Dumper \@used_images;
__END__