Subject: | Move from XML::XPath to XML::LibXML::XPathContext |
Hi,
as noted in eg. the thread at
http://aspn.activestate.com/ASPN/Mail/Message/perl-xml/3438368
the XML::XPath module is undermaintained and has unfixed serious bugs. A
better alternative would be XML::LibXML::XPathContext, which is faster
and provides all the functionality in XML::XPath.
I'm attaching a patch that switches to XML::LibXML and causes no test
suite regressions for me. Please consider applying it. I could also
rework the patch into a run-time detection between XML::XPath and
XML::LibXML::XPathContext; please let me know if you'd prefer that.
Note that the only non-trivial change in the patch is removing the
namespace prefix from the attribute xpath queries in get_tagfields(). I
believe that this only worked with the prefix due to a bug in
XML::XPath. Quoting the W3C recommendation "Namespaces in XML 1.0",
section 6.2 "Namespace Defaulting" [1]:
A default namespace declaration applies to all unprefixed element names
within its scope. Default namespace declarations do not apply directly
to attribute names; the interpretation of unprefixed attributes is
determined by the element on which they appear.
[1] http://www.w3.org/TR/REC-xml-names/#defaulting
Thanks for your work on SQL::Translator,
--
Niko Tyni
ntyni@iki.fi
Subject: | sqlfairy-libxml.patch |
diff --git a/Build.PL b/Build.PL
index 3190371..d49bd7f 100644
--- a/Build.PL
+++ b/Build.PL
@@ -38,7 +38,7 @@ my $builder = Module::Build->new(
'Text::ParseWords' => 0,
'Text::RecordParser' => 0.02,
'XML::Writer' => 0.500,
- 'XML::XPath' => 1.13,
+ 'XML::LibXML' => 1.61,
},
build_requires => {
'File::Basename' => 0,
diff --git a/lib/SQL/Translator/Parser/XML/SQLFairy.pm b/lib/SQL/Translator/Parser/XML/SQLFairy.pm
index a627665..896ba28 100644
--- a/lib/SQL/Translator/Parser/XML/SQLFairy.pm
+++ b/lib/SQL/Translator/Parser/XML/SQLFairy.pm
@@ -110,16 +110,17 @@ use base qw(Exporter);
use base qw/SQL::Translator::Parser/; # Doesnt do anything at the mo!
use SQL::Translator::Utils 'debug';
-use XML::XPath;
-use XML::XPath::XMLParser;
+use XML::LibXML;
+use XML::LibXML::XPathContext;
sub parse {
my ( $translator, $data ) = @_;
my $schema = $translator->schema;
local $DEBUG = $translator->debug;
- my $xp = XML::XPath->new(xml => $data);
+ my $doc = XML::LibXML->new->parse_string($data);
+ my $xp = XML::LibXML::XPathContext->new($doc);
- $xp->set_namespace("sqlf", "http://sqlfairy.sourceforge.net/sqlfairy.xml");
+ $xp->registerNs("sqlf", "http://sqlfairy.sourceforge.net/sqlfairy.xml");
#
# Work our way through the tables
@@ -274,27 +275,26 @@ sub get_tagfields {
my $is_attrib = m/^(sql|comments|action|extra)$/ ? 0 : 1;
- my $attrib_path = "\@$thisns$_";
+ my $attrib_path = "\@$_";
my $tag_path = "$thisns$_";
- if ( $xp->exists($attrib_path,$node) ) {
- $data{$_} = "".$xp->findvalue($attrib_path,$node);
+ if ( my $found = $xp->find($attrib_path,$node) ) {
+ $data{$_} = "".$found->to_literal;
warn "Use of '$_' as an attribute is depricated."
." Use a child tag instead."
." To convert your file to the new version see the Docs.\n"
unless $is_attrib;
debug "Got $_=".( defined $data{ $_ } ? $data{ $_ } : 'UNDEF' );
}
- elsif ( $xp->exists($tag_path,$node) ) {
+ elsif ( $found = $xp->find($tag_path,$node) ) {
if ($_ eq "extra") {
my %extra;
- my $extra_nodes = $xp->find($tag_path,$node);
- foreach ( $extra_nodes->pop->getAttributes ) {
+ foreach ( $found->pop->getAttributes ) {
$extra{$_->getName} = $_->getData;
}
$data{$_} = \%extra;
}
else {
- $data{$_} = "".$xp->findvalue($tag_path,$node);
+ $data{$_} = "".$found->to_literal;
}
warn "Use of '$_' as a child tag is depricated."
." Use an attribute instead."