Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(css-selector): default XML namespace should not be applied to wildcard #3413

Merged
merged 4 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ end
# If Psych doesn't build, you can disable this group locally by running
# `bundle config set --local without rdoc`
# Then re-run `bundle install`.
unless RUBY_PLATFORM == "java" # see #3391 and https://github.com/jruby/jruby/issues/7262
group :rdoc do
gem "rdoc", "6.10.0"
end
group :rdoc do
gem "rdoc", "6.10.0" unless RUBY_PLATFORM == "java" || ENV["CI"]
end
3 changes: 2 additions & 1 deletion lib/nokogiri/css/xpath_visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ def visit_element_name(node)
else
node.value.join(":")
end
elsif @namespaces&.key?("xmlns") # apply the default namespace if it's declared
elsif node.value.first != "*" && @namespaces&.key?("xmlns")
# apply the default namespace (if one is present) to a non-wildcard selector
"xmlns:#{node.value.first}"
else
node.value.first
Expand Down
1 change: 1 addition & 0 deletions scripts/test-gem-install
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ popd
# 2.3.21 because https://github.com/rubygems/rubygems/issues/5914
# 2.3.22 because https://github.com/rubygems/rubygems/issues/5940
gem install bundler -v "~> 2.2, != 2.3.21, != 2.3.22"
bundle config set --local without rdoc
bundle install --local || bundle install

rm -rf lib ext # ensure we don't use the local files
Expand Down
77 changes: 46 additions & 31 deletions test/css/test_xpath_visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,53 +143,68 @@ def visit_pseudo_class_aaron(node)
)
end

it "# id" do
assert_xpath("//*[@id='foo']", "#foo")
assert_xpath("//*[@id='escape:needed,']", "#escape\\:needed\\,")
assert_xpath("//*[@id='escape:needed,']", '#escape\3Aneeded\,')
assert_xpath("//*[@id='escape:needed,']", '#escape\3A needed\2C')
assert_xpath("//*[@id='escape:needed']", '#escape\00003Aneeded')
end

describe "attribute" do
it "basic mechanics" do
assert_xpath("//h1[@a='Tender Lovemaking']", "h1[a='Tender Lovemaking']")
assert_xpath("//h1[@a]", "h1[a]")
assert_xpath(%q{//h1[@a='gnewline\n']}, "h1[a='\\gnew\\\nline\\\\n']")
assert_xpath("//h1[@a='test']", %q{h1[a=\te\st]})
end

it "parses leading @ (extended-syntax)" do
assert_xpath("//a[@id='Boing']", "a[@id='Boing']")
assert_xpath("//a[@id='Boing']", "a[@id = 'Boing']")
assert_xpath("//a[@id='Boing']//div", "a[@id='Boing'] div")
describe "namespaces" do
let(:ns) do
{
"xmlns" => "http://default.example.com/",
"hoge" => "http://hoge.example.com/",
}
end

it "namespacing" do
it "basic mechanics" do
assert_xpath("//a[@flavorjones:href]", "a[flavorjones|href]")
assert_xpath("//a[@href]", "a[|href]")
assert_xpath("//*[@flavorjones:href]", "*[flavorjones|href]")
end

ns = {
"xmlns" => "http://default.example.com/",
"hoge" => "http://hoge.example.com/",
}

# An intentionally-empty namespace means "don't use the default xmlns"
assert_equal(["//a"], Nokogiri::CSS.xpath_for("|a", ns: ns, cache: false))

# The default namespace is not applied to attributes (just elements)
it "default namespace is applied to elements but not attributes" do
assert_equal(
["//xmlns:a[@class='bar']"],
Nokogiri::CSS.xpath_for("a[class='bar']", ns: ns, cache: false),
)
end

# We can explicitly apply a namespace to an attribue
it "default namespace is not applied to wildcard selectors" do
assert_equal(
["//xmlns:a//*"],
Nokogiri::CSS.xpath_for("a *", ns: ns, cache: false),
)
end

it "intentionally-empty namespace omits the default xmlns" do
# An intentionally-empty namespace
assert_equal(["//a"], Nokogiri::CSS.xpath_for("|a", ns: ns, cache: false))
end

it "explicit namespaces are applied to attributes" do
assert_equal(
["//xmlns:a[@hoge:class='bar']"],
Nokogiri::CSS.xpath_for("a[hoge|class='bar']", ns: ns, cache: false),
)
end
end

describe "attribute" do
it "basic mechanics" do
assert_xpath("//h1[@a='Tender Lovemaking']", "h1[a='Tender Lovemaking']")
assert_xpath("//h1[@a]", "h1[a]")
assert_xpath(%q{//h1[@a='gnewline\n']}, "h1[a='\\gnew\\\nline\\\\n']")
assert_xpath("//h1[@a='test']", %q{h1[a=\te\st]})
end

it "#id escaping" do
assert_xpath("//*[@id='foo']", "#foo")
assert_xpath("//*[@id='escape:needed,']", "#escape\\:needed\\,")
assert_xpath("//*[@id='escape:needed,']", '#escape\3Aneeded\,')
assert_xpath("//*[@id='escape:needed,']", '#escape\3A needed\2C')
assert_xpath("//*[@id='escape:needed']", '#escape\00003Aneeded')
end

it "parses leading @ (extended-syntax)" do
assert_xpath("//a[@id='Boing']", "a[@id='Boing']")
assert_xpath("//a[@id='Boing']", "a[@id = 'Boing']")
assert_xpath("//a[@id='Boing']//div", "a[@id='Boing'] div")
end

it "rhs with quotes" do
assert_xpath(%q{//h1[@a="'"]}, %q{h1[a="'"]})
Expand Down
7 changes: 0 additions & 7 deletions test/xml/test_xpath.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
module Nokogiri
module XML
class TestXPath < Nokogiri::TestCase
#
# Note that many of these tests vary for jruby because custom xpath functions in JRuby require
# a namespace, and libxml2 (and the original implementation of Nokogiri) do not.
#
# Ideally we should change this to always require a namespace.
# See https://github.com/sparklemotion/nokogiri/issues/2147
#
def setup
super

Expand Down
Loading