Index: t/14ignore_xpath.t
===================================================================
--- t/14ignore_xpath.t (revision 0)
+++ t/14ignore_xpath.t (revision 0)
@@ -0,0 +1,39 @@
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+use XML::SemanticDiff;
+
+my $xml1 = <<'EOX';
+<?xml version="1.0"?>
+<root>
+<el1 el1attr="good"/>
+<el2 el2attr="good">Some Text</el2>
+</root>
+EOX
+
+my $xml2 = <<'EOX';
+<?xml version="1.0"?>
+<root>
+<el1 el1attr="good"/>
+<el2 el2attr="good">Some Text</el2>
+<el3/>
+</root>
+EOX
+
+
+#TEST
+{
+ my $diff_simple = XML::SemanticDiff->new();
+ my @results = $diff_simple->compare($xml1, $xml2);
+ ok(@results, "XMLs are not identical");
+}
+
+#TEST
+{
+ my $diff_ignore = XML::SemanticDiff->new(ignorexpath=>["/root/el3"]);
+ my @results = $diff_ignore->compare($xml1, $xml2);
+ ok((!@results), "XMLs should count identical if xpath /root/el3 is excluded");
+}
+
Index: t/15ignore_multi.t
===================================================================
--- t/15ignore_multi.t (revision 0)
+++ t/15ignore_multi.t (revision 0)
@@ -0,0 +1,45 @@
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+
+use XML::SemanticDiff;
+
+my $xml1 = <<'EOX';
+<?xml version="1.0"?>
+<root>
+<el1 el1attr="good"/>
+<el2 el2attr="good">Some Text</el2>
+<el4/>
+</root>
+EOX
+
+my $xml2 = <<'EOX';
+<?xml version="1.0"?>
+<root>
+<el1 el1attr="good"/>
+<el2 el2attr="good">Some Text</el2>
+<el3/>
+</root>
+EOX
+
+#TEST
+{
+ my $diff_simple = XML::SemanticDiff->new();
+ my $results = $diff_simple->compare($xml1, $xml2);
+ ok($results == 2, "Two differences in XMLs");
+}
+
+#TEST
+{
+ my $diff_ignore = XML::SemanticDiff->new(ignorexpath=>["/root/el3"]);
+ my $results = $diff_ignore->compare($xml1, $xml2);
+ ok($results == 1, "Only one difference if /root/el3 is excluded");
+}
+
+#TEST
+{
+ my $diff_multiignore = XML::SemanticDiff->new(ignorexpath=>["/root/el3", "/root/el4"]);
+ my $results = $diff_multiignore->compare($xml1, $xml2);
+ ok($results == 0, "XMLs should count identical if xpaths /root/el3 and /root/el4 are excluded");
+}
Index: lib/XML/SemanticDiff.pm
===================================================================
--- lib/XML/SemanticDiff.pm (revision 3238)
+++ lib/XML/SemanticDiff.pm (working copy)
@@ -83,6 +83,27 @@
return 0;
}
}
+
+sub match_xpath {
+ my $self = shift;
+ my ($xpath, $flat_name) = @_;
+ my @x_way = split /\//, $xpath;
+ my @f_way = split /\//, $flat_name;
+ for my $i (0..$#x_way) {
+ $x_way[$i]=~s/.*?://g;
+ }
+ for my $i (0..$#f_way) {
+ $f_way[$i]=~s/\[.*?\]$//g;
+ }
+ return 0 if $#x_way > $#f_way;
+ for my $i (0..$#x_way) {
+ if ($x_way[$i] ne $f_way[$i]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
# Okay, it's pretty basic...
#
# We flatten each doc tree to a Perl hash where the keys are "fully qualified"
@@ -105,6 +126,19 @@
my $handler = $self->{diffhandler} || XML::SemanticDiff::BasicHandler->new(%$self);
+ # drop away nodes matching xpaths to be ignored
+ if (defined $self->{ignorexpath}) {
+ my $ignore = $self->{ignorexpath};
+ for my $path (@$ignore) {
+ for my $ref ($from_doc, $to_doc) {
+ for my $key (keys %$ref) {
+ if ($self->match_xpath($path, $key)) {
+ delete $ref->{$key};
+ }
+ }
+ }
+ }
+ }
# fire the init handler
push (@warnings, $handler->init($self)) if $handler->can('init');
@@ -470,6 +504,12 @@
Please see the section on 'CUSTOM HANDLERS' below.
+=item * ignorexpath
+
+This option takes array of strings as argument. Strings are interpreted as simple xpath expressions. Nodes matching these expressions are ignored during comparison. All xpath expressions should be absolute (start with '/').
+
+Current implementation ignores namespaces during comparison.
+
=back
=head2 @results = $differ->compare($xml1, $xml2)