#!perl -w # # (c) 2003 by Bjoern Hoehrmann # use strict; use warnings; use XML::LibXML; use XML::Parser; use CSS::SAC; use CSS::SAC::Writer; use CSS::SAC::Selector ':constants'; use CSS::SAC::Condition ':constants'; use LWP::Simple; ##################################### # main ##################################### unless (@ARGV == 2) { warn "Usage: $0 http://example.org/xml http://example.org/css\n"; exit(1); } my $pfx = "selectorviz"; my $xmluri = shift; my $cssuri = shift; my $xml = get $xmluri; my $css = get $cssuri; my $i = 1; sub handler::new { bless[], shift } sub handler::start_selector { push @{$_[0]} => [ @{$_->Specifity}, $i++, $_, $_->ToXPath ] foreach @{$_[1]} } sub handler::end_document { @{shift()} } my @selectors = CSS::SAC->new({DocumentHandler => handler->new })->parse({string => $css }); my @offsets; my $index = 0; my $current; XML::Parser->new(Handlers => { Start => sub { $offsets[$index]->[0] = shift->current_byte; push @$current, $offsets[$index++] }, End => sub { (pop@$current)->[1] = $_[0]->current_byte + length $_[0]->original_string } })->parse($xml); my @sorted = sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] || $a->[3] <=> $b->[3] } @selectors; my $doc = XML::LibXML->new->parse_string($xml); my $nodenum = -1; my %edits; foreach my $node ($doc->findnodes("//*")) { my @classes; $nodenum++; foreach my $selector (@sorted) { my $xpath = $selector->[5]; next unless defined $xpath; my $senum = $selector->[3]; push @classes, "$pfx$senum" if $node->find($xpath); } next unless @classes; $edits{$offsets[$nodenum]->[0]} .= join '', map { sprintf "", $_ } @classes; $edits{$offsets[$nodenum]->[1]} .= '' x scalar @classes; } $edits{0} = '' unless exists $edits{0}; $edits{ length $xml } = '' unless exists $edits{ length $xml }; sub xml_escape { local $_ = shift; s/&/&/g; s//]]>/g; s/'/'/g; s/"/"/g; $_ } my @sedits = sort { $b <=> $a } keys %edits; while (@sedits) { my $x = shift @sedits; my $y = $sedits[0]; my $replacement = ""; $replacement .= xml_escape(substr $xml, $y, $x - $y) if defined $y; $y = $offsets[0]->[0] unless defined $y; $replacement .= $edits{$x}; $x ||= $y; substr $xml, $y, $x - $y, $replacement; } print <<"__EO__"; ... __EO__ printf "

Selectors

\n
    \n"; foreach my $s (@selectors) { printf "
  1. %s
  2. \n", (defined $s->[5] ? xml_escape($s->[5]) : ''), $s->[3], xml_escape(eval { $s->[4]->ToString } or "Error, fix CSS::SAC::Writer...") } printf "
\n"; printf "

Stylesheet

\n"; printf "
\n%s\n
\n", xml_escape($css); printf "

Source

\n
\n";
print $xml;
print "
";